Spring MVC and #RequestParam with x-www-form-urlencoded - java

I'm trying to build an API that takes a POST with one parameter in the body that should be x-www-form-urlencoded. I've currently mapped it as:
#RequestMapping(method = POST, consumes = APPLICATION_FORM_URLENCODED_VALUE, produces = APPLICATION_JSON_VALUE)
public ResponseEntity<LinkEntity> createShortLink(#RequestBody String url) {
LinkEntity savedLink = linkService.create(url);
}
When I do a POST with Postman (REST Chrome extension) with one form parameter url=http://www.drissamri.be it comes into this method as url=http%3A%2F%2Fwww.drissamri.be as expected.
When I try to change the #Requestbody into #RequestParam(value = "url") I still get the URL with the url= prefix (as expected) but it is not urlencoded anymore. Why doesn't the encoding take place any more? Is this a bug or is there another way to take in the parameter as urlencoded value

As correctly mentioned by Pavel Horal the parameter is retrieved by ServletRequest#getParameter and is already decoded. If you need to access the origin parameter you can access the parameter by other means.
One way would be to inject a HttpServletRequest and use HttpServletRequest#getQueryString() which does not decode the values.

Related

GetMapping with JSON array parameter

I am using a FeignClient and a GetMapping to interact with an external system.
My GetMapping is defined as:
#GetMapping(value = "/path/to/endpoint?fields=[\"nm\",\"label\"]")
public String hitEndpoint() {}
Debug shows that the endpoint is being called with:
https://url/path/to/endpoint?fields=[%22nm%22&fields=%22label%22]
Which is failing because the endpoint expects valid json for the fields parameter:
https://url/path/to/endpoint?fields=[%22nm%22,%22label%22]
How do I convince GetMapping to make the request correctly?
Thanks for any help.
Although I think its better to pass JSON as body of a POST method to your controller. But if you insist on doing this I can propose to you 2 solutions:
First Solution
Encode your JSON array into Percent-encoding so you can send it via URL.
For example, your array will be like this:
["nm","label"] -> %5B%22nm%22%2C%22label%22%5D
I used this online tool to encode it.
Second Solution
Encode your array into Base64 and GET it via URL to your controller.
Decode the given Base64 string in the controller and parse it as a JSON array.
There is no need to define your Array parameter in the URL, using spring you can define your API as below and with the power of #RequestParam annotation you can define that you expect to receive an array as a parameter in the URL
#RequestMapping(value = "/path-to-endpoint", method = RequestMethod.GET)
public ResponseEntity<YourResponseDTO> yourMethodName(
#RequestParam("ids") List<Long> arrayParam) {
// Return successful response
return new ResponseEntity<>(service.yourServiceMethod(requestDTO), HttpStatus.OK);
}
Then you can call your GET endpoint using below URL:
/path-to-endpoint?ids=1,2,3,4

Why when I use #PostMapping is the result correct, and when I replace it with #RequestMapping the result is a 404 HTTP error?

The code is here:
#ResponseBody
//#RequestMapping(name = "getScreenRecordListByHipJointEntity",method = RequestMethod.POST)
#PostMapping("getScreenRecordListByHipJointEntity")
public PageResult getScreenRecordListByHipJointEntity(#RequestBody HipJointVo hipJointVo) {
return hipJointScreenService.getScreenRecordListByHipJointEntity(hipJointVo);
}
When I request this API which uses PostMapping annotation, the result code is ok and nothing is wrong, but when I replace the annotation
#PostMapping("getScreenRecordListByHipJointEntity") with #RequestMapping(name = "getScreenRecordListByHipJointEntity",method = RequestMethod.POST), the HTTP request code is 404.
The requestBody has no changes. All the data is exactly the same.
And this is how I do the post request in postman
The problem is that you're using the name parameter of #RequestMapping, which isn't what you're intending. Instead, you should use value (which is the default parameter the value is applied to if you don't specify, as in your #PostMapping version) or path (which is a Spring alias to make the code more readable).
#RequestMapping and #PostMapping's default parameter is value and value is aliasFor path. Both parameter are for path mapping.
#PostMapping("getScreenRecordListByHipJointEntity") ==
#RequestMapping(value = "getScreenRecordListByHipJointEntity", method = RequestMethod.POST)
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestMapping.html

Spring Boot Content type 'multipart/form-data;boundary=--------------------------#;charset=UTF-8' not supported

I'm new to Spring...I have a Spring Boot API application and all of my methods (POST, GET, etc) work great with Postman when the Content-Type is set to application/json, I can send and receive JSON.
However, I'd really like for my methods to also accept a GET or POST in the browser. When I use the browser to do a GET, the API returns an INTERNAL_SERVER_ERROR. I created a small form and try to POST to my API, but then I get the UNSUPPORTED_MEDIA_TYPE: Content type 'multipart/form-data;boundary=--------------------------802438220043016845671644;charset=UTF-8' not supported
These are 2 of the methods in my #RestController:
#RequestMapping(method = RequestMethod.POST, value = {"","/"})
public ResponseEntity<MyModel> createModel(#Valid #RequestBody MyModelDto modelDto) {
MyModel model = modelService.createModel(modelDto);
URI createdModelUrl = ServletUriComponentsBuilder.fromCurrentRequest().path("/{identifier}")
.buildAndExpand(model.getIdentifier()).normalize().toUri();
return ResponseEntity.created(createdModelUrl).build();
#RequestMapping(method = RequestMethod.GET, value = "/{identifier}")
public Resource<MyModel> getByIdentifier(#PathVariable("identifier") String identifier) {
MyModel model = modelService.getByIdentifier(identifier);
Resource<MyModel> resource = new Resource<>(model);
return resource;
}
If there's any other code that would be helpful to show, let me know and I'll update the thread.
In createModel method, instead of #RequestBody, please use #ModelAttribute for MyModelDto parameter.
You can use can try following ways,
Set consume block in "#RequestMapping".
like , #RequestMapping(value="/abc", consume = "multipart/form-data", method=HTTPMethod.POST")
Use #Multipart annotation and file object as #Part annotation
Instead of use #RequestBody use #RequestPart.

Null Parameters in AJAX POST to Spring Controller

I'm having trouble doing an ajax POST to a Spring Controller using jquery.
The post contains several parameters, among which is a base 64 string that represents a file sent from the client side.
Now, if the file is under 1,5~2mb, the request gets done just fine.
If it surpasses this size, the controller returns that the request is syntatically incorrect.
I'm using encodeuricomponent in the client side.
In both scenarios, if I get the reader from the HTTPServletRequest, I can get the entire POST form. Needless tosay, it's super slow.
If the file is above 2 mb, I can also get the entire query by the method referenced above, but not by the getParameter() method(HTTPServletRequest) nor by annotations (#requestParam("file")).
This is my controller:
#ResponseBody
#RequestMapping(value="/uploadClient", method = RequestMethod.POST)
public String uploadClient( Model model, HttpServletRequest req,#RequestParam(value="file", required = false) String file, #RequestParam(value="projectID") Integer projectID,
#RequestParam(value="opID") Integer opID, #RequestParam(value="releaseID") Integer releaseID,
#RequestParam(value="name") String name, #RequestParam(value="url") String url,
#RequestParam(value="date") String date,
#RequestParam(value="version") String version, #RequestParam(value="comment") String comment,
#RequestParam(value="fileName") String fileName){
For uploading files using Spring, try using the multipart support. Refer to the link Spring's multipart (fileupload) support

In a Spring 3.0 GET request, what's the difference between a #PathVariable and a #RequestParam

In an example such as the following, what's the difference between a #PathVariable and a #RequestParam?
#RequestMapping(value = "/portfolio/{portfolioIdPath}", method = RequestMethod.GET)
public final String portfolio(HttpServletRequest request, ModelMap model,
#PathVariable long portfolioIdPath, #RequestParam long portfolioIdRequest)
#RequestParam binds a request parameter to a parameter in your method. In your example, the value of the parameter named "portfolioIdRequest" in the GET request will be passed as the "portfolioIdRequest" argument to your method. A more concrete example - if the request URL is
http://hostname/portfolio/123?portfolioIdRequest=456
then the value of the parameter "portfolioIdRequest" will be "456".
More info here: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-ann-requestparam
#PathVariable similarly binds the value of the URI template variable "portfolioIdPath" to the method parameter "portfolioIdPath". For example, if your URI is
/portfolio/123
then the value of "portfolioIdPath" method parameter will be "123".
More info here: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping-uri-templates
#RequestParam identifies the HTTP GET or POST parameter which is sent by the client(user), And #RequestMapping extracts a segment of URL which varies from request to request:
http://host/?var=1
In the above URL "var" is a requestparam.
http://host/registration/{which}
and above URL's {which} is a request mapping. You could call your service like :
http://host/registration/user
OR like
http://host/registration/firm
In your application you can access the value of {which} (In first case which="user" and in second which="firm".
It depends the way you want to handle your request
#RequestParam example
(request)http://something.com/owner?ownerId=1234
#PathVariable example
(request) http://something.com/owner/1234
(in tour code) /owner/{ownerId}

Categories