【第二十一讲】参数解析器
【第二十一讲】参数解析器
文章目录
- 【第二十一讲】参数解析器
- 1-常见参数解析器
- 2-组合模式在 Spring 中的体现
- 总结
- 常见参数解析器
- 组合模式在 Spring 中的体现
- ${} #{} 小技巧
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 调用过程为
- 控制器方法被封装为 HandlerMethod
- 准备对象绑定与类型转换
- 准备 ModelAndViewContainer 用来存储中间 Model 结果
- 解析每个参数值
解析参数依赖的就是各种参数解析器,它们都有两个重要方法
- supportsParameter 判断是否支持方法参数
- resolveArgument 解析方法参数
常见参数的解析
* @RequestParam
* 省略 @RequestParam
* @RequestParam(defaultValue)
* MultipartFile
* @PathVariable
* @RequestHeader
* @CookieValue
* @Value
* HttpServletRequest 等
* @ModelAttribute
* 省略 @ModelAttribute
* @RequestBody
@RequestParam, @CookieValue 等注解中的参数名、默认值, 都可以写成活的, 即从 ${ } #{ }中获取
【第二十一讲】参数解析器相关推荐
- spring MVC使用自定义的参数解析器解析参数
目录 写在前面 编写自定义的参数解析器解析请求参数 项目结构 定义注解 实体类 controller 定义参数解析器 注册参数解析器 启动项目 发起请求查看结果 写在前面 如果还有小伙伴不知道spri ...
- SpringMVC 参数解析器
一.问题 springMVC对于下面这种接口,参数是怎么解析的: @GetMapping("/hello/{id}") public void hello3(@PathVariab ...
- springMvc(实现HandlerMethodArgumentResolver)自定义参数解析器
由于之前用@RequestParam无法接收request payload 正文格式为json格式的字符串,只能使用@RequestBody整个接收,觉得麻烦,但是spring自带的参数解析器不具有这 ...
- Spring自定义参数解析器
虽然Spring提供了比较完善的参数解析器,但是对于一些特殊的数据类型我们还是需要进行特殊处理,这样会提高代码的复杂度,增加冗余的代码,降低代码可读性和可维护性.所以自定义参数解析器是一个很好的解 ...
- springmvc自定义参数解析器
由于开发中一般使用参数提交方式是json格式,对于单个参数的传递使用无法接收只能自定义参数解析器处理 springmvc的自定义参数解析器实现HandlerMethodArgumentResolver ...
- (十六)ATP应用测试平台——java应用中的过滤器Filter、拦截器Interceptor、参数解析器Resolver、Aop切面,你会了吗?
前言 过滤器Filter.拦截器Interceptor.参数解析器Resolver.Aop切面是我们应用开发中经常使用到的技术,到底该如何使用这些web附属功能, 本小节我们就分别介绍一下其各自的用法 ...
- SpringBoot--网上商城项目(自定义的参数解析器、购物车后台前台功能、商品详情页)
目录 一.自定义的参数解析器 关于Mybatis-plus时间字段代码生成问题 报错信息:Caused by: java.lang.IllegalStateException: No typehand ...
- 拦截器HandlerInterceptor+方法参数解析器HandlerMethodArgumentResolver用于统一获取当前登录用户信息
文章目录 前言 一.拦截器+方法参数解析器 是什么? 二.具体实现步骤 1.自定义权限拦截器LoginInterceptor拦截所有request请求,并将token解析为currentUser,最终 ...
- Spring MVC自定义类型转换器Converter、参数解析器HandlerMethodArgumentResolver
文章目录 一.前言 二.类型转换器Converter 1.自定义类型转换器 三.参数解析器 1.自定义分页参数解析器 2.自定义注解参数解析器 一.前言 Spring MVC源码分析相关文章已出: S ...
最新文章
- wayland与linux_将Linux与Wayland一起使用? 您需要知道的 | MOS86
- 鉴权必须了解的5个知识点:cookie,session,token,jwt,单点登录
- 第二章密码学基础与应用备考要点及真题分布
- ubuntu中文输入法fcitx的安装以及出现方块的解决方法
- OracleBulkCopy的批量数据导入
- Mangos源码分析(9):服务器公共组件实现之环形缓冲区
- json转换map多层嵌套问题
- 计算机考研408每日一题 day158
- LeetCode 34. 在排序数组中查找元素的第一个和最后一个位置 Find First and Last Position of Element in Sorted Array
- 计算机图形学必读的10本书
- iOS 15 真机调试包 DeviceSupport
- 企业邮箱登录入口有哪些?
- pyecharts图表库学习:Pie(饼图)
- Python语音信号特征-感知线性预测系数PLP
- jdbc.IncorrectResultSetColumnCountException: Incorrect column count: expected 1, actual 14
- codeforces#710
- python shell怎么调字体大小_Linux_Shell 设置字体 前景色 与 背景色 的几种方法
- 计算机视觉用显卡,基于GPU加速的计算机视觉编程:使用OpenCV和CUDA实时处理复杂图像数据...
- 解决TreeView的节点更改NodeFont后无法完全显示节点名的问题
- python文字识别前端_Python文字识别