为何@RequestParam优先绑定请求体参数,无则绑定URL参数?
Question
I've written the following Spring MVC request interface:
@RequestMapping(value = "/test", method = RequestMethod.POST) public void test(ModelMap modelMap, @RequestParam(value = "name") String name) { modelMap.put("result",name); }
When calling this interface with Postman:
- If I pass the
nameparameter both in the request body and the URL, the result shows the value from the request body. - If I remove the parameter from the request body, the result shows the value from the URL.
Why does the @RequestParam annotation prioritize binding parameters from the request body, and only bind URL parameters when the request body has no such parameter?
Answer
Great question! Let’s break down the behavior you’re seeing step by step:
1. What @RequestParam actually reads from
First, a common misconception: @RequestParam doesn’t only pull values from the URL’s query string. Instead, it retrieves values from the combined parameter set of the HttpServletRequest in Spring MVC. This set includes two key sources when dealing with POST requests:
- Query parameters from the URL (the part after
?) - Form parameters from the request body if the request uses the
application/x-www-form-urlencodedcontent type (this is Postman’s default for "form data" submissions, or explicitly selecting thex-www-form-urlencodedtab)
2. Servlet container’s parameter merging rule
When handling a application/x-www-form-urlencoded POST request, the underlying Servlet container (like Tomcat, Jetty) follows a specific order to parse parameters:
- First, it parses the query string from the URL and adds those parameters to the request’s parameter map.
- Next, it parses the form parameters from the request body and adds them to the same map.
The critical part here: if a parameter with the same name exists in both sources, the value from the request body will overwrite the one from the URL. This is because the body parameters are parsed later, and the container uses the most recently parsed value for duplicate keys.
That’s exactly why when you send name in both places, your endpoint picks up the body’s value first.
3. What happens when the body has no matching parameter
If you remove the name parameter from the request body, the Servlet container’s parameter map only contains the value from the URL’s query string. So @RequestParam naturally falls back to that value since it’s the only one available.
A quick note on other content types
This behavior only applies to application/x-www-form-urlencoded (and multipart/form-data for file uploads, where @RequestParam can also read form fields). If you send a request with a different content type like application/json, @RequestParam will not read values from the request body—you’d need @RequestBody for that, and @RequestParam would only use URL query parameters.
内容的提问来源于stack exchange,提问作者Sawan

