Spring cloud feign behavior when parameter is empty - java

I am writing a feign client
#RequestMapping(
path = "/TrackingServlet?CompanyName=Test&UserName=&BranchCode=",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE
)
ResponseEntity<String> getInfo(
#RequestParam("DocumentNumbers") String bill);
when it is invoked the url becomes /TrackingServlet?CompanyName=Test&UserName&BranchCode
eliminating the = symbol, but the API needs it in that format, since its a third party API we cannot modify it.
Also tried
#RequestMapping(
path = "/TrackingServlet?CompanyName=Test&UserName=",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE
)
ResponseEntity<String> getInfo(
#RequestParam("DocumentNumbers") String bill,
#RequestParam(name = "BranchCode", required = true) String BranchCode);
default ResponseEntity<String> getInfo(String bill) {
return getInfo(bill, "");
}
this will not even have the param BranchCode
I am using org.springframework.cloud:spring-cloud-starter-openfeign:2.1.1.RELEASE
Spring boot version 2.1.4.RELEASE
is there anyway or workarounds for keeping empty params in urls as it is ?

If your URL is http://localhost:8080/trackingServlet/testing?userName=pratik
Use feign client:
#FeignClient(name = "tracking-servlet-service")
public interface TestFeignClient {
#GetMapping("/trackingServlet/testing")
public String getQueryParam(#RequestParam("userName") String name);
}
If you have 2 or more parameter then you can add same in #RequestParam
E.g
URL http://localhost:8080/trackingServlet/testing?userName=pratik&companyName=Test
#FeignClient(name = "tracking-servlet-service")
public interface TestFeignClient {
#GetMapping("/trackingServlet/testing")
public String getQueryParam(#RequestParam("userName") String name,
#RequestParam("companyName") String companyName);
}

Related

Spring rest controller inheritance by params

In our spring rest controller we would like to use the same mappings with different kind of parameters.
To do this we created additional functions differentiated by mapping params. By doing so we are duplicating the number of functions. To avoid this I would like to use different controllers that should be loaded based on params values.
The question is can we
#RequestMapping(value = "/v1")
#RestController
public class Controller {
#PostMapping(value = "/event-calendar", params = {"externalToken", "event_type"})
public ResponseEntity createEntityOfTypeToken(#RequestHeader(name = "X-Application-Authentication") String externalToken,
#RequestParam(value = "event_type") String eventType) {
MyEntity entity = service.createEntityOfType(
userService.getTokenService(externalToken).getDeviceSerialNumber());
return new ResponseEntity<>(entity, HttpStatus.OK);
}
#PostMapping(value = "/event-calendar", params = {"serialId", "event_type"})
public ResponseEntity createEntityOfTypeSerial(#RequestParam(value = "serialId") String serialId,
#RequestParam(value = "event_type") String eventType) {
MyEntity entity = service.createEntityOfType(serialId);
return new ResponseEntity<>(entity, HttpStatus.OK);
}
}
Please refer
create two method for same url pattern with different arguments
Spring - is possible to give same url in request mapping of post method?
P.S. not enough points to comment

How to convert one request param into several request params in Spring before calling a controller?

The client sends some data in one request param like:
example.com/test?myparam=some123data
I would like to convert myparam into several other params and call a necessary controller with such parameters. Like this one:
#RequestMapping(value = "/test")
public #ResponseBody MyObject test(
#RequestParam(value = "prefix") String prefix, // some
#RequestParam(value = "number") int number, // 123
#RequestParam(value = "suffix") String suffix) //data
{ ... }
It is possible to put some custom converter for such situation?
I'm not really sure if it can be made wit request params. Instead, you could use path variables with regular expressions in the following way:
#RequestMapping(value = "/test/{prefix:[a-z]+}{number:[0-9]+}{suffix:[a-z]+}")
public #ResponseBody MyObject test(
#PathVariable(value = "prefix") String prefix, // some
#PathVariable(value = "number") int number, // 123
#PathVariable(value = "suffix") String suffix) //data
{ ... }
In this case your request URL will look like this:
example.com/test/some123data
You can try to implement your own argument resolver, here an example

GetMapping in Spring boot to exclude specific path variable match

I have a controller with the following GetMapping
#GetMapping(value = "/dawson/v1/{dataType}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<String> respondWithData(#PathVariable String dataType, #RequestParam(name = "minDate") String min_date, #RequestParam(name = "maxDate") String max_date, #RequestParam(USERID) String user_id, #RequestHeader(value = "Authorization") String authorizationHeader) {
where dataType can be one of either String, Map, Object or Calendar. I created another GetMapping as follows
#GetMapping(value = "/dawson/v1/signInReq")
public ResponseEntity<String> mySignInRequest(#RequestBody Map<String, String> paramMap, HttpServletRequest request, HttpServletResponse response) {
However, when I try to access the /dawson/v1/signInReq, it still hits the first mapping and not the signInReq one. Is there a way to exclude signInReq as a match for {dataType}?
I do have the workaround of listing all possible dataTypes in the first mapping above but was wondering if there was a better way to handle it(Regex maybe?).
I used a REGEX pattern to resolve the filtering of path as follows:
#GetMapping(value = "/dawson/v1/{dataType:^.*(?!signInReq)}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
The Regex will only match requests that are not signInReq.

liferay spring portal #ResourceMapping can't trigger different types of http methods

I have created a liferay portlet application using Spring, thymeleaf and AngularJS. For communication between AngularJS and spring I need to create some rest calls which I have created using #ResourceMapping like as shown below. The application is working fine but the problem is that I don't know how to make GET, DELETE, PUT http REST calls since #ResourceMapping is not allowing to specify any methods.
#ResourceMapping(value="getUserDetail")
public void userDetail(#RequestParam long userId, ResourceResponse response) throws Exception {
Users users = new Users(userId);
// some logic
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
JSON_MAPPER.writeValue(response.getPortletOutputStream(), users);
}
When I used #RequestMapping instead of #ResourceMapping like as shown below
#RequestMapping(value="getUserDetail", method=RequestMethod.GET)
#ResponseBody
public void userDetail(#RequestParam long userId, ResourceResponse response) throws Exception {
System.out.println("Got detail request for user with id {} "+ userId);
// UserDetail userDetail = this.userService.getPortalUserDetail(userId);
List<String> users = new ArrayList<String>();
users.add("Manu");
users.add("Lissie");
users.add("John");
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
JSON_MAPPER.writeValue(response.getPortletOutputStream(), users);
}
I have got
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping': Initialization of bean failed; nested exception is java.lang.IllegalStateException: Mode mappings conflict between method and type level: [getUserDetail] versus [view]
Can anyone please tell me some solution for this
How to create different types of http calls using #ResourceMapping
Can we use #RequestMapping instead of #ResourceMapping in Liferay Spring portlet for REST calls
How can we create resource based REST urls like getUser/12/mumbai
How can we send REST json as body instead of Request Param
Mode mappings conflict exception
The question doesn't show it, but your controller probably has #RequestMapping("view") annotation. This type level mapping is in conflict with the method level mappings. You should remove #RequestMapping annotation on the controller class.
Request mapping examples
#Controller
public class SampleRESTFullController {
// Simple GET
#RequestMapping(value = "/helloSample", method = RequestMethod.GET)
#ResponseStatus(HttpStatus.OK)
public #ResponseBody List<HelloSample> helloSample() { ... }
// GET with path variable
#RequestMapping(value = "/helloSample/sampleId/{sampleId}", method = RequestMethod.GET)
public #ResponseBody HelloSample helloSample(#PathVariable("sampleId") Long sampleId) { ... }
// POST with #RequestBody
#RequestMapping(value = "/helloSample", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public #ResponseBody HelloSample createSample(#RequestBody HelloSample helloSample) { ... }
// PUT with path variable and #RequestBody
#RequestMapping(value = "/helloSample/sampleId/{sampleId}", method = RequestMethod.PUT)
#ResponseStatus(HttpStatus.NO_CONTENT)
void update(#PathVariable("sampleId") long sampleId, #RequestBody HelloSample helloSample) { ... }
// DELETE
#RequestMapping(value = "/helloSample/sampleId/{sampleId}", method = RequestMethod.DELETE)
#ResponseStatus(HttpStatus.NO_CONTENT)
void delete(#PathVariable("sampleId") long sampleId) { ... }
}
I took the examples from Using RESTFul services with Liferay blog post. It answers all your questions and presents tons of examples. Pay attention to Spring configuration, which makes the RESTful services possible (especially the view resolver and message converter).
1. How to create different types of http calls using #ResourceMapping
If you want to a REST Api with Complete Actions (GET, POST, PUT, DELETE) you need to use #RequestMapping.
2. Can we use #RequestMapping instead of #ResourceMapping in Liferay Spring portlet for REST calls
You should be able to use.
3. How can we create resource based REST urls like getUser/12/mumbai
#RequestMapping(value="getUser/{userId}/mumbai", method=RequestMethod.GET)
#ResponseBody
public List<String> userDetail(#RequestParam("userId") long userId) throws Exception {
System.out.println("Got detail request for user with id {} "+ userId);
//UserDetail userDetail = this.userService.getPortalUserDetail(userId);
List<String> users = new ArrayList<String>();
users.add("Manu");
users.add("Lissie");
users.add("John");
return users;
}
4. How can we send REST json as body instead of Request Param
You can use #RequestBody
#RequestMapping(value="saveUser/{userId}", method=RequestMethod.GET)
#ResponseStatus(HttpStatus.CREATED)
public void userDetail(#RequestParam("userId") long userId, #RequestBody User user) throws Exception {
// Logic
}
How to create different types of http calls using #ResourceMapping
Here are some examples that may help you, that's how i use #RequestMapping:
// GET
#RequestMapping(value = "/api/something", method = RequestMethod.GET)
#ResponseBody
public boolean getSomething() {
return "something";
}
// GET with param
#RequestMapping(value = "/api/something/{id}", method = RequestMethod.GET)
#ResponseBody
public boolean getSomething(#PathVariable("id") Long id) {
return id;
}
Instead of RequestMethod.GET you can use RequestMethod.POST,RequestMethod.PUT,RequestMethod.DELETE and so on...
How can we send REST json as body instead of Request Param
Here is a code snippet that i currently use with an AngularJS FrontEnd for user registration. It works just fine and i use #RequestMapping:
#ResponseBody
#RequestMapping(value = "/auth/register", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<User> register(#RequestBody User user) {
user = userService.initUser(user);
Authentication authentication = securityUserDetailsService.register(user);
if (authentication != null) {
SecurityContext context = SecurityContextHolder.getContext();
context.setAuthentication(authentication);
User authUser = securityUserDetailsService.getAuthenticatedUser();
return new ResponseEntity<>(authUser, HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
In order to consume JSON you do:
RequestMapping(value = "/whatever", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
In order to produce (return) JSON you do:
RequestMapping(value = "/whatever", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
Also since you use Spring i think you should take a look at Spring Data and Spring Data Rest. This way you can expose your business models as RESTful endpoints.
How can we create resource based REST urls like getUser/12/mumbai
So in order to expose this endpoint getUser/12/mumbai that's what you should do:
// mumbai hardcoded
#RequestMapping(value = "/getUser/{id}/mumbai", method = RequestMethod.GET)
#ResponseBody
public User getUser(#PathVariable("id") Long id) {
// go get the user ...
return user;
}
// mumbai as a param
#RequestMapping(value = "/getUser/{id}/{prop}", method = RequestMethod.GET)
#ResponseBody
public User getUser(#PathVariable("id") Long id, #PathVariable("prop") String prop) {
// go get the user ...
return user;
}
Lastly can you please try to change
public void userDetail (...
to this
public ResponseEntity<userDetail > (...
There are following methods to use rest app with angular js
#RequestMapping(value = "/saveuser", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
#RequestMapping(value = "/getemployee", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
#RequestMapping(value = "/editCountry", method = RequestMethod.PUT)
#RequestMapping(value = "/deleteCountry", method = RequestMethod.DELETE)
and use following javascript to communicate with spring controller
var formData = {
"userName" : 'Vasim',
"password" : '123456',
"roleName" : 'Admin'
};
var response = $http.post('add', formData);
response.success(function(data, status, headers, config) {
$scope.message = data;
});
var formData = {
"userName" : 'Vasim',
"password" : '123456',
"roleName" : 'Admin'
};
var response = $http.put('edit', formData);
response.success(function(data, status, headers, config) {
$scope.message = data;
});
$scope.delete= function(employeeId) {
$http['delete']('delete', {
params : {
'employeeId' : employeeId
}
}).
success(function(data) {
$scope.msg = data;
});
$http.get('get',{params:{
'id':id
}
}).success(function(data) {
$scope.employees = data;

Cannot handle request by requestMapping

I need to handle requests like
www.example.com/student/thisisname?age=23&country=UK&city=London
I am just interested in thisisname part and value of city parameter.
I have following RequestMapping but it does not work. I tried {name}{.*:city} as well.
#RequestMapping(value = "/{name:.*}{city}", method = RequestMethod.GET)
You can do it by 2 ways. Either using #RequestParam or #PathVariable
By Using #RequestParam
#RequestMapping(value = "/name", method = RequestMethod.GET)
public void someMethod(#RequestParam String city){}
By using #PathVariable
#RequestMapping(value = "/name/{city}", method = RequestMethod.GET)
public void someMethod(#PathVariable String city){}
You can use any of this method just you need to concentrate on URL
You can handle it using PathVariable and RequestParam annotation. In below code name is thisisname part and city is query param city value.
#RequestMapping(value = "/student/{name}", method = RequestMethod.GET)
public void someMethod(#PathVariable String name, #RequestParam("city") String city){
}

Categories

Resources