Spring Boot 中 @RequestBody 的全面解析

1. 基础概念与核心思想

@RequestBody 是 Spring MVC 中使用频率极高的注解之一,它用于将 HTTP 请求体(Request Body)中的 JSON / XML / 表单数据 自动转换为 Java 对象。初学者最困惑的问题通常是:

  • 它与 @RequestParam 有什么区别?
  • 为什么传 JSON 时必须加 @RequestBody
  • 为什么不加就接不到数据?
  • 底层到底是谁在解析 JSON?
  • 到底什么时候用它?

为了完全理解它,我们需要从 原理 → 用途 → 示例 → 实战 的路径来全面剖析。

核心理念

@RequestBody = 接收请求体内容(JSON/XML)并自动反序列化为 Java 对象

底层依赖的是:

HttpMessageConverter(消息转换器)

只要你的项目中有 Jackson(Spring Boot 默认引入),Spring 就能自动把 JSON → Java Bean。


2. 为什么需要 @RequestBody(解决什么痛点)

在没有 @RequestBody 之前,获取 JSON 只能通过原始方式:

BufferedReader reader = request.getReader();
String body = reader.lines().collect(Collectors.joining());
JSONObject json = new JSONObject(body);

痛点:

  • 代码冗长
  • 手动解析 JSON 容易出错
  • Controller 中充满重复逻辑
  • 参数多、层级深时异常复杂
  • 不支持自动校验(JSR303)

@RequestBody 的出现:

  • 自动解析 JSON
  • 支持复杂嵌套对象
  • 自动类型转换
  • 配合 @Valid 支持 Bean 校验
  • 支持集合、泛型、数组

请求体再复杂也能轻松解析。


3. 工作原理(底层机制)

理解原理是避免踩坑的关键。

Spring 处理请求的大概流程如下伪图示:

HTTP Request
      ↓
DispatcherServlet
      ↓
HandlerMapping 查找匹配的Controller方法
      ↓
HandlerAdapter 调用对应方法
      ↓
参数解析(ArgumentResolver)
      ↓
如果参数上有 @RequestBody → 使用 HttpMessageConverter 处理
      ↓
读取请求体(JSON)
      ↓
反序列化(Jackson)
      ↓
生成 Java 对象
      ↓
Controller 方法内部可直接使用

3.1 底层关键组件:HttpMessageConverter

常见的几个转换器:

转换器 说明
MappingJackson2HttpMessageConverter JSON 转换器(最常用)
StringHttpMessageConverter 文本 / 字符串转换
FormHttpMessageConverter 表单数据转换
Jaxb2RootElementHttpMessageConverter XML 转换器

当 Spring 听到你的 Controller 参数上有:

@RequestBody UserDTO user

它会自动交给 JSON 转换器处理。


4. @RequestBody 的各种使用场景

4.1 接收 JSON 对象

示例代码

前端请求:

{
  "username": "zhangsan",
  "age": 18
}

Java Bean:

@Data
public class UserDTO {
    private String username;
    private Integer age;
}

Controller:

@PostMapping("/user/add")
public String addUser(@RequestBody UserDTO user) {
    return "接收到用户:" + user.getUsername();
}

4.2 接收 JSON 数组

前端请求:

[
  {"username": "zs", "age": 18},
  {"username": "ls", "age": 20}
]

Controller:

@PostMapping("/user/list")
public String addUserList(@RequestBody List<UserDTO> users) {
    return "收到用户数量:" + users.size();
}

4.3 接收嵌套对象

前端 JSON:

{
  "orderId": 1001,
  "items": [
    {"name": "可乐", "count": 2},
    {"name": "面包", "count": 3}
  ]
}

Java Bean:

@Data
public class OrderItem {
    private String name;
    private Integer count;
}

@Data
public class OrderDTO {
    private Long orderId;
    private List<OrderItem> items;
}

4.4 与 @Valid 联合使用

@PostMapping("/user/save")
public String save(@Valid @RequestBody UserDTO user, BindingResult result) {
    if (result.hasErrors()) {
        return result.getFieldError().getDefaultMessage();
    }
    return "ok";
}

4.5 接收 Map

@PostMapping("/map")
public Map<String, Object> test(@RequestBody Map<String, Object> map) {
    return map;
}

5. 实战案例:用户注册接口(Spring Boot)

用户注册通常包含 JSON 请求:

{
  "username": "Tom",
  "password": "123456",
  "email": "tom@example.com"
}

5.1 Java Bean

@Data
public class RegisterDTO {

    @NotBlank(message = "用户名不能为空")
    private String username;

    @NotBlank(message = "密码不能为空")
    private String password;

    @Email(message = "邮箱格式不正确")
    private String email;
}

5.2 Controller 接口

@RestController
@RequestMapping("/auth")
public class AuthController {

    @PostMapping("/register")
    public String register(@Valid @RequestBody RegisterDTO dto, BindingResult result) {
        if (result.hasErrors()) {
            return result.getFieldError().getDefaultMessage();
        }
        return "注册成功:" + dto.getUsername();
    }
}

5.3 application.yml(完整示例)

server:
  port: 8080

spring:
  jackson:
    serialization:
      indent_output: true
  mvc:
    format:
      date: yyyy-MM-dd HH:mm:ss

6. 深入理解:@RequestBody vs @RequestParam vs @ModelAttribute

这是很多小白最困惑的问题。

6.1 区别表格(重点)

(根据要求,表格前后必须空一行)

注解 数据来源 常用格式 是否必须注解 使用场景
@RequestBody 请求体(Body) JSON/XML 必须 JSON 请求、前后端分离
@RequestParam URL 查询参数 ?a=1&b=2 可选 简单参数
@ModelAttribute 表单、URL 参数 form-data 可选 传统表单提交

6.2 判断依据

如果前端发 JSON → 一定要用 @RequestBody
如果是 URL 参数(?name=xxx)→ 用 @RequestParam
如果是 form 表单 → 用 @ModelAttribute(可省略)

7. 常见错误与 Debug 指南

错误 1:Required request body is missing

原因:

  • 使用 JSON 请求,但 Controller 没写 @RequestBody

错误示例:

@PostMapping("/add")
public void add(UserDTO user) { }  // ❌ user 为 null

正确:

@PostMapping("/add")
public void add(@RequestBody UserDTO user) { } // ✔

错误 2:415 Unsupported Media Type

原因:

  • 请求头没有写:
Content-Type: application/json

必须这样写:

curl -H "Content-Type: application/json" -d '{"a":1}' ...

错误 3:JSON parse error

原因:

  • JSON 格式语法错误
  • 字段类型不匹配(如 age=“abc”)

解决:

  • 检查 JSON
  • 检查字段类型

错误 4:List 接收失败

若前端发送:

[
  {"name":"a"}
]

Controller 必须写:

@RequestBody List<UserDTO> list

不能写:

@RequestBody UserDTO user   // ❌

8. 高级用法

8.1 自定义消息转换器

例如使用 Gson:

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        GsonHttpMessageConverter gsonConverter = new GsonHttpMessageConverter();
        converters.add(gsonConverter);
    }
}

8.2 响应体加密 / 解密

可以通过自定义:

  • RequestBodyAdvice
  • ResponseBodyAdvice

实现 Controller 层透明加密解密。


9. 实战案例:前后端分离的登录接口(完整)

9.1 JSON 请求

{
  "username": "admin",
  "password": "123456"
}

9.2 Java Bean

@Data
public class LoginDTO {
    private String username;
    private String password;
}

9.3 Controller

@RestController
@RequestMapping("/login")
public class LoginController {

    @PostMapping
    public String login(@RequestBody LoginDTO dto) {
        if ("admin".equals(dto.getUsername()) && "123456".equals(dto.getPassword())) {
            return "登录成功";
        }
        return "用户名或密码错误";
    }
}

10. 作者经验总结

10.1 什么时候必须用 @RequestBody?

  • 你使用的是 JSON 请求(前后端分离必用)
  • 请牢记:Body 中的数据不会被自动解析,必须使用 @RequestBody

10.2 最常见的坑

  • Content-Type 写错
  • Controller 参数没加 @RequestBody
  • JSON 字段类型不一致
  • 嵌套对象字段名错误

10.3 最佳实践

  • 所有 JSON 接口都加 @RequestBody
  • Bean 使用 @Data
  • 开启校验并处理异常
  • 全局异常处理,统一返回 JSON

11. 结语

到此我们已经从基础概念、底层原理、使用方法、示例代码、实战案例、错误排查、最佳实践等方面,完整讲解了 @RequestBody。无论是对于新手还是有经验的开发者,只要牢牢掌握这篇内容,就能完全吃透 Spring MVC 中请求体解析的核心机制。


正文到此结束
评论插件初始化中...
Loading...