SpringBoot中接口传参的三大注解(RequestParam/RequestBody/PathVariable)全面解析
我们在学习后端开发的时候,都在相应教学内容上看到过这三个注解。教程里直接给使用方式,但却没有详细说什么时候该用哪个。等到真正写项目接口的时候,就会开始纠结:分页参数用 @RequestParam,那查详情的 ID 放在路径里用 @PathVariable 还是也用 @RequestParam?提交表单十几个字段,是全用 @RequestParam 一个个接,还是塞进一个对象用 @RequestBody?
三种注解都能拿到前端传来的数据,但它们的数据来源、适用场景、HTTP 语义完全不同。搞混了代码能跑,但接口设计会很别扭。我们一个一个来看一下使用场景。
一、@RequestParam:从 URL 查询参数中取值
@RequestParam 对应的是 URL 中 ? 后面的查询参数(Query String)。
@GetMapping("/users")
public List<User> listUsers(
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size) {
return userService.listUsers(page, size);
}
前端请求:GET /users?page=1&size=10
Spring 看到 @RequestParam,就知道去 URL 的查询参数里找 page 和 size 这两个 key,取出来转成 int,注入到方法参数里。defaultValue 是个保底:如果前端没传这个参数,就用默认值,不会报错。
适用场景
筛选、排序、分页这种可选的查询条件。 用 @RequestParam 最合适。参数是 URL 的一部分,浏览器地址栏能直接看到,方便调试和分享链接。
@GetMapping("/products")
public List<Product> search(
@RequestParam(required = false) String keyword,
@RequestParam(required = false) String category,
@RequestParam(defaultValue = "price") String sortBy) {
return productService.search(keyword, category, sortBy);
}
请求:GET /products?keyword=手机&category=electronics&sortBy=price
注意 required = false:这个参数是可选的,不传也不会报 400。如果你确定某个参数必须传(比如分页的页码),可以用 required = true(默认值),前端不传就直接返回 400 错误。
多个值的情况
一个参数还能接收多个值,前端用同一个 key 传多次:
@GetMapping("/users/batch")
public List<User> getByIds(@RequestParam List<Long> ids) {
return userService.getByIds(ids);
}
请求:GET /users/batch?ids=1,2,3 或 GET /users/batch?ids=1&ids=2&ids=3
Spring 会自动把多个值收集到 List 里。
二、@PathVariable:从 URL 路径中取值
@PathVariable 对应的是 URL 路径中用 {xxx} 占位的部分。
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
return userService.getUserById(id);
}
前端请求:GET /users/42
{id} 是一个路径变量,@PathVariable 告诉 Spring:去 URL 路径里把 {id} 位置的值取出来,转成 Long,赋给 id 参数。
适用场景
标识具体资源的场景。 RESTful 风格的 API 设计中,用路径来表达"操作的是哪个资源"。
GET /users/42 → 查看用户 42
PUT /users/42 → 更新用户 42
DELETE /users/42 → 删除用户 42
GET /orders/1001/items → 查看订单 1001 的商品列表
路径中的 42、1001 就是资源标识,用 @PathVariable 接收。这种设计比 GET /users?id=42 更符合 REST 语义,URL 也更简洁直观。
多个路径变量
一个 URL 里可以有多个占位符:
@GetMapping("/departments/{deptId}/employees/{empId}")
public Employee getEmployee(
@PathVariable Long deptId,
@PathVariable Long empId) {
return employeeService.get(deptId, empId);
}
请求:GET /departments/5/employees/128
两个占位符对应两个 @PathVariable,Spring 会按名称匹配。
三、@RequestBody:从请求体中取值
@RequestBody 对应的是 HTTP 请求的 Body 部分。当前端发送 JSON 格式的数据时,Spring 会用 HttpMessageConverter(默认是 Jackson)把 JSON 反序列化成 Java 对象。
@PostMapping("/users")
public User createUser(@RequestBody UserCreateRequest request) {
return userService.createUser(request);
}
// 请求体对应的 DTO
public class UserCreateRequest {
private String name;
private String email;
private Integer age;
// getter/setter
}
前端请求:
POST /users
Content-Type: application/json
{
"name": "张三",
"email": "zhangsan@example.com",
"age": 25
}
Spring 看到 @RequestBody,就知道把整个请求体读出来,用 Jackson 解析成 UserCreateRequest 对象。字段名要和 JSON 的 key 对应,类型要能转换,否则直接报 400。
适用场景
提交复杂表单数据、创建或更新资源。 当参数多、结构复杂、或者包含嵌套对象时,@RequestBody 是最佳选择。
// 嵌套对象的场景
public class OrderCreateRequest {
private Long userId;
private List<OrderItem> items;
private Address shippingAddress;
private String paymentMethod;
}
public class OrderItem {
private Long productId;
private Integer quantity;
}
public class Address {
private String province;
private String city;
private String detail;
}
这种嵌套结构,用 @RequestParam 一个个接几乎不可能,用 @RequestBody 一行搞定。
三种注解对比
| 对比维度 | @RequestParam | @PathVariable | @RequestBody |
|---|---|---|---|
| 数据来源 | URL 查询参数 ?key=value | URL 路径 /users/{id} | HTTP 请求体 Body |
| Content-Type | 无要求 | 无要求 | 通常 application/json |
| 参数数量 | 适合少量可选参数 | 适合 1-2 个资源标识 | 适合复杂/大量参数 |
| HTTP 方法 | 任意 | 任意 | 通常 POST/PUT |
| 典型场景 | 分页、筛选、排序 | 资源标识、RESTful 路径 | 创建、更新、复杂提交 |
| 浏览器可见性 | 地址栏可见 | 地址栏可见 | 不可见(在请求体里) |
一句话总结:@RequestParam 管查询条件,@PathVariable 管资源标识,@RequestBody 管请求体。
什么时候用哪个:按 HTTP 语义来选
与其记住注解的语法,不如理解 HTTP 本身的语义。每个 HTTP 方法有它自己的含义,参数怎么传跟着语义走就行了。
GET 请求:筛选和查询
GET 用来获取资源。参数通常是可选的筛选条件,放在 URL 查询参数里:
@GetMapping("/articles")
public List<Article> search(
@RequestParam(required = false) String keyword,
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "20") int size) {
return articleService.search(keyword, page, size);
}
如果要查某个具体资源,用路径标识:
@GetMapping("/articles/{id}")
public Article getDetail(@PathVariable Long id) {
return articleService.getById(id);
}
GET 请求没有请求体,所以 @RequestBody 在 GET 中没有意义。 虽然 HTTP 规范没有明确禁止 GET 带 Body,但大多数 HTTP 客户端和代理服务器会忽略 GET 的 Body,Spring 默认也不支持。如果你发现自己想在 GET 里用 @RequestBody,大概率是接口设计有问题,应该改成 POST。
POST 请求:创建资源
POST 用来提交数据、创建资源。数据通常比较复杂,放在请求体里:
@PostMapping("/articles")
public Article create(@RequestBody @Valid ArticleCreateRequest request) {
return articleService.create(request);
}
PUT 请求:更新资源
PUT 用来更新资源。被更新的资源用路径标识,更新的内容放请求体:
@PutMapping("/articles/{id}")
public Article update(
@PathVariable Long id,
@RequestBody ArticleUpdateRequest request) {
return articleService.update(id, request);
}
这里 @PathVariable 和 @RequestBody 同时出现——一个管"更新谁",一个管"更新成什么",职责非常清晰。
DELETE 请求:删除资源
DELETE 用来删除资源,被删除的对象用路径标识:
@DeleteMapping("/articles/{id}")
public void delete(@PathVariable Long id) {
articleService.delete(id);
}
把上面的规律总结成一张表:
| HTTP 方法 | 资源标识 | 请求数据 | 典型注解组合 |
|---|---|---|---|
| GET | @PathVariable | @RequestParam | 查询列表 / 查看详情 |
| POST | — | @RequestBody | 创建资源 |
| PUT | @PathVariable | @RequestBody | 更新资源 |
| DELETE | @PathVariable | — | 删除资源 |
使用时注意事项
@RequestBody 不能和 @RequestParam 混用在同一参数上
有些新手会写出这种代码:
// 错误写法
@PostMapping("/users")
public User create(@RequestBody @RequestParam UserDTO dto) {
...
}
这两个注解的数据来源是矛盾的:@RequestBody 从请求体取,@RequestParam 从查询参数取。一个参数不可能同时从两个地方取值。Spring 会直接报错。
正确的做法是分清楚:哪些参数从查询参数来,哪些从请求体来:
@PostMapping("/users")
public User create(
@RequestParam(defaultValue = "false") Boolean notify, // 查询参数
@RequestBody UserDTO dto) { // 请求体
return userService.create(dto, notify);
}
@PathVariable 的变量名要和路径占位符一致
// 如果占位符叫 {userId},参数名也得叫 userId
@GetMapping("/users/{userId}")
public User getUser(@PathVariable Long userId) { ... }
@RequestBody 的校验
@RequestBody 接收的对象通常需要校验。配合 @Valid 注解和 JSR-303 校验注解一起用:
public class UserCreateRequest {
@NotBlank(message = "用户名不能为空")
private String name;
@Email(message = "邮箱格式不正确")
private String email;
@Min(value = 0, message = "年龄不能为负数")
private Integer age;
}
@PostMapping("/users")
public User create(@RequestBody @Valid UserCreateRequest request) {
return userService.create(request);
}
不加 @Valid,校验注解不会生效,前端传什么数据都能进来。
接收数组或列表
@RequestBody 可以直接接收 JSON 数组:
@PostMapping("/users/batch")
public List<User> batchCreate(@RequestBody List<UserCreateRequest> requests) {
return userService.batchCreate(requests);
}
前端传一个 JSON 数组就行:
[
{"name": "张三", "email": "zhangsan@example.com"},
{"name": "李四", "email": "lisi@example.com"}
]
小结
三种注解的本质区别在于数据来源不同:@RequestParam 从 URL 查询参数取,@PathVariable 从 URL 路径取,@RequestBody 从请求体取。不用死记语法,只需要跟着 HTTP 语义走:GET 查询用 @RequestParam,资源标识用 @PathVariable,复杂数据提交用 @RequestBody。
以上就是SpringBoot中接口传参的三大注解(RequestParam/RequestBody/PathVariable)全面解析的详细内容,更多关于SpringBoot接口传参注解的资料请关注脚本之家其它相关文章!
相关文章
springboot使用小工具之Lombok、devtools、Spring Initailizr详解
这篇文章主要介绍了springboot使用小工具之Lombok、devtools、Spring Initailizr详解,Lombok可以代替手写get、set、构造方法等,需要idea装插件lombok,本文通过示例代码给大家介绍的非常详细,需要的朋友可以参考下2022-10-10


最新评论