SpringBoot 中 @RequestParam 的完整使用详解

1. @RequestParam 的基础概念与核心思想

在 Web 开发中,请求参数是最常见的数据传递方式之一。无论是查询列表、分页、搜索、筛选,还是接口调试中的简单参数提交,开发者都离不开对 URL 参数的读取。SpringBoot 在处理 HTTP 请求参数时,提供了一个非常关键且高频使用的注解 —— @RequestParam

@RequestParam 的核心用途是:将 HTTP 请求中的 QueryString 参数Form 表单字段 绑定到控制器方法的形参上。简单理解:

/api/user?name=Tom&age=18

对应的 Controller 方法可能是:

@GetMapping("/api/user")
public String getUser(@RequestParam String name,
                      @RequestParam int age) {
    return name + " - " + age;
}

伪图示:

浏览器或服务端请求:
    URL: /api/user?name=Tom&age=18
           │       │           │
           └───>   name=Tom    └── age=18

SpringMVC 参数解析器:
    将 Query 参数绑定到对应形参

Controller 方法:
    getUser("Tom", 18)

其本质属于 SpringMVC 提供的 参数解析机制(Argument Resolver)

核心思想总结

  • @RequestParam 专门用于 接收 URL Query 参数表单参数
  • 基于 SpringMVC 中的 RequestParamMethodArgumentResolver 完成解析
  • 支持基本类型、包装类型、字符串、List、单值、多值等格式
  • 支持默认值、必填校验、参数重命名

2. 为什么需要 @RequestParam:解决了哪些痛点

如果不使用 @RequestParam,SpringMVC 仍然能够自动绑定参数,例如:

@GetMapping("/api/search")
public String search(String keyword, Integer page) { }

看似可行,但存在如下痛点:

2.1 无法明确参数来源

不加任何注解,Spring 需要自行判断该从:

  • Query 参数?
  • PathVariable?
  • RequestBody?
  • ModelAttribute?

对于初学者往往容易产生混淆。@RequestParam 明确告诉框架:

这个字段来自请求参数(QueryString / Form)

2.2 不能设置默认值、必填校验

无注解时:

  • 参数是否必填?(无法明确)
  • 缺参数时返回什么?(默认为 null)
  • 默认值如何处理?(只能手动代码判断)

@RequestParam 包含了:

属性 说明
required 是否必须存在
defaultValue 默认值
value/name 指定参数名

因此它可以提供更安全的接口约束。

2.3 多值参数处理不方便

例如:

/api/item?ids=1,2,3
/api/item?ids=1&ids=2&ids=3

使用 @RequestParam List<Integer> ids 能自动解析多值,避免手写复杂解析逻辑。

2.4 接口文档可读性更强

在多人开发中:

@GetMapping("/list")
public String list(@RequestParam("keyword") String kw) { }

比无注解更清晰,让维护更容易。


3. @RequestParam 的工作原理(底层机制)

SpringMVC 处理请求时,参数的绑定机制遵循以下流程:

DispatcherServlet
    └── HandlerMapping → 找到 Controller 方法
    └── HandlerAdapter
            └── ArgumentResolvers (参数解析器链)
                      └── 找到能处理 @RequestParam 的解析器
                            RequestParamMethodArgumentResolver

该解析器会执行如下逻辑:

  1. 判断方法参数是否含有 @RequestParam
  2. 判断参数是否为简单类型(基础类型、字符串、包装类型)
  3. 根据注解配置(value、required、defaultValue)读取参数
  4. 通过类型转换器 ConversionService 转换类型
  5. 将结果作为实参传入 Controller 方法

伪代码流程:

if(param.hasAnnotation(@RequestParam)):
    name = annotation.value or paramName
    if(required && not exist):
        throw MissingServletRequestParameterException
    else:
        value = request.getParameter(name)
        if(defaultValue exists and value == null):
            value = defaultValue
    convertedValue = conversionService.convert(value, targetType)
    return convertedValue

理解底层机制非常重要,因为:

  • 能帮助你定位参数解析类错误
  • 能解决复杂情况下的绑定问题
  • 能更好设计 API 和参数结构

4. @RequestParam 的基本用法

4.1 最简单的参数绑定

@GetMapping("/hello")
public String hello(@RequestParam String name) {
    return "Hello " + name;
}

请求方式:

GET /hello?name=Tom

4.2 指定参数名(value 或 name)

@GetMapping("/user")
public String getUser(@RequestParam("username") String name) {
    return name;
}

作用:

URL: /user?username=Tom
绑定为方法参数 name

4.3 设置默认值 defaultValue

@GetMapping("/page")
public Integer page(@RequestParam(defaultValue = "1") Integer pageNum) {
    return pageNum;
}

即使不传参数,也不会报错:

GET /page → 返回 1

4.4 设置参数非必填(required=false)

@GetMapping("/optional")
public String optional(@RequestParam(required = false) String q) {
    return q == null ? "no param" : q;
}

4.5 结合默认值与非必填

@GetMapping("/search")
public String search(@RequestParam(defaultValue = "") String keyword) {
    return keyword;
}

4.6 多值参数绑定

方式 1:逗号分隔

/ids?list=1,2,3
@GetMapping("/ids")
public Object getIds(@RequestParam List<Integer> list) {
    return list;
}

方式 2:多 key 重复

/ids?list=1&list=2&list=3

自动解析:

@GetMapping("/ids")
public Object getIds(@RequestParam List<Integer> list) {
    return list;
}

4.7 参数绑定到数组

@GetMapping("/tags")
public String[] tags(@RequestParam String[] t) {
    return t;
}

5. 实战案例:RESTful 接口中的参数设计

以下以一个简单“用户查询接口”为例。

5.1 Controller 代码

@RestController
@RequestMapping("/api/user")
public class UserController {

    @GetMapping("/list")
    public Object list(@RequestParam(defaultValue = "1") Integer page,
                       @RequestParam(defaultValue = "10") Integer size,
                       @RequestParam(required = false) String keyword,
                       @RequestParam(required = false) List<Integer> roles) {

        Map<String, Object> map = new HashMap<>();
        map.put("page", page);
        map.put("size", size);
        map.put("keyword", keyword);
        map.put("roles", roles);

        return map;
    }
}

5.2 请求示例

GET /api/user/list?page=2&size=20&keyword=admin&roles=1,2

返回:

{
  "page": 2,
  "size": 20,
  "keyword": "admin",
  "roles": [1, 2]
}

6. @RequestParam 与其他参数注解的区别

6.1 与 @PathVariable 的区别

注解 来源 示例 URL 用途
@RequestParam Query 参数 ?id=1 过滤、分页、条件
@PathVariable 路径参数 /user/1 REST规范中的资源 ID

示例:

@GetMapping("/user/{id}")
public Integer get(@PathVariable Integer id) { }

6.2 与 @RequestBody 的区别

注解 数据来源 格式
@RequestParam Query / Form key=value
@RequestBody JSON application/json

示例:

@PostMapping("/add")
public User add(@RequestBody User user) { }

典型错误:

前端传 JSON,却用 @RequestParam 接收 → 接收不到

这是初学者最常踩的坑之一。


7. 参数校验:结合 @Valid 使用

常见示例:

DTO

public class QueryDTO {
    @NotNull
    private Integer page;

    @NotNull
    private Integer size;

    // getter / setter
}

Controller

@GetMapping("/query")
public Object query(@Valid QueryDTO dto) {
    return dto;
}

注意:此时 DTO 内属性没有 @RequestParam,但 SpringMVC 依然能够从 Query 参数绑定。

原因是:没有注解时,Spring 会使用 ModelAttribute 解析器处理表单或 Query 参数。


8. @RequestParam 的常见错误与调试指南

8.1 required = true,但参数缺失

错误示例:

@GetMapping("/age")
public int age(@RequestParam int age) { }

请求:

GET /age

报错:

MissingServletRequestParameterException

解决办法:

  • 加默认值
  • 设置 required=false
  • 使用包装类型 Integer 代替 int

8.2 前端 JSON 调用接口报错

请求:

POST /add
Content-Type: application/json
{ "name": "Tom" }

Controller 却写成:

public String add(@RequestParam String name)

结果 name=null。

根本原因:

JSON 体 == RequestBody
不是 Query 参数

正确写法:

public String add(@RequestBody User user)

8.3 多值数组解析异常

例如前端传:

ids=1,2,3,abc

就会发生类型转换错误。

排查方式:

  • 检查是否包含非数字字符
  • 检查是否有空值(连续两个逗号)
  • 查看 ConversionService 的错误日志

9. 最佳实践:如何设计更优雅的参数接收

9.1 基础类型不要使用原始类型

避免:

int page

使用:

Integer page

原因:

  • 避免 required=true 时缺参报错
  • 允许 null,更灵活

9.2 对分页参数使用默认值

推荐:

@RequestParam(defaultValue = "1") Integer page

9.3 多值参数使用 List,而非数组

理由:

  • List 更好扩展
  • 与多数框架序列化方式更一致

推荐:

@RequestParam List<Integer> ids

9.4 对复杂条件查询,不建议写太多 @RequestParam

不优雅:

public Object list(@RequestParam Integer page,
                   @RequestParam Integer size,
                   @RequestParam String name,
                   @RequestParam String gender,
                   @RequestParam Integer age,
                   @RequestParam List<Integer> roles)

推荐将复杂结构参数封装成 DTO:

public Object list(UserQueryDTO dto)

10. 项目级实战示例:用户管理模块的参数接收

场景:实现用户搜索接口

10.1 DTO 结构

public class UserQueryDTO {
    private String keyword;
    private Integer page = 1;
    private Integer size = 10;
    private List<Integer> roles;

    // getter / setter
}

10.2 Controller 代码

@RestController
@RequestMapping("/api/user")
public class UserController {

    @GetMapping("/search")
    public Map<String, Object> search(UserQueryDTO dto) {

        Map<String, Object> result = new HashMap<>();
        result.put("keyword", dto.getKeyword());
        result.put("page", dto.getPage());
        result.put("size", dto.getSize());
        result.put("roles", dto.getRoles());

        return result;
    }
}

10.3 请求示例

GET /api/user/search?keyword=Tom&roles=1,2&page=3

11. 与全局类型转换结合

传递日期参数:

/api/time?date=2025-05-10

如果:

public String time(@RequestParam Date date)

未配置全局转换器会报错。

解决方式:添加全局转换器

@Configuration
public class DateConfig implements WebMvcConfigurer {
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addFormatter(new DateFormatter("yyyy-MM-dd"));
    }
}

12. 高级用法:Map、MultiValueMap 参数接收

12.1 Map 接收所有 Query 参数

@GetMapping("/all")
public Map<String, String> all(@RequestParam Map<String, String> params) {
    return params;
}

请求:

/all?a=1&b=2

输出:

{ "a": "1", "b": "2" }

12.2 MultiValueMap 接收重复 key

@GetMapping("/multi")
public MultiValueMap<String, String> multi(@RequestParam MultiValueMap<String, String> params) {
    return params;
}

请求:

/multi?a=1&a=2&b=3

结果:

{
  "a": ["1", "2"],
  "b": ["3"]
}

13. 作者经验总结(全局总结)

  • @RequestParam 是 SpringMVC 中最基础、最常用的参数注解之一,必须熟练掌握
  • 对于简单查询参数,使用 @RequestParam 更清晰
  • 大量条件参数时,使用 DTO 更优雅
  • 原始类型(int/long)在接收参数时容易报错,应使用包装类型
  • 多值参数优先使用 List
  • 默认值和 required 属性是开发中最重要的两个配置
  • Query 参数绝不能用 @RequestBody 接收
  • 多层级结构参数尽量用 JSON + @RequestBody
  • Map 和 MultiValueMap 适用于通用型网关或日志统计场景

正文到此结束
评论插件初始化中...
Loading...