【探索Spring底层】14.谈谈参数解析器

news2024/11/18 11:27:22

文章目录

  • 1. 参数解析器概述
  • 2. 常见参数的解析

1. 参数解析器概述

参数解析器是Spring-Web包提供的组件,并且SpringMVC中提供了很多参数解析器。

常见的参数解析器如下

  • org.springframework.web.method.annotation.RequestParamMethodArgumentResolver@abbc908
  • org.springframework.web.method.annotation.RequestParamMapMethodArgumentResolver@44afefd5
  • org.springframework.web.servlet.mvc.method.annotation.PathVariableMethodArgumentResolver@9a7a808
  • org.springframework.web.servlet.mvc.method.annotation.PathVariableMapMethodArgumentResolver@72209d93
  • org.springframework.web.servlet.mvc.method.annotation.MatrixVariableMethodArgumentResolver@2687f956
  • org.springframework.web.servlet.mvc.method.annotation.MatrixVariableMapMethodArgumentResolver@1ded7b14
  • org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor@29be7749
  • org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor@5f84abe8
  • org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver@4650a407
  • org.springframework.web.method.annotation.RequestHeaderMethodArgumentResolver@30135202
  • org.springframework.web.method.annotation.RequestHeaderMapMethodArgumentResolver@6a4d7f76
  • org.springframework.web.servlet.mvc.method.annotation.ServletCookieValueMethodArgumentResolver@10ec523c
  • org.springframework.web.method.annotation.ExpressionValueMethodArgumentResolver@53dfacba
  • org.springframework.web.servlet.mvc.method.annotation.SessionAttributeMethodArgumentResolver@79767781
  • org.springframework.web.servlet.mvc.method.annotation.RequestAttributeMethodArgumentResolver@78411116
  • org.springframework.web.servlet.mvc.method.annotation.ServletRequestMethodArgumentResolver@aced190
  • org.springframework.web.servlet.mvc.method.annotation.ServletResponseMethodArgumentResolver@245a060f
  • org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor@6edaa77a
  • org.springframework.web.servlet.mvc.method.annotation.RedirectAttributesMethodArgumentResolver@1e63d216
  • org.springframework.web.method.annotation.ModelMethodProcessor@62ddd21b
  • org.springframework.web.method.annotation.MapMethodProcessor@16c3ca31
  • org.springframework.web.method.annotation.ErrorsMethodArgumentResolve

2. 常见参数的解析

我们在开发中,常用的参数如下

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

那么这些参数Spring到底是怎么解析的呢?

下面就来模拟一下吧

首先准备controller

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=18
        User user2,                          // name=zhang&age=18
        @RequestBody User user3              // json
    ) {
    }
}

接着准备模拟请求

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");
    request.setContent("""
                       {
                           "name":"李四",
                           "age":20
                       }
                       """.getBytes(StandardCharsets.UTF_8));

                       return new StandardServletMultipartResolver().resolveMultipart(request);
                       }

首先准备一个容器

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(WebConfig.class);

接着准备Request

HttpServletRequest request = mockRequest();

接着将controller类的方法封装成HandlerMethod

HandlerMethod 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));

接着准备对象绑定与类型转换

ServletRequestDataBinderFactory factory = new ServletRequestDataBinderFactory(null, null);

准备 ModelAndViewContainer 用来存储中间 Model 结果

ModelAndViewContainer container = new ModelAndViewContainer();

最后解析每个参数值

遍历handlerMethod.getMethodParameters()MethodParameter

首先准备一个多解析器组合

HandlerMethodArgumentResolverComposite composite = new HandlerMethodArgumentResolverComposite();
composite.addResolvers(
    //                                          false 表示必须有 @RequestParam
    new RequestParamMethodArgumentResolver(beanFactory, false),
    new PathVariableMethodArgumentResolver(),
    new RequestHeaderMethodArgumentResolver(beanFactory),
    new ServletCookieValueMethodArgumentResolver(beanFactory),
    new ExpressionValueMethodArgumentResolver(beanFactory),
    new ServletRequestMethodArgumentResolver(),
    new ServletModelAttributeMethodProcessor(false), // 必须有 @ModelAttribute
    new RequestResponseBodyMethodProcessor(List.of(new MappingJackson2HttpMessageConverter())),
    new ServletModelAttributeMethodProcessor(true), // 省略了 @ModelAttribute
    new 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);
    System.out.println("模型数据为:" + container.getModel());
} else {
    System.out.println("[" + parameter.getParameterIndex() + "] " + str + parameter.getParameterType().getSimpleName() + " " + parameter.getParameterName());
}

全部代码

public static void main(String[] args) throws Exception {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(WebConfig.class);
    DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
    // 准备测试 Request
    HttpServletRequest request = mockRequest();

    // 要点1. 控制器方法被封装为 HandlerMethod
    HandlerMethod 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 表示必须有 @RequestParam
            new RequestParamMethodArgumentResolver(beanFactory, false),
            new PathVariableMethodArgumentResolver(),
            new RequestHeaderMethodArgumentResolver(beanFactory),
            new ServletCookieValueMethodArgumentResolver(beanFactory),
            new ExpressionValueMethodArgumentResolver(beanFactory),
            new ServletRequestMethodArgumentResolver(),
            new ServletModelAttributeMethodProcessor(false), // 必须有 @ModelAttribute
            new RequestResponseBodyMethodProcessor(List.of(new MappingJackson2HttpMessageConverter())),
            new ServletModelAttributeMethodProcessor(true), // 省略了 @ModelAttribute
            new 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);
            System.out.println("模型数据为:" + container.getModel());
        } else {
            System.out.println("[" + parameter.getParameterIndex() + "] " + str + parameter.getParameterType().getSimpleName() + " " + parameter.getParameterName());
        }
    }

}

image-20221223213830065


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/111252.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

部署并启动项目在linux(CentOS7)上,一名合格的程序猿不能不会(ಥ_ಥ)

各位小伙伴大家好呀哈哈哈~ 遇到问题不要慌─≡Σ(((つ•̀ω•́)つ让我先发个朋友圈~( • ̀ω•́ )✧ 我们知道项目的正常运行是需要先部署在服务器上&#xff0c;然后才能正常使用&#xff0c;我们一般都是在idea下写好然后直接部署在tomcat上或者其他服务器&#xff0c;但…

多维表需求管理表自动生成TAPD需求

【实现效果&#xff1a;】业务同学使用多维表管理客户需求&#xff0c;和产品团队经过评审之后&#xff0c;一键把多维表里对应的需求生成TAPD需求/缺陷单 【准备工作】 准备一个多维表&#xff0c;比如维格表、金山轻维表等 可以参考这两个模版&#xff1a; 金山轻维表&am…

【深入浅出Spring原理及实战】「开发实战系列」Aspectj和LoadTimeWeaving的动态代理技术实现指南

前提介绍 当我们聊到Spring框架的项目实际开发中&#xff0c;用的强大的功能之一就是&#xff08;面向切面编程&#xff09;的这门AOP技术。如果使用得当&#xff0c;它的最大的作用就是侵入性比较少并且简化我们的工作任务&#xff08;节省大量的重复性编码&#xff09;&…

【QT】PySide6 数据可视化折线图

一、项目介绍 本项目将通过PySide6构建一个可以显示数据折线图的可视化程序&#xff0c;其中&#xff0c;数据来源时美国地质调查局(US Geological Survey)上公开的一小时地震震级数据。 可以通过链接进行下载。 二、实现步骤 本项目的实现步骤可以概括为&#xff1a; 读取…

艾美捷过氧化氢酶检测试剂盒的功能和应用

过氧化氢酶&#xff08;EC 1.11.1.6&#xff1b;2H2O2氧化还原酶&#xff09;是一种普遍存在于大多数需氧细胞中的抗氧化酶。过氧化氢酶&#xff08;CAT&#xff09;参与过氧化氢&#xff08;H2O2&#xff09;的解毒&#xff0c;过氧化氢是一种活性氧&#xff08;ROS&#xff0…

领域首创!合合信息与上海大学联合开启贵州原生态古彝文典籍数字化项目

古彝文传承至今已有数千年历史&#xff0c;是世界上最古老的文字之一。2022年12月21日&#xff0c;合合信息与上海大学社会学院正式签署校企合作协议&#xff0c;双方将合力完成以国家珍贵古籍《西南彝志》为中心的贵州古彝文图像识别及数字化校对项目&#xff08;简称“古彝文…

搜索与图论---最短路

最短路:建图! 源点—起点汇点—终点约定n为点数,m为边数1单源最短路:求一个点到其他所有点的最短路 1.1所有边权都是正数 (1)朴素的Dijkstra算法(On^2) 例题:Dijkstra求最短路 I 代码: #include<iostream> #include<cstring> #

代码随想录算法训练营第42天 | 01背包问题 416. 分割等和子集

01背包问题 由于leetcode上没原题&#xff0c;故参考卡哥意见自己编题记录一下。 一、题干 背包最大重量为4。物品为&#xff1a; 物品名称重量价值011513202430––– 问背包能背的物品最大价值是多少&#xff1f; 二、解法 二维dp&#xff1a; 递推公式&#xff1a;dp[i…

数组方法中会更改原数组,不会更改原数组(详细)

1.不会改变原来数组的有&#xff1a; concat() 连接两个或更多的数组&#xff0c;并返回结果。 如果arr.concat&#xff08;&#xff09;里面不放数组参数&#xff0c;则会浅拷贝arr 如果参数不是数组&#xff0c;它不会递归到嵌套数组参数中 数据类型如字符串&#xff0c;数…

elasticsearch小白入门

一般再项目中都会用到 搜索&#xff0c;如果直接查询数据库&#xff0c;性能会存在瓶颈。 这时&#xff0c;用ES就很好的解决这个问题。 ES组件很多&#xff1a;包括 elasticsearch kibana beats logstash 安装 elasticsearch 下载&#xff1a; Elasticsearch 7.10.2 | El…

SpringBoot项目搭建+登录功能实现(小结)

项目目录 登录功能实现思路 目录 1.pom.xml添加依赖 2.配置application.yml文件 3.sql映射文件配置---UserMapper.xml 4.导入页面资源 5.Springboot启动类的配置 6.编写全局配置类 config->AppConfig 7.创建实体类--数据表对应 8.修改login.html页面 9.编写UserCo…

基于SpringBoot的SSMP整合案例

基于SpringBoot的SSMP整合案例 简介&#xff1a;SSMP(SpringSpringMVCMyBatis)&#xff0c;通过SpringBoot整合SSMP来完成增删改查案例。 功能开发模块 实体类开发————使用Lombok快速制作实体类Dao开发————整合MyBatisPlus&#xff0c;制作数据层测试Service开发——…

如意如意猿如意

如意如意猿如意什么是猿如意猿如意效率工具JSON编辑器jsontojava开发工具ChatGPT推荐指数评分及改进意见UI界面效率工具和开发工具ChatGPT一行代码总结经常听到一句话&#xff1a;如意如意随我心意&#xff0c;作为程序猿&#xff0c;我也想要一个如意&#xff0c;心中默念咒语…

LeetCode-91-解码方法

1、动态规划法 我们可以使用动态规划法来解决本问题。我们利用数组dp[i]dp[i]dp[i]来记录字符串前iii位能够组成的解码方法总数。在设计状态转移方程时&#xff0c;我们需要注意这样子的特殊情况&#xff1a;1、当s[i]s[i]s[i]不为0时&#xff0c;单独一个s[i]s[i]s[i]肯定能够…

PID算法总结-从公式原理到参数整定解析

目录 一、控制系统 1.1控制系统的分类 1.2 性能指标 二、PID算法的起源及特点 三、PID应用 四、PID公式原理 五、PID源码 六、PID整定方法 6.1 经验法 6.2 衰减曲线法 6.3 响应曲线法 参考文献&#xff1a; 一、控制系统 1.1控制系统的分类 分为开环控制、闭环控制和复…

Axios(二)

1.axios的基本使用 <!doctype html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, user-scalableno, initial-scale1.0, maximum-scale1.0, minimum-scale1.…

前端基础_像素的处理

像素的处理 在HTML5中使用canvas API所能够做到的图像处理技术中&#xff0c;还有一个更让人惊讶的技术就是像素处理技术。使用canvas API能够获取图像中的每一个像素&#xff0c;然后得到该像素颜色的rgb值或rgba值。 使用图形上下文对象的getImageData方法来获取图像中的像…

Docker安装Nginx 反向代理服务器

前端代码扔在服务器上怎么运行&#xff0c;首先安装Nginx&#xff0c;这里我用Docker安装Nginx 文章目录一、安装nginx docker镜像1、 获取nginx官方镜像2、查看镜像库3、宿主机创建好要挂载的目录4、启动一个不挂载的容器5、配置文件挂载到宿主机6、停止/删除容器7、查看宿主机…

Kaggle手写识别-卷积神经网络Top6%-代码详解

目录 1. Introduction 简介 2. Data preparation 数据准备 2.1 Load data 加载数据 2.2 Check for null and missing values 检查空值和缺失值 2.3 Normalization 规范化 2.4 Reshape 重塑 2.5 Label encoding 标签编码 2.6 Split training and valdiation set 拆分训…

阳康,但没恢复...

这几天真的是被新冠教育了… 我是上周五就开始有症状了&#xff0c;刚开始因为看了太多小感冒、没流感厉害、几天就康复的言论&#xff0c;我以为应该很快就能好&#xff0c;再加上全过程一直没发烧还暗自窃喜&#xff1a;这玩意不过如此嘛。 没想到病毒很快教我重新做人了&a…