【第二十一讲】参数解析器

文章目录

  • 【第二十一讲】参数解析器
    • 1-常见参数解析器
    • 2-组合模式在 Spring 中的体现
    • 总结
  1. 常见参数解析器
  2. 组合模式在 Spring 中的体现
  3. ${} #{} 小技巧

1-常见参数解析器

构建参数类型

static class Controller {public void test(@RequestParam("name1") String name1, // name1=张三String name2,                        // name2=李四@RequestParam("age") int age,        // age=18@RequestParam(name = "home", defaultValue = "${JAVA_HOME}") String home1, // spring 获取数据@RequestParam("file") MultipartFile file, // 上传文件@PathVariable("id") int id,               //  /test/124   /test/{id}@RequestHeader("Content-Type") String header,@CookieValue("token") String token,@Value("${JAVA_HOME}") String home2, // spring 获取数据  ${} #{}HttpServletRequest request,          // request, response, session ...@ModelAttribute("abc") User user1,          // name=zhang&age=18User user2,                          // name=zhang&age=18@RequestBody User user3              // json) {}
}

属性

static class User {private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}
}

模拟输入

private static HttpServletRequest mockRequest() {MockHttpServletRequest request = new MockHttpServletRequest();request.setParameter("name1", "zhangsan");request.setParameter("name2", "lisi");request.addPart(new MockPart("file", "abc", "hello".getBytes(StandardCharsets.UTF_8)));Map<String, String> map = new AntPathMatcher().extractUriTemplateVariables("/test/{id}", "/test/123");System.out.println(map);request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, map);request.setContentType("application/json");request.setCookies(new Cookie("token", "123456"));request.setParameter("name", "张三");request.setParameter("age", "18");String json ="{\n" +"\"name\": \"john\",\n" +"\"age\": 42\n" +"}" ;request.setContent( json.getBytes(StandardCharsets.UTF_8));return new StandardServletMultipartResolver().resolveMultipart(request);}

测试

public static void main(String[] args) throws Exception {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(WebConfig.class);DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();// 准备测试 RequestHttpServletRequest request = mockRequest();// 要点1. 控制器方法被封装为 HandlerMethodHandlerMethod handlerMethod = new HandlerMethod(new Controller(), Controller.class.getMethod("test", String.class, String.class, int.class, String.class, MultipartFile.class, int.class, String.class, String.class, String.class, HttpServletRequest.class, User.class, User.class, User.class));// 要点2. 准备对象绑定与类型转换DefaultDataBinderFactory factory = new DefaultDataBinderFactory(null);// 要点3. 准备 ModelAndViewContainer 用来存储中间 Model 结果ModelAndViewContainer container = new ModelAndViewContainer();// 要点4. 解析每个参数值for (MethodParameter parameter : handlerMethod.getMethodParameters()) {RequestParamMethodArgumentResolver resolver = new RequestParamMethodArgumentResolver(beanFactory, false);String annotations = Arrays.stream(parameter.getParameterAnnotations()).map(a -> a.annotationType().getSimpleName()).collect(Collectors.joining());String str = annotations.length() > 0 ? " @" + annotations + " " : " ";parameter.initParameterNameDiscovery(new DefaultParameterNameDiscoverer());if(resolver.supportsParameter(parameter)){// 支持此参数Object v = resolver.resolveArgument(parameter, container, new ServletWebRequest(request), factory);System.out.println(v.getClass());System.out.println("[" + parameter.getParameterIndex() + "] " + str + parameter.getParameterType().getSimpleName() + " " + parameter.getParameterName() + "->" + v);}else {System.out.println("[" + parameter.getParameterIndex() + "] " + str + parameter.getParameterType().getSimpleName() + " " + parameter.getParameterName());}}
}
  • RequestParamMethodArgumentResolver设置为true时可以解析,默认不带注解的

  • String name2,
    

  • 用来参数转换,第三个参数中要求的时 int 类型,但实际输入的是String 类型,设置下面代码后会自动转换

  • // 要点2. 准备对象绑定与类型转换
    DefaultDataBinderFactory factory = new DefaultDataBinderFactory(null);
    

2-组合模式在 Spring 中的体现

public static void main(String[] args) throws Exception {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(WebConfig.class);DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();// 准备测试 RequestHttpServletRequest request = mockRequest();// 要点1. 控制器方法被封装为 HandlerMethodHandlerMethod handlerMethod = new HandlerMethod(new Controller(), Controller.class.getMethod("test", String.class, String.class, int.class, String.class, MultipartFile.class, int.class, String.class, String.class, String.class, HttpServletRequest.class, User.class, User.class, User.class));// 要点2. 准备对象绑定与类型转换ServletRequestDataBinderFactory factory = new ServletRequestDataBinderFactory(null,null);// 要点3. 准备 ModelAndViewContainer 用来存储中间 Model 结果ModelAndViewContainer container = new ModelAndViewContainer();// 要点4. 解析每个参数值for (MethodParameter parameter : handlerMethod.getMethodParameters()) {// 多个解析器组合HandlerMethodArgumentResolverComposite composite = new HandlerMethodArgumentResolverComposite();composite.addResolvers(// false 表示必须有 @RequestParamnew RequestParamMethodArgumentResolver(beanFactory, false),new PathVariableMethodArgumentResolver(),// 请求头解析器new RequestHeaderMethodArgumentResolver(beanFactory),// 解析Cookie 的值new ServletCookieValueMethodArgumentResolver(beanFactory),// ${} #{}new ExpressionValueMethodArgumentResolver(beanFactory),new ServletRequestMethodArgumentResolver(),new ServletModelAttributeMethodProcessor(false), // 必须有 @ModelAttributenew RequestResponseBodyMethodProcessor(Arrays.asList(new MappingJackson2HttpMessageConverter())),new ServletModelAttributeMethodProcessor(true), // 省略了 @ModelAttributenew RequestParamMethodArgumentResolver(beanFactory, true) // 省略 @RequestParam);String annotations = Arrays.stream(parameter.getParameterAnnotations()).map(a -> a.annotationType().getSimpleName()).collect(Collectors.joining());String str = annotations.length() > 0 ? " @" + annotations + " " : " ";parameter.initParameterNameDiscovery(new DefaultParameterNameDiscoverer());if(composite.supportsParameter(parameter)){// 支持此参数Object v = composite.resolveArgument(parameter, container, new ServletWebRequest(request), factory);//System.out.println(v.getClass());System.out.println("[" + parameter.getParameterIndex() + "] " + str + parameter.getParameterType().getSimpleName() + " " + parameter.getParameterName() + "->" + v);log.info("模型数据为:" + container.getModel());}else {System.out.println("[" + parameter.getParameterIndex() + "] " + str + parameter.getParameterType().getSimpleName() + " " + parameter.getParameterName());}}
}

总结

RequestMappingHandlerAdapter 调用过程为

  1. 控制器方法被封装为 HandlerMethod
  2. 准备对象绑定与类型转换
  3. 准备 ModelAndViewContainer 用来存储中间 Model 结果
  4. 解析每个参数值

解析参数依赖的就是各种参数解析器,它们都有两个重要方法

  • supportsParameter 判断是否支持方法参数
  • resolveArgument 解析方法参数

常见参数的解析

* @RequestParam
* 省略 @RequestParam
* @RequestParam(defaultValue)
* MultipartFile
* @PathVariable
* @RequestHeader
* @CookieValue
* @Value
* HttpServletRequest 等
* @ModelAttribute
* 省略 @ModelAttribute
* @RequestBody

@RequestParam, @CookieValue 等注解中的参数名、默认值, 都可以写成活的, 即从 ${ } #{ }中获取

【第二十一讲】参数解析器相关推荐

  1. spring MVC使用自定义的参数解析器解析参数

    目录 写在前面 编写自定义的参数解析器解析请求参数 项目结构 定义注解 实体类 controller 定义参数解析器 注册参数解析器 启动项目 发起请求查看结果 写在前面 如果还有小伙伴不知道spri ...

  2. SpringMVC 参数解析器

    一.问题 springMVC对于下面这种接口,参数是怎么解析的: @GetMapping("/hello/{id}") public void hello3(@PathVariab ...

  3. springMvc(实现HandlerMethodArgumentResolver)自定义参数解析器

    由于之前用@RequestParam无法接收request payload 正文格式为json格式的字符串,只能使用@RequestBody整个接收,觉得麻烦,但是spring自带的参数解析器不具有这 ...

  4. Spring自定义参数解析器

      虽然Spring提供了比较完善的参数解析器,但是对于一些特殊的数据类型我们还是需要进行特殊处理,这样会提高代码的复杂度,增加冗余的代码,降低代码可读性和可维护性.所以自定义参数解析器是一个很好的解 ...

  5. springmvc自定义参数解析器

    由于开发中一般使用参数提交方式是json格式,对于单个参数的传递使用无法接收只能自定义参数解析器处理 springmvc的自定义参数解析器实现HandlerMethodArgumentResolver ...

  6. (十六)ATP应用测试平台——java应用中的过滤器Filter、拦截器Interceptor、参数解析器Resolver、Aop切面,你会了吗?

    前言 过滤器Filter.拦截器Interceptor.参数解析器Resolver.Aop切面是我们应用开发中经常使用到的技术,到底该如何使用这些web附属功能, 本小节我们就分别介绍一下其各自的用法 ...

  7. SpringBoot--网上商城项目(自定义的参数解析器、购物车后台前台功能、商品详情页)

    目录 一.自定义的参数解析器 关于Mybatis-plus时间字段代码生成问题 报错信息:Caused by: java.lang.IllegalStateException: No typehand ...

  8. 拦截器HandlerInterceptor+方法参数解析器HandlerMethodArgumentResolver用于统一获取当前登录用户信息

    文章目录 前言 一.拦截器+方法参数解析器 是什么? 二.具体实现步骤 1.自定义权限拦截器LoginInterceptor拦截所有request请求,并将token解析为currentUser,最终 ...

  9. Spring MVC自定义类型转换器Converter、参数解析器HandlerMethodArgumentResolver

    文章目录 一.前言 二.类型转换器Converter 1.自定义类型转换器 三.参数解析器 1.自定义分页参数解析器 2.自定义注解参数解析器 一.前言 Spring MVC源码分析相关文章已出: S ...

最新文章

  1. wayland与linux_将Linux与Wayland一起使用? 您需要知道的 | MOS86
  2. 鉴权必须了解的5个知识点:cookie,session,token,jwt,单点登录
  3. 第二章密码学基础与应用备考要点及真题分布
  4. ubuntu中文输入法fcitx的安装以及出现方块的解决方法
  5. OracleBulkCopy的批量数据导入
  6. Mangos源码分析(9):服务器公共组件实现之环形缓冲区
  7. json转换map多层嵌套问题
  8. 计算机考研408每日一题 day158
  9. LeetCode 34. 在排序数组中查找元素的第一个和最后一个位置 Find First and Last Position of Element in Sorted Array
  10. 计算机图形学必读的10本书
  11. iOS 15 真机调试包 DeviceSupport
  12. 企业邮箱登录入口有哪些?
  13. pyecharts图表库学习:Pie(饼图)
  14. Python语音信号特征-感知线性预测系数PLP
  15. jdbc.IncorrectResultSetColumnCountException: Incorrect column count: expected 1, actual 14
  16. codeforces#710
  17. python shell怎么调字体大小_Linux_Shell 设置字体 前景色 与 背景色 的几种方法
  18. 计算机视觉用显卡,基于GPU加速的计算机视觉编程:使用OpenCV和CUDA实时处理复杂图像数据...
  19. 解决TreeView的节点更改NodeFont后无法完全显示节点名的问题
  20. python文字识别前端_Python文字识别

热门文章

  1. mysql函数 游标_存储过程/游标/mysql 函数
  2. GoogleNet、AleXNet、VGGNet、ResNet等总结
  3. ORA-00392: log 4 of thread 2 is being cleared, operation not allowed
  4. 大一转专业计算机考什么,武汉大学 计算机 转专业 经验贴
  5. 达梦数据库角色详解——VTI、SOI
  6. 清华北大2018届毕业生去向统计
  7. 高德地图区域围栏绘制
  8. python学习-数组
  9. 汶川大地震已过十一年,我仍记忆犹新
  10. 【python】print函数的用法示例与讲解