Distinguish different values in #PostMapping, #GetMapping or #RequestMapping - spring

#PostMapping(value = { "/weblogin", "/mobilelogin" })
#ResponseStatus(HttpStatus.OK)
public AccessTokenResponseModel login() { // need to distinguish "/weblogin" or "/mobilelogin" }
In spring boot, How can I distinguish the post request comes from "/weblogin" or "/mobilelogin"
in login() method?

You could use the BEST_MATCHING_PATTERN_ATTRIBUTE attribute.
#PostMapping(value = { "/weblogin", "/mobilelogin" })
#ResponseStatus(HttpStatus.OK)
public AccessTokenResponseModel login(HttpServletRequest httpRequest) {
final String requestMapping = ( String ) httpRequest.getAttribute( HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE );
final boolean isMobileLogin = requestMapping.contains("/mobilelogin");
....
}

Related

Overloading SpringBoot #PostMapping controller method not working

I have faced some challenge and to describe shortly I created test application. Code you can see and error you can see below.
#RestController
public class TestController {
#PostMapping(value = "/test",params = { "a", "b" })
public String test(#RequestPart MultipartFile a, #RequestPart(required = false) MultipartFile b) {
return "test1";
}
#PostMapping(value = "/test", params = { "b" })
public String test(#RequestPart MultipartFile b) {
return "test2";
}
}
I`m trying to execute this request from postman:
And I`m getting such error in logs:
Resolved [org.springframework.web.bind.UnsatisfiedServletRequestParameterException:
Parameter conditions "a, b" OR "b" not met for actual request parameters: ]
The thing is, if I will put parameters also in postman (not in body, in request url: localhost:8080/test?b=anything) it will work fine, but I don`t need request params in url.
Is there some possible way to make it work?
I am able to override #PostMapping. But the type of the parameter should be different.
#PostMapping(value="/test" )
public String testApi(#ModelAttribute MultipartDTO multipartDTO) {
return "test1";
}
#PostMapping(value="/test" ,params = { "b" })
public String test(#RequestParam String b) {
return "test2";
}
/** DTO **/
#Data
public class MultipartDTO{
private MultipartFile a;
private MultipartFile b;
}
you can not map the same signature twice which contains the same Http methods then below error will occur.
java.lang.IllegalStateException: Ambiguous handler methods
try this one
#RestController
public class TestController {
#PostMapping("/test")
public String test(#RequestParam MultipartFile a, #RequestParam(required = false) MultipartFile b) {
return "test1";
}
#PostMapping("/test2")
public String test(#RequestParam MultipartFile b) {
return "test2";
}
}
You should try something like below.
#RestController
public class TestController {
#PostMapping(value = "/test")
public String test(#RequestParam MultipartFile a, #RequestParam(required = false) MultipartFile b) {
return "test1";
}
#PostMapping(value = "/test")
public String test(#RequestParam MultipartFile b) {
return "test2";
}
}

Can spring map POST parameters by a way other than #RequestBody

I am using #RestControllers with an application where all requests are POST requests ... As I learned from this post , you can't map individual post parameters to individual method arguments, rather you need to wrap all the parameters in an object and then use this object as a method parameter annotated with #RequestBody thus
#RequestMapping(value="/requestotp",method = RequestMethod.POST)
public String requestOTP( #RequestParam(value="idNumber") String idNumber , #RequestParam(value="applicationId") String applicationId) {
return customerService.requestOTP(idNumber, applicationId);
will not work with a POST request of body {"idNumber":"345","applicationId":"64536"}
MY issue is that I have A LOT of POST requests , each with only one or two parameters, It will be tedious to create all these objects just to receive the requests inside ... so is there any other way similar to the way where get request parameters (URL parameters) are handled ?
Yes there are two ways -
first - the way you are doing just you need to do is append these parameter with url, no need to give them in body.
url will be like - baseurl+/requestotp?idNumber=123&applicationId=123
#RequestMapping(value="/requestotp",method = RequestMethod.POST)
public String requestOTP( #RequestParam(value="idNumber") String idNumber , #RequestParam(value="applicationId") String applicationId) {
return customerService.requestOTP(idNumber, applicationId);
second- you can use map as follows
#RequestMapping(value="/requestotp",method = RequestMethod.POST)
public String requestOTP( #RequestBody Map<String,Object> body) {
return customerService.requestOTP(body.get("idNumber").toString(), body.get("applicationId").toString());
I have change your code please check it
DTO Class
public class DTO1 {
private String idNumber;
private String applicationId;
public String getIdNumber() {
return idNumber;
}
public void setIdNumber(String idNumber) {
this.idNumber = idNumber;
}
public String getApplicationId() {
return applicationId;
}
public void setApplicationId(String applicationId) {
this.applicationId = applicationId;
}
}
Rest Controller Method
#RequestMapping(value="/requestotp",method = RequestMethod.POST)
public String requestOTP( #RequestBody DTO1 dto){
System.out.println(dto.getApplicationId()+" (------) "+dto.getIdNumber());
return "";
}
Request Type -- application/json
{"idNumber":"345","applicationId":"64536"}
OR
#RequestMapping(value="/requestotp",method = RequestMethod.POST)
public String requestOTP( #RequestBody String dto){
System.out.println(dto);
return "";
}

404 Request Resource not found

I am using Spring Framework with restful web services, and I am trying to create an API with restful service and use a get method. I have created a method and I'm trying to have it return a string, but instead I get a 404 error - requested resources not found. Please see my code below:
#RestController
#RequestMapping("/test")
public class AreaController {
public RestResponse find(#PathVariable String name, ModelMap model) {
model.addAttribute("movie", name);
return "list";
}
}
I am using: localhosr:8080/MyProject/wangdu
This error occurs because you forgot to add
#RequestMapping(value = "/{name}", method = RequestMethod.GET) before your find method:
#RestController
#RequestMapping("/test")
public class AreaController {
#RequestMapping(value = "/{name}", method = RequestMethod.GET)
public RestResponse find(#PathVariable String name, ModelMap model) {
model.addAttribute("movie", name);
return "list";
}
}
Please make sure about this:
The value that the find method is returning is a String with the value "list" and the find method declaration is waiting for a RestResponse object
For example if I have a RestResponse object like this:
public class RestResponse {
private String value;
public RestResponse(String value){
this.value=value;
}
public String getValue(){
return this.value;
}
}
Then try to return the value in this way:
public RestResponse find(#PathVariable String name, ModelMap model) {
model.addAttribute("movie", name);
return new RestResponse("list");
}
Verify that the method has #RequestMapping annotation with the value that your expect from the url
#RequestMapping(method = RequestMethod.GET, value = "/{name}")
By default the proper way to call the rest resource is by the #RequestMapping value that you set at the #RestController level (#RequestMapping("/test")), in this case could be: http://localhost:8080/test/myValue
If you need to use a different context path then you can change it on the application.properties (for spring boot)
server.contextPath=/MyProject/wangdu
In that case you can call the api like this:
http://localhost:8080/MyProject/wangdu/test/myValue
Here is the complete code for this alternative:
#RestController
#RequestMapping("/test")
public class AreaController {
#RequestMapping(method = RequestMethod.GET, value = "/{name}")
public RestResponse find(#PathVariable String name, ModelMap model) {
model.addAttribute("movie", name);
return new RestResponse("list");
}

How to bind a cookie value to a pojo field in Spring MVC?

For example, I'd like to bind the value of the cookie in the current request to the pojo below.
#RequestMapping(path="/", method= GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> handleTheRequest(Foo foo){
return blah;
}
public class Foo{
private string cookieValue;
//Other fun fields
public void setCookieValue(String value){
this.cookieValue = value;
}
public string getCookieValue(){
return cookieValue;
}
}
Can you try ?
#RequestMapping(path="/", method= GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> handleTheRequest(#RequestBody Foo foo){
return blah;
}

#PathVariable Validation in Spring 4

How can i validate my path variable in spring. I want to validate id field, since its only single field i do not want to move to a Pojo
#RestController
public class MyController {
#RequestMapping(value = "/{id}", method = RequestMethod.PUT)
public ResponseEntity method_name(#PathVariable String id) {
/// Some code
}
}
I tried doing adding validation to the path variable but its still not working
#RestController
#Validated
public class MyController {
#RequestMapping(value = "/{id}", method = RequestMethod.PUT)
public ResponseEntity method_name(
#Valid
#Nonnull
#Size(max = 2, min = 1, message = "name should have between 1 and 10 characters")
#PathVariable String id) {
/// Some code
}
}
You need to create a bean in your Spring configuration:
#Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
You should leave the #Validated annotation on your controller.
And you need an Exceptionhandler in your MyController class to handle theConstraintViolationException :
#ExceptionHandler(value = { ConstraintViolationException.class })
#ResponseStatus(value = HttpStatus.BAD_REQUEST)
public String handleResourceNotFoundException(ConstraintViolationException e) {
Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
StringBuilder strBuilder = new StringBuilder();
for (ConstraintViolation<?> violation : violations ) {
strBuilder.append(violation.getMessage() + "\n");
}
return strBuilder.toString();
}
After those changes you should see your message when the validation hits.
P.S.: I just tried it with your #Size validation.
To archive this goal I have apply this workaround for getting a response message equals to a real Validator:
#GetMapping("/check/email/{email:" + Constants.LOGIN_REGEX + "}")
#Timed
public ResponseEntity isValidEmail(#Email #PathVariable(value = "email") String email) {
return userService.getUserByEmail(email).map(user -> {
Problem problem = Problem.builder()
.withType(ErrorConstants.CONSTRAINT_VIOLATION_TYPE)
.withTitle("Method argument not valid")
.withStatus(Status.BAD_REQUEST)
.with("message", ErrorConstants.ERR_VALIDATION)
.with("fieldErrors", Arrays.asList(new FieldErrorVM("", "isValidEmail.email", "not unique")))
.build();
return new ResponseEntity(problem, HttpStatus.BAD_REQUEST);
}).orElse(
new ResponseEntity(new UtilsValidatorResponse(EMAIL_VALIDA), HttpStatus.OK)
);
}

Resources