java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot接口传参注解

SpringBoot中接口传参的三大注解(RequestParam/RequestBody/PathVariable)全面解析

作者:花生了什么事o

本文介绍了 @RequestParam、@PathVariable、@RequestBody三种注解的数据来源和适用场景,并以 HTTP语义为主线,帮助读者理解不同请求方法下该如何选择参数接收方式

我们在学习后端开发的时候,都在相应教学内容上看到过这三个注解。教程里直接给使用方式,但却没有详细说什么时候该用哪个。等到真正写项目接口的时候,就会开始纠结:分页参数用 @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 的查询参数里找 pagesize 这两个 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,3GET /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 的商品列表

路径中的 421001 就是资源标识,用 @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=valueURL 路径 /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接口传参注解的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文