当前位置:   article > 正文

代码技巧——Controller参数注解@RequestParam_baseresponse.returnsuccess

baseresponse.returnsuccess

本篇介绍下Controller参数注解@RequestParam的使用方法,使用时的注意事项,以及与HttpServletRequest#getParameter方法的区别;
 

1. 注解@RequestParam的作用

(1)是SpringMVC中接收普通参数的注解,注解打在Controller的方法参数上;

(2)可以将URL请求参数映射绑定到Controller的方法参数上,便于业务接收处理HTTP请求参数;

(3)通过注解的属性,可以对Controller参数做一些简单的"必传校验"和"默认值填充";

2. 注解@RequestParam参数说明

参考:org.springframework.web.bind.annotation.RequestParam

  1. @Target(ElementType.PARAMETER)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. public @interface RequestParam {
  5. /**
  6. * Alias for {@link #name}.
  7. */
  8. @AliasFor("name")
  9. String value() default "";
  10. /**
  11. * The name of the request parameter to bind to.
  12. * @since 4.2
  13. */
  14. @AliasFor("value")
  15. String name() default "";
  16. /**
  17. * Whether the parameter is required.
  18. * <p>Defaults to {@code true}, leading to an exception being thrown
  19. * if the parameter is missing in the request. Switch this to
  20. * {@code false} if you prefer a {@code null} value if the parameter is
  21. * not present in the request.
  22. * <p>Alternatively, provide a {@link #defaultValue}, which implicitly
  23. * sets this flag to {@code false}.
  24. */
  25. boolean required() default true;
  26. /**
  27. * The default value to use as a fallback when the request parameter is
  28. * not provided or has an empty value.
  29. * <p>Supplying a default value implicitly sets {@link #required} to
  30. * {@code false}.
  31. */
  32. String defaultValue() default ValueConstants.DEFAULT_NONE;
  33. }

解释:

  • value:name属性的别名,作用相同;
  • name:URL中的参数名,映射到当前注解对应的参数上;如果没有设置该属性,方法参数名则和接口参数名匹配;
  • required:默认值是"true",表示该请求路径中必须包含该参数,如果不包含就会报404错误码;
  • defaultValue:String类型,默认参数值,如果设置了该值,属性required=true将失效,自动为false;如果没有传该参数,就使用默认值;默认值也可以是SpEL表达式

3. 使用示例

(1)name属性

  1. @RequestMapping(value = "/testParams", method = RequestMethod.POST)
  2. public BaseResponse<String> testParams(HttpServletRequest request, @RequestParam(name = "pkgName") String packageName) {
  3. log.warn("[request.getParameterMap={} request.getParameter(\"packageName\")={} packageName={}]",
  4. JSON.toJSONString(request.getParameterMap()),
  5. request.getParameter("packageName"),
  6. packageName);
  7. return BaseResponse.success("ok");
  8. }

控制台输出:

[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,可以不用传递该参数;

  1. @RequestMapping(value = "/testParams", method = RequestMethod.POST)
  2. public BaseResponse<String> testParams(HttpServletRequest request, @RequestParam(name = "pkgName", required = false) String packageName) {
  3. log.warn("[request.getParameterMap={} request.getParameter(\"pkgName\")={} packageName={}]",
  4. JSON.toJSONString(request.getParameterMap()),
  5. request.getParameter("pkgName"),
  6. packageName);
  7. return BaseResponse.success("ok");
  8. }

(3)defaultValue属性

如果设置了该值,属性required=true将失效,URL未传该参数时,会使用默认值;

  1. @RequestMapping(value = "/testParams", method = RequestMethod.POST)
  2. public BaseResponse<String> testParams(HttpServletRequest request,
  3. @RequestParam(name = "pkgName", defaultValue = "defaultPkgName") String packageName) {
  4. log.warn("[request.getParameterMap={} request.getParameter(\"pkgName\")={} packageName={}]",
  5. JSON.toJSONString(request.getParameterMap()),
  6. request.getParameter("pkgName"),
  7. packageName);
  8. return BaseResponse.success("ok");
  9. }

控制台输出:

[request.getParameterMap={} request.getParameter("pkgName")=null packageName=defaultPkgName]

类型转换,这里defaultValue为String类型,参数类型为Integer,将defaultValue置位100,可以看到简单类型可以自动转换:

  1. @RequestMapping(value = "/testParams1", method = RequestMethod.POST)
  2. public BaseResponse<String> testParams1(HttpServletRequest request,
  3. @RequestParam(name = "appId", defaultValue = "100") Integer id) {
  4. log.warn("[request.getParameterMap={} request.getParameter(\"appId\")={} id={}]",
  5. JSON.toJSONString(request.getParameterMap()),
  6. request.getParameter("appId"),
  7. id);
  8. return BaseResponse.success("ok");
  9. }
[request.getParameterMap={} request.getParameter("appId")=null id=100]

如果Controller参数类型为Integer而默认值不是数值类型对应的字符串,请求时会报错方法参数错误:

  1. @RequestMapping(value = "/testParams2", method = RequestMethod.POST)
  2. public BaseResponse<String> testParams2(HttpServletRequest request,
  3. @RequestParam(name = "appId", defaultValue = "defaultAppId") Integer id) {
  4. log.warn("[request.getParameterMap={} request.getParameter(\"appId\")={} id={}]",
  5. JSON.toJSONString(request.getParameterMap()),
  6. request.getParameter("appId"),
  7. id);
  8. return BaseResponse.success("ok");
  9. }
MethodArgumentTypeMismatchException, bad param type: bad params type: id required type java.lang.Integer

4. 也可以不使用@RequestParam注解——注解加与不加的区别

不使用@RequestParam注解,URL参数依然可以接收到;

  1. // 不加注解接收参数
  2. @RequestMapping("/test1")
  3. public String test1(int userId) {
  4.   return "list";
  5. }
  6. // 加注解接收参数
  7. @RequestMapping("/test2")
  8. public String test2(@RequestParam int userId) {
  9.   return "list";
  10. }

表现为:

(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当作获取第一个参数使用,早晚会出问题!

参考:

@RequestParam详解

request.getParameter()和@RequestParam的区别

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号