当前位置:网站首页>代码技巧——Controller参数注解@RequestParam
代码技巧——Controller参数注解@RequestParam
2022-07-02 06:15:00 【七海健人】
本篇介绍下Controller参数注解@RequestParam的使用方法,使用时的注意事项,以及与HttpServletRequest#getParameter方法的区别;
1. 注解@RequestParam的作用
(1)是SpringMVC中接收普通参数的注解,注解打在Controller的方法参数上;
(2)可以将URL请求参数映射绑定到Controller的方法参数上,便于业务接收处理HTTP请求参数;
(3)通过注解的属性,可以对Controller参数做一些简单的"必传校验"和"默认值填充";
2. 注解@RequestParam参数说明
参考:org.springframework.web.bind.annotation.RequestParam
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {
/**
* Alias for {@link #name}.
*/
@AliasFor("name")
String value() default "";
/**
* The name of the request parameter to bind to.
* @since 4.2
*/
@AliasFor("value")
String name() default "";
/**
* Whether the parameter is required.
* <p>Defaults to {@code true}, leading to an exception being thrown
* if the parameter is missing in the request. Switch this to
* {@code false} if you prefer a {@code null} value if the parameter is
* not present in the request.
* <p>Alternatively, provide a {@link #defaultValue}, which implicitly
* sets this flag to {@code false}.
*/
boolean required() default true;
/**
* The default value to use as a fallback when the request parameter is
* not provided or has an empty value.
* <p>Supplying a default value implicitly sets {@link #required} to
* {@code false}.
*/
String defaultValue() default ValueConstants.DEFAULT_NONE;
}
解释:
- value:name属性的别名,作用相同;
- name:URL中的参数名,映射到当前注解对应的参数上;如果没有设置该属性,方法参数名则和接口参数名匹配;
- required:默认值是"true",表示该请求路径中必须包含该参数,如果不包含就会报404错误码;
- defaultValue:String类型,默认参数值,如果设置了该值,属性required=true将失效,自动为false;如果没有传该参数,就使用默认值;默认值也可以是SpEL表达式;
3. 使用示例
(1)name属性
@RequestMapping(value = "/testParams", method = RequestMethod.POST)
public BaseResponse<String> testParams(HttpServletRequest request, @RequestParam(name = "pkgName") String packageName) {
log.warn("[request.getParameterMap={} request.getParameter(\"packageName\")={} packageName={}]",
JSON.toJSONString(request.getParameterMap()),
request.getParameter("packageName"),
packageName);
return BaseResponse.success("ok");
}
控制台输出:
[request.getParameterMap={"pkgName":["com.ee.test.aaa"]} request.getParameter("pkgName")=com.ee.test.aaa packageName=com.ee.test.aaa]
URL中的参数名为"pkgName",通过注解name属性,Controller方法参数使用"packageName"去接收参数;
(2)required属性
默认require=true,不传递该参数则会报错;
控制台MissingServletRequestParameterException异常:
org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'pkgName' is not present
require=false,可以不用传递该参数;
@RequestMapping(value = "/testParams", method = RequestMethod.POST)
public BaseResponse<String> testParams(HttpServletRequest request, @RequestParam(name = "pkgName", required = false) String packageName) {
log.warn("[request.getParameterMap={} request.getParameter(\"pkgName\")={} packageName={}]",
JSON.toJSONString(request.getParameterMap()),
request.getParameter("pkgName"),
packageName);
return BaseResponse.success("ok");
}
(3)defaultValue属性
如果设置了该值,属性required=true将失效,URL未传该参数时,会使用默认值;
@RequestMapping(value = "/testParams", method = RequestMethod.POST)
public BaseResponse<String> testParams(HttpServletRequest request,
@RequestParam(name = "pkgName", defaultValue = "defaultPkgName") String packageName) {
log.warn("[request.getParameterMap={} request.getParameter(\"pkgName\")={} packageName={}]",
JSON.toJSONString(request.getParameterMap()),
request.getParameter("pkgName"),
packageName);
return BaseResponse.success("ok");
}
控制台输出:
[request.getParameterMap={} request.getParameter("pkgName")=null packageName=defaultPkgName]
类型转换,这里defaultValue为String类型,参数类型为Integer,将defaultValue置位100,可以看到简单类型可以自动转换:
@RequestMapping(value = "/testParams1", method = RequestMethod.POST)
public BaseResponse<String> testParams1(HttpServletRequest request,
@RequestParam(name = "appId", defaultValue = "100") Integer id) {
log.warn("[request.getParameterMap={} request.getParameter(\"appId\")={} id={}]",
JSON.toJSONString(request.getParameterMap()),
request.getParameter("appId"),
id);
return BaseResponse.success("ok");
}
[request.getParameterMap={} request.getParameter("appId")=null id=100]
如果Controller参数类型为Integer而默认值不是数值类型对应的字符串,请求时会报错方法参数错误:
@RequestMapping(value = "/testParams2", method = RequestMethod.POST)
public BaseResponse<String> testParams2(HttpServletRequest request,
@RequestParam(name = "appId", defaultValue = "defaultAppId") Integer id) {
log.warn("[request.getParameterMap={} request.getParameter(\"appId\")={} id={}]",
JSON.toJSONString(request.getParameterMap()),
request.getParameter("appId"),
id);
return BaseResponse.success("ok");
}
MethodArgumentTypeMismatchException, bad param type: bad params type: id required type java.lang.Integer
4. 也可以不使用@RequestParam注解——注解加与不加的区别
不使用@RequestParam注解,URL参数依然可以接收到;
// 不加注解接收参数
@RequestMapping("/test1")
public String test1(int userId) {
return "list";
}
// 加注解接收参数
@RequestMapping("/test2")
public String test2(@RequestParam int userId) {
return "list";
}
表现为:
(1)不加@RequestParam时,请求的参数名需要和Controller的方法参数名保持一致才能生效;使用@RequestParam时,可以通过@RequestParam(“userId”)或者@RequestParam(value = “userId”)指定传入的参数名;
(2)不加@RequestParam时,参数为非必传,加@RequestParam而不指定注解属性require=false时,参数为必传;并且可以通过@RequestParam(defaultValue = “0”)指定参数默认值;
5. 注解@RequestParam与HttpServletRequest#getParameter方法的区别
request.getParameter("name")和@RequestParam String name的获取方式是不同的,对比如下:
HttpServletRequest#getParameter
(1) request.getParameter(String name):获取name对应的value,如果有多个,返回第一个;
(2) request.getParameterNames():获取request里所有的name,返回Enumeration类型;
(3) request.getParameterValues(String name):获取name对应的所有value;
其实这三种方式都是从一个全局变量Map<String, String[]> 中获取的值,由此可见:key是String类型,也就是name,而value是String数组类型,请求时是可以提供多个相同的key,value值进行请求,下面是个示例;
请求参数相同参数名,传入两个不同的值:
控制台结果:
[request.getParameterMap={"pkgName":["AAA","BBB"]} request.getParameter("pkgName")=AAA packageName=AAA,BBB]
可见:
- Map中是全部的参数K/V,V为数组类型,当相同参数传递多个值时,加入数组;
- request.getParameter会取数组中的第一个值,这里就是AAA;
- Controller方法参数packageName接收到的是数组中的多个值拼接后的结果,这里就是=AAA,BBB;
从上面的结果来看,至少可以知道,@RequestParam与request.getParameter的逻辑是不一样的,来断点看一下:
答案找到了,在这里完成字符串的拼接;
从源码来看,@RequestParam与request.getParameter的逻辑是不一样的,实际调用的是getParameterValues方法,该方法返回的是String数组,并且源码中做了判断,在数组不为null的情况下,如果数组长度为1返回第一个元素,如果否则(大于1)返回当前数组,并通过Spring包的StringUtils将数组转成字符串,用逗号拼接;
结论:request.getParameter和@RequestParam本质上是不同的,所以在不确定是否有多个value的情况下,@RequestParam是不能代替request.getParameter来使用的!
规范的使用@RequestParam写法应该是@RequestParam String[] packageNames,如下:
而request.getParameter获取的确确实实是第一个value,可能我们研发过程中很少遇到多个相同key提交请求这种情况,但是这种情况是真实存在的,如果不了解这段代码,还是把@RequestParam当作获取第一个参数使用,早晚会出问题!
参考:
边栏推荐
- 利用NVIDIA GPU将Minecraft场景渲染成真实场景
- 介绍两款代码自动生成器,帮助提升工作效率
- 深入学习JVM底层(三):垃圾回收器与内存分配策略
- LeetCode 78. 子集
- 链表(线性结构)
- Spark overview
- Generic classes and parameterized classes of SystemVerilog
- 浏览器原理思维导图
- Don't use the new WP collection. Don't use WordPress collection without update
- Community theory | kotlin flow's principle and design philosophy
猜你喜欢
Data playback partner rviz+plotjuggler
CUDA中的Warp Shuffle
队列(线性结构)
Contest3147 - game 38 of 2021 Freshmen's personal training match_ G: Flower bed
LeetCode 90. Subset II
Decryption skills of encrypted compressed files
Replace Django database with MySQL (attributeerror: 'STR' object has no attribute 'decode')
Deep learning classification network -- Network in network
Detailed steps of JS foreground parsing of complex JSON data "case: I"
Summary of WLAN related knowledge points
随机推荐
Cglib代理-代码增强测试
深入了解JUC并发(二)并发理论
10 erreurs classiques de MySQL
Contest3147 - game 38 of 2021 Freshmen's personal training match_ A: chicken
State machine in BGP
官方零基础入门 Jetpack Compose 的中文课程来啦!
Replace Django database with MySQL (attributeerror: 'STR' object has no attribute 'decode')
TensorRT的命令行程序
穀歌出海創業加速器報名倒計時 3 天,創業人闖關指南提前收藏!
Google Play Academy 组队 PK 赛,正式开赛!
Compte à rebours de 3 jours pour l'inscription à l'accélérateur de démarrage Google Sea, Guide de démarrage collecté à l'avance!
Top 10 classic MySQL errors
LeetCode 77. combination
Introduce two automatic code generators to help improve work efficiency
It is said that Kwai will pay for the Tiktok super fast version of the video? How can you miss this opportunity to collect wool?
Community theory | kotlin flow's principle and design philosophy
Step by step | help you easily submit Google play data security form
深入学习JVM底层(二):HotSpot虚拟机对象
递归(迷宫问题、8皇后问题)
Arduino Wire 库使用