@RequestParam用法及原理

发布时间 2023-04-21 22:57:27作者: binbinx

@RequestParam用法及原理 

大家好,我是路人,这是 SpringMVC 系列第 23 篇。

前面没有详细介绍 SpringMVC 中各种注解的用法,这里准备一一补上,今天来看@RequestParam 注解的用法。

1、预备知识

  1. 接口测试利器 HTTP Client
  2. 参数解析器 HandlerMethodArgumentResolver 解密

2、@RequestParam 注解的作用

标注在接口的方法参数上,被标注的参数的值来源于request.getParameterrequest.getParameterValues

推荐阅读2021 最新版 Java 微服务学习线路图 + 视频

3、@RequestParam 源码

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {

 /**
  * 对应request中参数名称
  */
 @AliasFor("name")
 String value() default "";

 /**
  * 同value
  */
 @AliasFor("value")
 String name() default "";

 /**
  * 请求中是否必须有这个参数,默认为true
  */
 boolean required() default true;

 /**
  * 默认值
  */
 String defaultValue() default ValueConstants.DEFAULT_NONE;

}

4、案例 1:@RequestParam 指定 name,获取对应参数的值

4.1、案例接口代码

/**
 * {@link RequestParam}中指定name,用来取name的值对应的请求参数中的值
 *
 * @param name:可以不传递name参数,不传递的时候默认值为ready
 * @param age
 * @param pets
 * @return
 */
@RequestMapping("/requestparam/test1")
public Map<String, Object> test1(@RequestParam(value = "name", required = false, defaultValue = "ready") String name, //相当于request.getParameter("name")
                                 @RequestParam("age") int age, //Integer.parseInt(request.getParameter("age"))
                                 @RequestParam("interests") String[] interests, //request.getParameterValues("pets")
                                 @RequestParam("pets") List<String> pets //Arrays.asList(request.getParameterValues("pets"))
) {
    Map<String, Object> result = new LinkedHashMap<>();
    result.put("name", name);
    result.put("age", age);
    result.put("interests", interests);
    result.put("pets", pets);
    return result;
}

4.2、用例 1:所有参数都传值

POST http://localhost:8080/chat18/requestparam/test1
Content-Type: application/x-www-form-urlencoded

name=路人&age=35&interests=篮球&interests=旅游&pets=小狗&pets=小猫

运行上面用例代码输出

{
  "name": "路人",
  "age": 35,
  "interests": [
    "篮球",
    "旅游"
  ],
  "pets": [
    "小狗",
    "小猫"
  ]
}

4.3、用例 2:name 不传递,会取默认值 ready

POST http://localhost:8080/chat18/requestparam/test1
Content-Type: application/x-www-form-urlencoded

age=35&interests=篮球&interests=旅游&pets=小狗&pets=小猫

运行上面用例代码输出

{
  "name": "ready",
  "age": 35,
  "interests": [
    "篮球",
    "旅游"
  ],
  "pets": [
    "小狗",
    "小猫"
  ]
}

4.4、用来 3:required 属性为 true,不传,则报错

POST http://localhost:8080/chat18/requestparam/test1
Content-Type: application/x-www-form-urlencoded

参数都没有传递,而接口要求除 name 之外的,其他几个参数都必须传递,所以这个案例结果会报 400 错,提示 age 参数不存在,这个错误比较常见,大家熟悉下,以后看到了就知道什么问题了。

5、案例 2:@RequestParam 不指定 name,获取所有参数值

当我们想用一个 Map 来接收所有参数的之后,代码如下,@RequestParam 不用指定 name 的值,参数类型为 Map<String,String>,所有请求参数会以参数名称:值的方式丢在 Map 中。

/**
 * {@link RequestParam}不指定name,用于接收所有参数的值,
 * 参数类型为Map<String,String>,key为请求中的参数名称,value为值
 *
 * @param paramMap
 * @return
 */
@RequestMapping("/requestparam/test2")
public Map<String, String> test2(@RequestParam Map<String, String> paramMap) {
    return paramMap;
}

运行下面的用例调用上面接口

###
POST http://localhost:8080/chat18/requestparam/test2
Content-Type: application/x-www-form-urlencoded

name=路人&age=35&interests=篮球&interests=旅游&pets=小狗&pets=小猫

运行输出

{
  "name": "路人",
  "age": "35",
  "interests": "篮球",
  "pets": "小狗"
}

interests 和 pet 都是有多个值,上面的结果中都只获取了第一个 值,如果我们想获取所有的值呢,下面看案例 3。

6、案例 3:@RequestParam 不指定 name,获取所有参数值

/**
 * {@link RequestParam}不指定name,用于接收所有参数的值,
 * 参数类型为MultiValueMap<String, String>:key为请求中的参数名称,value为值的集合List<String>
 *
 * @param paramMap
 * @return
 */
@RequestMapping(value = "/requestparam/test3", produces = MediaType.APPLICATION_JSON_VALUE)
public MultiValueMap<String, String> test3(@RequestParam MultiValueMap<String, String> paramMap) {
    return paramMap;
}

这个接口的参数是MultiValueMap类型,这玩意是干啥的?好像很陌生啊,哈哈

再模式的东西,把其源码放出来,瞬间明了了,如下,可以看出来MultiValueMap相当于Map<String,List<String>>

public interface MultiValueMap<K, V> extends Map<K, List<V>> {
}

运行下面的用例调用上面接口,注意下面第 3 行,表示我们期望服务器端返回 json 格式数据

POST http://localhost:8080/chat18/requestparam/test3
Content-Type: application/x-www-form-urlencoded
Accept: application/json

name=路人&age=35&interests=篮球&interests=旅游&pets=小狗&pets=小猫

运行输出,结果的值比较特别,是一个 String 类型的数组,这次获取到所有参数的值了。

{
  "name": [
    "路人"
  ],
  "age": [
    "35"
  ],
  "interests": [
    "篮球",
    "旅游"
  ],
  "pets": [
    "小狗",
    "小猫"
  ]
}

7、@RequestParam 原理

@RequestParam 标注的参数的值是有下面 2 个类处理的,有兴趣了解的建议先看一下上一篇中的:参数解析器 HandlerMethodArgumentResolver 解密,然后再来看下面 2 个类的源码就是小意思了。

org.springframework.web.method.annotation.RequestParamMethodArgumentResolver
org.springframework.web.method.annotation.RequestParamMapMethodArgumentResolver

8、总结

  • @RequestParam 注解用来标注在控制器方法的参数上,springmvc 从 request 中获取请求的值赋值给方法的参数
  • @RequestParam 指定 name 时,可以获取 request 中指定参数的值,相当于 request.getParameter(name)或 request.getParameters(name)
  • @RequestParam 未指定 name,参数类型为:Map<String,String>时,用来接收 request 中所有参数的值,Map 中 key 为参数名称,value 为参数的值
  • @RequestParam 未指定 name,参数类型为 MultiValueMap<String, String>时,用来接收 request 中所有参数的值,key 为请求中的参数名称,value 为值的集合 List<String>
  • 推荐阅读尚硅谷 Java 学科全套教程(总 207.77GB)

9、代码位置及说明

9.1、git 地址

https://gitee.com/javacode2018/springmvc-series

9.2、本文案例代码结构说明

10、SpringMVC 系列目录

  1. SpringMVC 系列第 1 篇:helloword
  2. SpringMVC 系列第 2 篇:@Controller、@RequestMapping
  3. SpringMVC 系列第 3 篇:异常高效的一款接口测试利器
  4. SpringMVC 系列第 4 篇:controller 常见的接收参数的方式
  5. SpringMVC 系列第 5 篇:@RequestBody 大解密,说点你不知道的
  6. SpringMVC 系列第 6 篇:上传文件的 4 种方式,你都会么?
  7. SpringMVC 系列第 7 篇:SpringMVC 返回视图常见的 5 种方式,你会几种?
  8. SpringMVC 系列第 8 篇:返回 json & 通用返回值设计
  9. SpringMVC 系列第 9 篇:SpringMVC 返回 null 是什么意思?
  10. SpringMVC 系列第 10 篇:异步处理
  11. SpringMVC 系列第 11 篇:集成静态资源
  12. SpringMVC 系列第 12 篇:拦截器
  13. SpringMVC 系列第 13 篇:统一异常处理
  14. SpringMVC 系列第 14 篇:实战篇:通用返回值 & 异常处理设计
  15. SpringMVC 系列第 15 篇:全注解的方式 & 原理解析
  16. SpringMVC 系列第 16 篇:通过源码解析 SpringMVC 处理请求的流程
  17. SpringMVC 系列第 17 篇:源码解析 SpringMVC 容器的启动过程
  18. SpringMVC 系列第 18 篇:强大的 RequestBodyAdvice 解密
  19. SpringMVC 系列第 19 篇:强大的 ResponseBodyAdvice 解密
  20. SpringMVC 系列第 20 篇:RestFull 详解
  21. SpringMVC 系列第 21 篇:接口调用过利器 RestTemplate
  22. SpringMVC 系列第 22 篇:参数解析器 HandlerMethodArgumentResolver 解密

11、更多系列文章

  1. Spring 高手系列(共 56 篇)
  2. Java 高并发系列(共 34 篇)
  3. MySql 高手系列(共 27 篇)
  4. Maven 高手系列(共 10 篇)
  5. Mybatis 系列(共 12 篇)
  6. 聊聊 db 和缓存一致性常见的实现方式
  7. 接口幂等性这么重要,它是什么?怎么实现?
  8. 泛型,有点难度,会让很多人懵逼,那是因为你没有看这篇文章!

12、最新资料

  1. 尚硅谷 Java 学科全套教程(总 207.77GB)
  2. 2021 最新版 Java 微服务学习线路图 + 视频
  3. 阿里技术大佬整理的《Spring 学习笔记.pdf》
  4. 阿里大佬的《MySQL 学习笔记高清.pdf》
  5. 2021 版 java 高并发常见面试题汇总.pdf
  6. Idea 快捷键大全.pdf