Spring Boot 传参避坑指南:@RequestParam、@PathVariable 与 @RequestBody 到底怎么选?

27 阅读4分钟

在前后端分离的开发模式下,后端工程师每天都在和接口打交道。而写接口的第一步,就是准确接收前端传来的参数

很多初学者在面对 @RequestParam@PathVariable@RequestBody 时经常会一头雾水,甚至因为用错了注解导致满屏的 400 Bad Request 或者接收到的数据全为 null

今天,我们就来系统地梳理一下,在 Spring Boot 中到底该如何优雅地接收前端参数。


一、 GET 请求传参(查询数据)

GET 请求主要用于获取数据,参数通常拼接在 URL 中。我们有三种常见的接收方式:

1. 基础查询参数:@RequestParam

适用场景:前端通过 URL 问号拼接传参,例如 /api/stats?salesmanId=1001&month=2023-10

@GetMapping("/api/stats")
public Result getStats(
        @RequestParam("salesmanId") String salesmanId, 
        @RequestParam(value = "month", required = false, defaultValue = "2023-01") String month) {
    
    System.out.println("业务员ID: " + salesmanId);
    System.out.println("月份: " + month);
    return Result.success();
}

💡 避坑指南:

  • 默认情况下,被 @RequestParam 修饰的参数是必填的。如果前端不传,会直接报错 400。
  • 如果该参数是可选的,务必加上 required = false
  • 可以结合 defaultValue 设置默认值,防止空指针异常。

2. 多参数对象接收(推荐)

适用场景:GET 请求的查询条件非常多(如分页查询、多条件筛选),全写在方法参数里不仅代码冗长,还难以维护。

技巧:直接使用对象(DTO)接收,不需要加任何注解!Spring Boot 会自动将 URL 中的参数映射到实体类的同名属性上。

定义 DTO:

@Data 
public class StatsQueryDTO {
    private String salesmanId;
    private String month;
    private Integer pageNum;
    private Integer pageSize;
}

Controller:

@GetMapping("/api/stats/list")
public Result getStatsList(StatsQueryDTO queryDTO) {
    System.out.println("业务员ID: " + queryDTO.getSalesmanId());
    return Result.success();
}

3. RESTful 风格路径参数:@PathVariable

适用场景:参数作为 URL 路径的一部分,表达层级或具体资源的定位。例如 /api/salesman/1001

@GetMapping("/api/salesman/{salesmanId}")
public Result getSalesmanDetail(@PathVariable("salesmanId") String salesmanId) {
    System.out.println("查询的业务员ID: " + salesmanId);
    return Result.success();
}

二、 POST / PUT 请求传参(提交数据)

POST 和 PUT 请求主要用于新增或修改数据,这类请求通常带有请求体(Body),用于传递复杂的 JSON 数据。

核心注解:@RequestBody

适用场景:前端将参数放在 HTTP 报文的 Body 中,并以 JSON 格式(Content-Type: application/json)提交。

前端发送的 JSON 数据:

{
  "salesmanId": "1001",
  "name": "张三",
  "department": "销售一部",
  "skills": ["Java", "Spring Boot"]
}

Controller 接收:

@PostMapping("/api/salesman/add")
public Result addSalesman(@RequestBody SalesmanDTO salesmanDTO) {
    System.out.println("收到业务员姓名: " + salesmanDTO.getName());
    // 插入数据库逻辑...
    return Result.success();
}

💡 避坑指南:

  • 一个 HTTP 请求只有一个 Body,所以一个方法里只能有一个 @RequestBody
  • 如果你发现 POST 请求接收到的对象属性全是 null,大概率是忘了加 @RequestBody 注解,导致 Spring 尝试用 URL 参数去绑定对象。

三、 进阶:请求头参数获取

获取请求头:@RequestHeader

适用场景:获取前端放在 Request Header 中的通用数据,最典型的就是 Token 鉴权。

@GetMapping("/api/protected/data")
public Result getProtectedData(@RequestHeader("Authorization") String token) {
    System.out.println("当前用户的Token: " + token);
    return Result.success();
}

四、 总结与速查表(建议收藏)

为了方便大家日常开发,我总结了这张传参黄金法则速查表

请求方式前端传参位置后端接收注解常见场景
GET在 URL ? 后拼接 (?id=1&name=A)@RequestParam直接用对象接收列表查询、条件检索、导出报表
GET在 URL 路径中间 (/user/1001)@PathVariable根据主键 ID 查询详情
POST/PUT在请求体 (Body) 中传 JSON@RequestBody表单提交、新增、修改、复杂对象嵌套
通用在请求头中 (Header)@RequestHeader获取 Token、App版本号、设备信息

🛑 终极警告:千万不要在 GET 请求中使用 @RequestBody

虽然某些 HTTP 客户端(如 Postman)允许你在 GET 请求里塞入 Body,但在 HTTP 规范中这是不标准的。许多网关(如 Nginx)、代理服务器或浏览器可能会直接丢弃 GET 请求的 Body,导致线上环境参数丢失。 记住:查询用 GET + URL 传参,提交/修改用 POST/PUT + @RequestBody


希望这篇文章能帮你理清 Spring Boot 的参数绑定机制,写出更健壮的接口。如果有疑问,欢迎在评论区探讨!