Spring Boot 请求参数注解完全指南:从入门到精通

一篇文章搞懂 @PathVariable@RequestParam@RequestBody@ModelAttribute 等所有请求参数注解

前言

在 Spring Boot 开发过程中,相信大家都会遇到这样的场景:前端传来各种各样的请求参数,有的是在 URL 路径中,有的是在 URL "?" 后面,还有的是放在请求体中的 JSON 数据。我们应该如何在后端优雅地接收这些参数?Spring Boot 提供了一系列注解来帮助我们轻松完成请求参数的绑定,本文将对其中最常用的注解进行详细讲解,包括它们的用法、区别以及最佳实践。

掌握这几个注解,可以说 Web 开发中 90% 的参数接收场景都可以轻松应对。现在就让我们一起来学习吧!

一、@PathVariable:路径变量

1.1 简介

@PathVariable 注解用于从请求 URL 路径中获取变量的值。它非常适用于 RESTful 风格的接口设计,将 URL 路径中的某一部分作为参数传递给控制器方法。

比如,我们在设计获取用户信息的接口时,通常会将用户 ID(唯一标识)放在 URL 路径中:/api/users/123,其中 123 就是路径变量。

1.2 基本用法

java 复制代码
@RestController
@RequestMapping("/api/users")
public class UserController {
    
    // 访问示例:GET /api/users/100
    @GetMapping("/{userId}")
    public ResponseEntity<User> getUserById(@PathVariable Long userId) {
        // userId 的值自动绑定为 100
        return ResponseEntity.ok(userService.getUserById(userId));
    }
}

1.3 多个路径变量

一个 URL 路径中可以包含多个路径变量:

java 复制代码
// 访问示例:GET /api/users/100/orders/200
@GetMapping("/{userId}/orders/{orderId}")
public ResponseEntity<Order> getUserOrder(@PathVariable Long userId, @PathVariable Long orderId) {
    // userId=100, orderId=200
    return ResponseEntity.ok(orderService.findByUserAndOrder(userId, orderId));
}

1.4 参数名不一致时的处理

如果方法参数名与 URL 中的变量名不一致,可以通过 @PathVariablevalue 属性显式指定:

java 复制代码
@GetMapping("/{userId}")
public ResponseEntity<User> getUserById(@PathVariable("userId") Long id) {
    // 将 {userId} 的值绑定到 id 参数上
    return ResponseEntity.ok(userService.getUserById(id));
}

1.5 @PathVariable 常用属性

属性 说明 示例
value / name 绑定参数的名称,默认不传递时绑定为同名形参 @PathVariable("uid")
required 参数是否必须,默认为 true @PathVariable(required = false)

需要注意的是,如果 required=true 而路径中没有对应的变量,请求将会失败。

1.6 使用正则表达式精确匹配

可以对 URL 变量进行更精确的定义:

java 复制代码
// 只允许大小写字母、数字和下划线
@GetMapping("/user/{username:[a-zA-Z0-9_]+}")
public String getUserProfile(@PathVariable String username) {
    return "User: " + username;
}

这样一来,不合法的 URL 路径将直接被 Spring MVC 拒绝。

二、@RequestParam:请求参数(查询参数)

2.1 简介

@RequestParam 注解用于从 HTTP 请求中获取查询参数 (Query Parameters),这些参数通常出现在 URL 的 ? 之后,格式为 key=value,多个参数之间用 & 连接。

典型的使用场景包括:GET 请求的分页参数(pagesize)、搜索关键字等。

2.2 基本用法

java 复制代码
@RestController
@RequestMapping("/api/users")
public class UserController {
    
    // 访问示例:GET /api/users/search?username=zhang
    @GetMapping("/search")
    public ResponseEntity<List<User>> searchUsers(@RequestParam String username) {
        return ResponseEntity.ok(userService.searchByUsername(username));
    }
}

当参数名与方法参数名相同时,可以省略 value 属性。

2.3 参数可选与默认值

@RequestParam 提供了 requireddefaultValue 两个重要属性来处理可选参数:

java 复制代码
@GetMapping("/greet")
public String greet(
    @RequestParam(name = "name", required = false, defaultValue = "World") String name
) {
    // 当请求没有提供 name 参数时,使用默认值 "World"
    return "Hello, " + name + "!";
}
// 访问 /greet -> Hello, World!
// 访问 /greet?name=John -> Hello, John!

属性详解:

  • required :参数是否必须,默认为 true。如果设为 false,表示参数可选,不传时参数值为 null(对于基本数据类型需要特别注意空指针问题)
  • defaultValue :参数的默认值,一旦设置了 defaultValuerequired 的设置会失效
  • value/name:指定请求参数名称,如果不指定则默认使用方法参数名

2.4 @RequestParam 接收数组/集合

java 复制代码
// 访问示例:GET /api/users?ids=1,2,3&ids=4
@GetMapping
public ResponseEntity<List<User>> getUsers(@RequestParam List<Long> ids) {
    // ids = [1,2,3,4]
    return ResponseEntity.ok(userService.findByIds(ids));
}

当请求中有多个同名参数时,Spring Boot 会自动将其收集为数组或集合。

2.5 @RequestParam vs 不加注解的区别

如果在控制器方法参数上不加任何注解,Spring Boot 也会尝试将请求参数绑定到该参数上,且默认值为 required=false。但为了代码可读性和明确性,建议显式使用 @RequestParam

三、@RequestBody:请求体

3.1 简介

@RequestBody 注解用于接收 HTTP 请求体(Request Body)中的数据,并自动将其转换为 Java 对象。在前后端分离的架构中,这是最常用的注解之一,通常用来接收 POST/PUT 请求中携带的 JSON 或 XML 数据。

3.2 基本用法

首先定义一个实体类:

java 复制代码
@Data
public class UserRequest {
    private String username;
    private String email;
    private Integer age;
}

然后在控制器中使用 @RequestBody

java 复制代码
@RestController
@RequestMapping("/api/users")
public class UserController {
    
    // 请求示例:POST /api/users
    // 请求体:{"username": "zhang", "email": "zhang@example.com", "age": 25}
    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody UserRequest userRequest) {
        // Spring Boot 自动将 JSON 字符串映射到 userRequest 对象
        User user = userService.createUser(userRequest);
        return ResponseEntity.status(HttpStatus.CREATED).body(user);
    }
}

3.3 底层原理:HttpMessageConverter

@RequestBody 的自动转换能力依赖于 Spring Boot 的 HTTP 消息转换器(HttpMessageConverter) 机制。Spring Boot 默认集成了 Jackson,它会自动将请求体中的 JSON 反序列化为 Java 对象,同时也支持 XML、表单数据等多种格式:

  • 反序列化:将 HTTP 请求体的字节流(JSON/XML)转换为 Java 对象
  • 序列化 :将 Java 返回值对象转换为 HTTP 响应体的字节流(由 @ResponseBody 配合完成)

3.4 接收复杂嵌套对象

java 复制代码
@Data
public class OrderRequest {
    private Long orderId;
    private List<OrderItem> items;      // 嵌套的 List
    private Address shippingAddress;    // 嵌套的对象
}

@PostMapping("/order")
public ResponseEntity<String> createOrder(@RequestBody OrderRequest orderRequest) {
    // 自动解析嵌套的 JSON 结构
    return ResponseEntity.ok("Order created with " + orderRequest.getItems().size() + " items");
}

3.5 @RequestBody 使用注意事项

  • 不能用于 GET 请求 :因为 GET 请求没有请求体,用 @RequestBody 会报错
  • 每个 Controller 方法只能有一个 @RequestBody:请求体的输入流只能被读取一次
  • Content-Type 必须匹配 :请求需要携带 Content-Type: application/json 等匹配的媒体类型
  • 对象属性缺失的处理 :如果 JSON 中缺少实体类的某些属性,这些属性会被赋值为 null

3.6 @ResponseBody 小贴士

@ResponseBody 通常和 @RequestBody 成对出现,用于将 Java 对象序列化为 JSON 返回给前端。而 @RestController 注解实际上就是 @Controller@ResponseBody 的结合体,所以我们在使用 @RestController 时,所有方法的返回值会自动被序列化为 JSON 响应体,无需再单独添加 @ResponseBody

四、@ModelAttribute:模型属性绑定

4.1 简介

@ModelAttribute 注解用于将多个请求参数绑定到一个 Java 对象(命令对象)上,非常适用于处理表单提交场景。它可以出现在两个位置:

  1. 方法参数上:将请求参数绑定到对象的属性上
  2. 方法上(非请求处理方法):在执行 Controller 方法之前,预先将数据添加到模型中供视图使用

4.2 方法参数中使用(最常用)

java 复制代码
@Data
public class UserForm {
    private String username;
    private String password;
    private String email;
}

@PostMapping("/register")
public String register(@ModelAttribute UserForm userForm, Model model) {
    // userForm 的 username、password、email 属性已自动绑定表单数据
    userService.register(userForm);
    model.addAttribute("message", "注册成功");
    return "result";
}

4.3 @ModelAttribute vs @RequestBody 的区别

这两个注解很容易混淆,但本质上有着完全不同的处理方式:

对比维度 @ModelAttribute @RequestBody
数据来源 请求参数(Query Parameters + Form Data) 请求体(Request Body)
数据格式 application/x-www-form-urlencoded application/json / application/xml
数据绑定 简单数据绑定,逐个属性映射 使用消息转换器进行序列化/反序列化
适用场景 传统 Web 表单提交 RESTful API 前后端分离

简单来说:传统表单用 @ModelAttribute,现代 REST API 用 @RequestBody

4.4 接收表单数据的方式对比

在 Spring Boot 中接收表单数据有三种常见方式:

方式一:使用 @RequestParam 逐个接收

java 复制代码
@PostMapping("/submit")
public String submit(@RequestParam("name") String name, @RequestParam("email") String email) {
    // 处理...
}

方式二:不加注解(Spring 自动绑定)

java 复制代码
@PostMapping("/submit")
public String submit(String name, String email) {
    // 处理...
}

方式三:使用 @ModelAttribute 封装为对象

java 复制代码
@PostMapping("/submit")
public String submit(@ModelAttribute User user) {
    // 处理...
}

当参数较多时,使用 @ModelAttribute 封装为对象是更优雅的选择。

五、其他常用注解

5.1 @RequestHeader:获取请求头

@RequestHeader 用于获取 HTTP 请求头中的信息。虽然业务代码中不太常用,但在认证鉴权、链路追踪等基础设施中不可或缺:

java 复制代码
@GetMapping("/user")
public ResponseEntity<User> getUserList(
    @RequestHeader("Authorization") String authToken,
    @RequestHeader Map<String, String> allHeaders          // 获取所有请求头
) {
    // 验证 token 并返回数据
    return ResponseEntity.ok(userRepo.findAll());
}

@RequestHeader 也支持 requireddefaultValue 属性,用法与 @RequestParam 类似。

当需要与客户端保持会话状态时,@CookieValue 可以方便地读取 Cookie 中的值:

java 复制代码
@GetMapping("/welcome")
public String welcome(@CookieValue(name = "sessionId", defaultValue = "none") String sessionId) {
    return "Session ID: " + sessionId;
}

5.3 @MatrixVariable:矩阵变量

@MatrixVariable 是一种比较少见(但在某些国外系统中会遇到)的参数形式,参数使用 ; 分隔:

java 复制代码
// 访问示例:GET /books/reviews;isbn=1234;topN=5
@GetMapping("/books/reviews")
public List<BookReview> getBookReviews(
    @MatrixVariable String isbn,
    @MatrixVariable Integer topN
) {
    return bookReviewsLogic.getTopNReviewsByIsbn(isbn, topN);
}

5.4 @RequestAttribute:获取请求域属性

@RequestAttribute 用于获取通过请求转发设置的 request 域属性值,主要用于请求转发(forward)场景:

java 复制代码
// 在过滤器或拦截器中 setAttribute
request.setAttribute("userInfo", userInfo);

// 在 Controller 中获取
@GetMapping("/profile")
public String getProfile(@RequestAttribute("userInfo") UserInfo userInfo) {
    return "user: " + userInfo.getUsername();
}

六、注解对比总结

注解 数据来源 适用请求方法 适用场景 必填属性
@PathVariable URL 路径中(如 /user/{id} GET / POST / PUT / DELETE RESTful 资源标识 required
@RequestParam 查询参数(?key=value GET(为主)/ POST 分页、筛选、搜索 required, defaultValue
@RequestBody 请求体(JSON/XML) POST / PUT / PATCH 创建/更新复杂对象 required
@ModelAttribute 表单/查询参数 GET / POST 传统表单提交 不常用
@RequestHeader HTTP 请求头 所有方法 认证 Token、TraceID required, defaultValue
@CookieValue Cookie 所有方法 Session ID、用户偏好 required, defaultValue
@MatrixVariable 矩阵变量(;key=value 所有方法 特殊 URL 设计 required, defaultValue
@RequestAttribute Request 域(setAttribute 所有方法 请求转发数据传递 required

快速选择指南

  • 路径中的唯一标识 (如用户 ID、订单号)→ @PathVariable
  • GET 请求的筛选/分页参数 (如 ?page=1&size=10)→ @RequestParam
  • POST/PUT 请求的 JSON 数据 (前后端分离)→ @RequestBody
  • 传统表单提交 (参数多且分散)→ @ModelAttribute@RequestParam
  • 需要读取请求头中的元数据 (如 Token)→ @RequestHeader
  • 需要读取浏览器 Cookie (如 Session ID)→ @CookieValue

七、多注解组合使用

在实际业务中,有时需要同时接收多种类型的参数,例如:从路径中获取用户 ID、从查询参数中获取筛选条件、从请求体中获取修改的数据:

java 复制代码
@PutMapping("/users/{userId}/profile")
public ResponseEntity<User> updateUserProfile(
    @PathVariable Long userId,                    // 从路径中获取用户 ID
    @RequestParam(required = false) String flag,  // 从查询参数中获取标志
    @RequestBody UserProfileRequest request       // 从请求体中获取更新数据
) {
    // 三个参数各司其职
    userService.updateProfile(userId, request, flag);
    return ResponseEntity.ok().build();
}

需要注意的是,@PathVariable@RequestParam@RequestBody 都是互不冲突的,可以根据需要在同一个方法中组合使用多个。

八、常见问题与避坑指南

8.1 @RequestParam required=true 但参数缺失

现象:请求中没有携带必填参数,返回 400 错误。

解决 :将 required 设为 false 或提供 defaultValue

8.2 @RequestBody 接收的参数为 null

可能原因

  1. 请求的 Content-Type 不是 application/json
  2. JSON 字段名与 Java 对象属性名不匹配
  3. 实体类缺少无参构造方法或 Getter/Setter 方法

8.3 @PathVariable 参数中包含斜杠被截断

默认情况下,路径变量不能包含 URL 分隔符 /,如果需要接收包含斜杠的值,可以使用正则表达式:

java 复制代码
@GetMapping("/files/{path:[a-zA-Z0-9/]+}")
public String getFile(@PathVariable String path) { ... }

8.4 基本数据类型与 required=false 的坑

当参数为基本数据类型(如 intlong)且 required=false 时,如果请求中没有该参数,会有空指针问题。应使用包装类(IntegerLong)来接收可选参数。

8.5 defaultValue 与 required 同时使用的注意事项

设置 defaultValue 后,required 的设置会失效。也就是说,即使你写了 required=true 并设置了 defaultValue,参数不传时也不会报错,会直接使用默认值。

结语

本文详细介绍了 Spring Boot 中用于接收请求参数的核心注解,从最常用的 @PathVariable@RequestParam@RequestBody,到表单绑定的 @ModelAttribute,再到请求头、Cookie 等相对进阶的注解,涵盖了日常开发中 90% 以上的参数接收场景。

在实际开发中,建议大家:

  1. 优先使用 RESTful 风格的 URL 设计 ,合理使用 @PathVariable 标识资源
  2. 前后端分离项目统一使用 @RequestBody 传递复杂数据
  3. 大量且相似的表单参数 ,使用 @ModelAttribute 封装为对象
  4. 保持代码可读性,即使是简单参数也建议显式使用注解
相关推荐
MegaDataFlowers3 小时前
代码自动生成
java
dllxhcjla3 小时前
Spring全套
java·后端·spring
@杰克成4 小时前
Java学习24
java·学习·idea
挨踢ren4 小时前
C++虚函数:从基础到高阶
java·开发语言·jvm
IT 行者4 小时前
Spring AI 2.0.0-M5 发布:全面转向 OpenAI Java SDK
java·人工智能·spring
Resky08184 小时前
ReentrantReadWriteLock 深度解析
java·开发语言·juc
铭keny4 小时前
子系统 SSO 单点登录接入配置指南
java
追逐时光者4 小时前
2026 年 .NET 客户端常用 MVVM 框架推荐
后端·.net
_Evan_Yao4 小时前
长上下文模型(1M token)会杀死RAG吗?—— 理性分析
人工智能·后端
电商API_180079052474 小时前
淘宝商品评论数据获取指南|批量自动化|api应用
java·爬虫·spring·性能优化·自动化