開發者希望在 Controller 方法中直接使用對象參數(如 User user),不添加 @RequestBody、@ModelAttribute 等註解,但發現 GET 可行、POST 參數為空。
SpringMVC 通過 HandlerMethodArgumentResolver 解析參數。對於非簡單類型(非基本類型、String、Date 等),默認使用 ServletModelAttributeMethodProcessor,其邏輯:
@RequestBody → 是則讀取 Body 反序列化WebDataBinder 將請求參數映射到對象屬性| 請求方式 | 參數來源 | Content-Type | 綁定結果 |
|---|---|---|---|
| GET | URL Query String | 無 | ✅ 正常綁定 |
| POST (form) | Request Body | application/x-www-form-urlencoded | ✅ 正常綁定 |
| POST (JSON) | Request Body | application/json | ❌ 失敗(需 @RequestBody) |
| POST (multipart) | Request Body | multipart/form-data | ✅ 正常綁定(含文件) |
關鍵點:MappingJackson2HttpMessageConverter 只處理 @RequestBody 註解的參數,不參與默認模型屬性綁定。
// POST JSON 必須加
@PostMapping("/user")
public Result createUser(@RequestBody User user) { ... }
// GET/POST form 可選加 @ModelAttribute 或不加
@GetMapping("/user")
public Result queryUser(User user) { ... } // 來自 ?name=xxx&age=11
@PostMapping("/user/form")
public Result updateUser(User user) { ... } // 來自 form 表單
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureArgumentResolvers(List resolvers) {
// 自定義 Resolver:檢測 JSON Content-Type 並反序列化
resolvers.add(new JsonRequestBodyArgumentResolver());
}
}
// 自定義 Resolver 核心邏輯
public class JsonRequestBodyArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return !parameter.hasParameterAnnotation(RequestBody.class)
&& !isSimpleType(parameter.getParameterType());
}
@Override
public Object resolveArgument(...) {
if ("application/json".equals(request.getContentType())) {
return objectMapper.readValue(request.getInputStream(), parameter.getParameterType());
}
return UNRESOLVED; // 交給下一個 Resolver
}
}
@PostMapping(value = "/user", consumes = MediaType.APPLICATION_JSON_VALUE)
public Result create(@RequestBody User user) { ... }
@PostMapping(value = "/user", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public Result createForm(@RequestBody User user) { ... } // Spring 5.2+ 支持 form 反序列化
1. 創建目標對象實例(默認構造函數)
2. PropertyEditor / Converter 轉換每個請求參數
3. 根據屬性名匹配:request.getParameter("userName") → user.setUserName()
4. 支持嵌套屬性:user.address.city
5. 支持集合/數組:user.roles[0].name
6. 驗證(若有 @Valid):JSR-303 Bean Validation
application/x-www-form-urlencodedFormatter 或 Converteraddress.city 需前綴 address.SpringMVC 默認支持無註解對象參數綁定,但僅限於請求參數(Query/Form)來源。JSON 請求體必須使用 @RequestBody 觸發 HttpMessageConverter。混淆兩者是導致「GET 行、POST 空」的核心原因。建議:明確語義加註解,@RequestBody 表消費 Body,無註解表綁定參數,代碼可讀性與維護性雙贏。