当前位置:网站首页>代码技巧——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 presentrequire=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.Integer4. 也可以不使用@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当作获取第一个参数使用,早晚会出问题!
参考:
边栏推荐
- 队列(线性结构)
- 社区说|Kotlin Flow 的原理与设计哲学
- ROS create workspace
- TensorRT中的循环
- LeetCode 78. subset
- LeetCode 39. Combined sum
- AttributeError: ‘str‘ object has no attribute ‘decode‘
- 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?
- BGP中的状态机
- Format check JS
猜你喜欢

Data playback partner rviz+plotjuggler

Community theory | kotlin flow's principle and design philosophy

深入学习JVM底层(二):HotSpot虚拟机对象

Leverage Google cloud infrastructure and landing area to build enterprise level cloud native excellent operation capability

IPv6 experiment and summary

社区说|Kotlin Flow 的原理与设计哲学

The difference between session and cookies

Contest3147 - game 38 of 2021 Freshmen's personal training match_ 1: Maximum palindromes

加密压缩文件解密技巧

深入了解JUC并发(二)并发理论
随机推荐
Support new and old imperial CMS collection and warehousing tutorials
ROS create workspace
浏览器原理思维导图
From design delivery to development, easy and efficient!
Web components series (VIII) -- custom component style settings
AttributeError: ‘str‘ object has no attribute ‘decode‘
Arduino Wire 库使用
I/o multiplexing & event driven yyds dry inventory
Contest3147 - game 38 of 2021 Freshmen's personal training match_ F: Polyhedral dice
Golang--map扩容机制(含源码)
Sentinel规则持久化到Nacos
Invalid operation: Load into table ‘sources_orderdata‘ failed. Check ‘stl_load_errors‘ system table
Replace Django database with MySQL (attributeerror: 'STR' object has no attribute 'decode')
LeetCode 40. Combined sum II
锐捷EBGP 配置案例
IDEA公布全新默认UI,太清爽了(内含申请链接)
稀疏数组(非线性结构)
深入了解JUC并发(一)什么是JUC
链表(线性结构)
Hydration failed because the initial UI does not match what was rendered on the server.问题原因之一