Using HTTP dev client with Post request and Content-Type application/x-www-form-urlencoded
URL: localhost:8080/SpringMVC/welcome
Body: name=abc
@RequestMapping(method = RequestMethod.POST)
public String printWelcome(@RequestBody String body, Model model) {
model.addAttribute("message", body);
return "hello";
}
// Gives body as 'name=abc' as expected
URL: localhost:8080/SpringMVC/welcome
In Body - name=abc
@RequestMapping(method = RequestMethod.POST)
public String printWelcome(@RequestParam String name, Model model) {
model.addAttribute("name", name);
return "hello";
}
// Gives name as 'abc' as expected
URL: localhost:8080/SpringMVC/welcome
Body: name=abc
@RequestMapping(method = RequestMethod.POST)
public String printWelcome(
@RequestBody String body,
@RequestParam String name, Model model)
{
model.addAttribute("name", name);
model.addAttribute("message", body);
return "hello";
}
// HTTP Error Code 400 - The request sent by the client was syntactically incorrect.
URL: localhost:8080/SpringMVC/welcome
Body: name=abc
@RequestMapping(method = RequestMethod.POST)
public String printWelcome(
@RequestParam String name,
@RequestBody String body, Model model)
{
model.addAttribute("name", name);
model.addAttribute("message", body);
return "hello";
}
// No Error. Name is 'abc'. body is empty
URL: localhost:8080/SpringMVC/welcome?name=xyz
Body: name=abc
@RequestMapping(method = RequestMethod.POST)
public String printWelcome(
@RequestBody String body,
@RequestParam String name, Model model)
{
model.addAttribute("name", name);
model.addAttribute("message", body);
return "hello";
}
// name is 'xyz' and body is 'name=abc'
@RequestMapping(method = RequestMethod.POST)
public String printWelcome(
@RequestParam String name,
@RequestBody String body, Model model)
{
model.addAttribute("name", name);
model.addAttribute("message", body);
return "hello";
}
// name = 'xyz,abc' body is empty
Can someone explain this behaviour?
This question is related to
spring
spring-mvc
post
http-post
http-request-parameters
You could also just change the @RequestParam default required status to false so that HTTP response status code 400 is not generated. This will allow you to place the Annotations in any order you feel like.
@RequestParam(required = false)String name
It's too late to answer this question, but it could help for new readers,
It seems version issues. I ran all these tests with spring 4.1.4 and found that the order of @RequestBody
and @RequestParam
doesn't matter.
body= "name=abc"
, and name = "abc"
body ="name=abc"
, name = "xyz,abc"
It happens because of not very straight forward Servlet specification. If you are working with a native HttpServletRequest
implementation you cannot get both the URL encode body and the parameters. Spring does some workarounds, which make it even more strange and nontransparent.
In such cases Spring (version 3.2.4) re-renders a body for you using data from the getParameterMap()
method. It mixes GET and POST parameters and breaks the parameter order. The class, which is responsible for the chaos is ServletServerHttpRequest
. Unfortunately it cannot be replaced, but the class StringHttpMessageConverter
can be.
The clean solution is unfortunately not simple:
StringHttpMessageConverter
. Copy/Overwrite the original class adjusting method readInternal()
.HttpServletRequest
overwriting getInputStream()
, getReader()
and getParameter*()
methods.In the method StringHttpMessageConverter#readInternal following code must be used:
if (inputMessage instanceof ServletServerHttpRequest) {
ServletServerHttpRequest oo = (ServletServerHttpRequest)inputMessage;
input = oo.getServletRequest().getInputStream();
} else {
input = inputMessage.getBody();
}
Then the converter must be registered in the context.
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true/false">
<bean class="my-new-converter-class"/>
</mvc:message-converters>
</mvc:annotation-driven>
The step two is described here: Http Servlet request lose params from POST body after read it once
Source: Stackoverflow.com