乐途乐途
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
  • 学习路径
  • 第1章 SpringMVC概述与DispatcherServlet

    • 本章导读:Spring MVC概述与DispatcherServlet
    • Spring MVC 是什么
    • MVC 设计模式
    • 前端控制器模式
    • DispatcherServlet
    • 核心组件协作
  • 第2章 控制器与请求映射

    • 本章导读:控制器与请求映射
    • Controller
    • RestController
    • RequestMapping
    • GetMapping
    • PostMapping
    • PutMapping
    • DeleteMapping
    • PathVariable
    • RESTful
    • 请求映射原理
  • 第3章 请求参数获取与转换

    • 本章导读:请求参数获取与转换
    • RequestParam
    • RequestBody
    • RequestHeader
    • CookieValue
    • Model
    • ModelAttribute
    • 数据绑定原理
    • 数据校验
  • 第4章 响应数据与视图解析

    • 本章导读:响应数据与视图解析
    • ResponseBody
    • ResponseEntity
    • ModelAndView
    • ViewResolver
    • HttpMessageConverter
    • forward与redirect
  • 第5章 拦截器过滤器与跨域

    • 本章导读:拦截器、过滤器与跨域
    • HandlerInterceptor
    • WebMvcConfigurer
    • CrossOrigin
    • 登录验证实战
  • 第6章 文件上传与异常处理

    • 本章导读:文件上传与异常处理
    • MultipartFile
    • 文件下载
    • ExceptionHandler
    • ControllerAdvice
    • RestControllerAdvice
    • ResponseStatus
  • 第7章 高级特性与最佳实践

    • 本章导读:高级特性与最佳实践
    • SessionAttributes
    • SessionAttribute
    • RedirectAttributes
    • MockMvc测试
    • 国际化
    • 最佳实践
  • 第8章 扩展与异步机制

    • 本章导读:扩展与异步机制
    • 异步请求处理
    • 自定义参数解析器
    • 内容协商

RequestBody

本章是请求参数获取系列的核心章节。如果说 @RequestParam、@RequestHeader、@CookieValue 处理的是"键值对形式"的零散数据,那么 @RequestBody 处理的是"结构化体"——它将 HTTP 请求体中的 JSON 或 XML 反序列化为完整的 Java 对象。这是 RESTful API 开发中最常用的数据绑定方式,也是前后端分离架构的基石。


定义与作用

@RequestBody 用于将 HTTP 请求体(Request Body)中的数据反序列化为 Java 对象。

在 RESTful 架构中,客户端通常以 JSON 格式提交复杂数据:

{
  "name": "张三",
  "department": "技术部",
  "salary": 25000,
  "skills": ["Java", "Spring", "MySQL"]
}

@RequestBody 的职责是:读取请求体中的这段 JSON 文本,通过 HttpMessageConverter 转换为对应的 Java 对象(如 Employee 实例)。

生活类比:拆箱验货

想象飞翔科技采购部收到一个快递包裹:

  • 包裹外箱(HTTP 请求头):贴有 Content-Type: application/json 标签,说明里面是 JSON 格式的货物清单
  • 包裹内物(HTTP 请求体):一张详细的 JSON 货物清单
  • @RequestBody:仓库管理员根据外箱标签确认格式(JSON),打开包裹,把清单上的每一项对应到仓库货架的指定位置(Java 对象的字段),完成入库

如果外箱标签写的是 application/xml,管理员就会按 XML 格式解析。如果标签缺失或写错,管理员会拒收(返回 415 Unsupported Media Type)。


核心原理

请求体反序列化完整流程

关键组件说明:

  1. RequestResponseBodyMethodProcessor:处理 @RequestBody 和 @ResponseBody 参数的解析器
  2. HttpMessageConverter:消息转换器,负责 HTTP 请求体/响应体与 Java 对象之间的互相转换
  3. MappingJackson2HttpMessageConverter:默认的 JSON 转换器,依赖 Jackson 库完成 JSON ↔ Java 对象的序列化/反序列化

Content-Type 与 Converter 的匹配

重要边界:@RequestBody 要求请求必须携带 Content-Type 头,且该类型必须被注册的 HttpMessageConverter 支持。Spring Boot 默认注册了 JSON、XML、String 等常用转换器。


适用位置与常用属性

@RequestBody 只能标注在 Controller 方法的参数 上。

属性类型默认值说明
requiredbooleantrue请求体是否必须存在。false 时请求体为空则参数为 null

注意:@RequestBody 没有 name 和 defaultValue 属性,因为它绑定的是整个请求体,不是某个键值对。


完整示例

场景

飞翔科技员工管理系统的前端黄俪开发了一个新增员工的表单页面。用户填写信息后,前端以 JSON 格式提交到后端。后端小崔使用 @RequestBody 接收并保存员工数据。

代码实现

package com.feixiang.web;

import org.springframework.web.bind.annotation.*;
import java.util.List;

@RestController
@RequestMapping("/employees")
public class EmployeeController {

    /**
     * 新增员工:JSON → Java 对象
     */
    @PostMapping
    public String createEmployee(@RequestBody Employee employee) {
        return String.format("已创建员工: %s, 部门: %s, 薪资: %d",
                employee.getName(), employee.getDepartment(), employee.getSalary());
    }

    /**
     * 批量更新:JSON 数组 → List<Java 对象>
     */
    @PutMapping("/batch")
    public String batchUpdate(@RequestBody List<Employee> employees) {
        return "批量更新员工数量: " + employees.size();
    }

    /**
     * 可选请求体
     */
    @PostMapping("/quick-create")
    public String quickCreate(@RequestBody(required = false) Employee employee) {
        if (employee == null) {
            return "使用默认配置创建员工";
        }
        return "快速创建: " + employee.getName();
    }
}

// Employee.java
package com.feixiang.web;

import java.util.List;

public class Employee {
    private String name;
    private String department;
    private Integer salary;
    private List<String> skills;

    // Getter / Setter
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public String getDepartment() { return department; }
    public void setDepartment(String department) { this.department = department; }
    public Integer getSalary() { return salary; }
    public void setSalary(Integer salary) { this.salary = salary; }
    public List<String> getSkills() { return skills; }
    public void setSkills(List<String> skills) { this.skills = skills; }
}

HTTP 请求示例

示例 1:JSON → Java 对象

curl -X POST "http://localhost:8080/employees" \
     -H "Content-Type: application/json" \
     -d '{
       "name": "张三",
       "department": "技术部",
       "salary": 25000,
       "skills": ["Java", "Spring", "MySQL"]
     }'

响应:

已创建员工: 张三, 部门: 技术部, 薪资: 25000

示例 2:JSON 数组 → List

curl -X PUT "http://localhost:8080/employees/batch" \
     -H "Content-Type: application/json" \
     -d '[
       {"name": "张三", "department": "技术部", "salary": 25000},
       {"name": "李四", "department": "产品部", "salary": 22000}
     ]'

响应:

批量更新员工数量: 2

示例 3:缺少 Content-Type(报错)

curl -X POST "http://localhost:8080/employees" \
     -d '{"name": "张三"}'

响应(HTTP 415):

{
  "timestamp": "2024-01-15T11:20:33.789+00:00",
  "status": 415,
  "error": "Unsupported Media Type",
  "message": "Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported"
}

未指定 Content-Type 时,curl 默认使用 application/x-www-form-urlencoded,Spring MVC 找不到支持该类型的 @RequestBody Converter,返回 415。


易错场景与面试考点

误区一:JSON 字段名与 Java 属性名不匹配

现象:客户端传 {"userName": "张三"},Java 对象是 private String name,绑定后 name 为 null。

原因:Jackson 默认按 Java 属性名(name)匹配 JSON 键(userName),不匹配则跳过。

解决:

  1. 统一命名规范(推荐):前后端约定统一使用驼峰命名
  2. 使用 @JsonProperty 注解映射:
@JsonProperty("userName")
private String name;

误区二:日期格式解析失败

现象:{"hireDate": "2024-01-15"} 绑定到 LocalDate hireDate 报错。

原因:Jackson 默认不支持 yyyy-MM-dd 格式的日期解析。

解决:

@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private LocalDate hireDate;

或在全局配置 ObjectMapper:

@Bean
public ObjectMapper objectMapper() {
    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(new JavaTimeModule());
    mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    return mapper;
}

误区三:400 错误排查清单

当 @RequestBody 接口返回 HTTP 400 时,按以下顺序排查:

排查项检查方法常见错误
Content-Type确认请求头包含 Content-Type: application/json缺失或写错为 text/plain
JSON 格式用 JSON 校验工具检查末尾多余逗号、引号不匹配
字段类型确认 JSON 值类型与 Java 类型匹配字符串传 "25" 但 Java 是 int
必填字段检查 Java 对象是否有无参构造缺少默认构造器导致 Jackson 无法实例化
日期格式检查日期字符串格式2024-01-15 与 2024/01/15 不匹配

面试高频:@RequestBody 和 @RequestParam 的区别

标准回答:

  1. 数据来源:@RequestParam 从 URL 查询参数或表单数据获取,@RequestBody 从 HTTP 请求体获取
  2. 数据格式:@RequestParam 处理键值对(name=value),@RequestBody 处理结构化数据(JSON/XML)
  3. Content-Type:@RequestBody 必须配合 Content-Type: application/json(或其他支持的类型),@RequestParam 通常配合 application/x-www-form-urlencoded
  4. 使用场景:@RequestParam 适合简单参数、GET 请求;@RequestBody 适合复杂对象、POST/PUT 请求
  5. 底层机制:@RequestBody 依赖 HttpMessageConverter 进行反序列化,@RequestParam 依赖 PropertyEditor 进行类型转换

小结

@RequestBody 是 Spring MVC 处理 RESTful API 请求体的核心注解。它通过 HttpMessageConverter 将 JSON/XML 等格式的请求体反序列化为 Java 对象,是前后端分离架构中数据传输的桥梁。

核心要点:

  • 必须携带正确的 Content-Type 请求头(通常是 application/json)
  • 依赖 Jackson 库完成 JSON 反序列化,确保 Java 对象有无参构造器和 Getter/Setter
  • JSON 字段名默认与 Java 属性名匹配,不匹配时用 @JsonProperty 映射
  • 400 错误优先排查 Content-Type、JSON 格式、类型匹配

本章与全局的关系:本章讲解了"如何将请求体中的结构化数据映射为 Java 对象"。下一节 @ModelAttribute 将讲解另一种对象绑定方式——它专门处理表单数据的绑定,与 @RequestBody 形成互补。

上一页
RequestParam
下一页
RequestHeader