【探索Spring底层】14.谈谈参数解析器-创新互联

文章目录
  • 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)));
    Mapmap = 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


你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


新闻标题:【探索Spring底层】14.谈谈参数解析器-创新互联
文章源于:http://myzitong.com/article/ddejdj.html