Controller中的参数解析器【Spring源码学习】

mockRequest构建request请求

private static HttpServletRequest mockRequest(){
   MockHttpServletRequest request = new MockHttpServletRequest();
   request.setParameter("name1","zhangsan");
   request.setParameter("name2","lisi");
   request.setParameter("age","18");
   return new StandardServletMultipartResolver().resolveMultipart(request);
}

定义controller

static class Controller{
  public void test(
          @RequestParam("name1") String name1,
          String name2,
          @RequestParam("age") int age,
          @RequestParam(value = "home",defaultValue = "${JAVA_HOME}") String home1
  ){

  }
}

解析过程

public static void main(String[] args) throws Exception {
 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(WebConfig.class);
 ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();

 HttpServletRequest multiRequest = mockRequest();

 // 控制器方法封装为 handlerMethod
 HandlerMethod handlerMethod = new HandlerMethod(new Controller(),Controller.class.getMethod("test", String.class, String.class, int.class,String.class));

 // 数据绑定工厂
 DefaultDataBinderFactory factory = new DefaultDataBinderFactory(null);

 // ModelAndViewContainer 存储Model结果.
 ModelAndViewContainer container = new ModelAndViewContainer();

 // 拿到当前控制器方法得参数信息
 for (MethodParameter methodParameter : handlerMethod.getMethodParameters()) {
     // 创建解析器对象 -> 是在HandlerMethodAdapter中
     RequestParamMethodArgumentResolver resolver = new RequestParamMethodArgumentResolver(beanFactory,false);
     // 拿到当前的参数
     methodParameter.initParameterNameDiscovery(new DefaultParameterNameDiscoverer());
     // 当前解析器支持这个参数进行处理 如果标注了@RequestParam注解从请求参数里找到对应的信息
     if (resolver.supportsParameter(methodParameter)) {
         Object v = resolver.resolveArgument(methodParameter,container,new ServletWebRequest(multiRequest),factory);
         System.out.println("[" + methodParameter.getParameterIndex() + "]" + methodParameter.getParameterType().getSimpleName() + " " + methodParameter.getParameterName() + "->" + v);
     }else{
         System.out.println("[" + methodParameter.getParameterIndex() + "]" + methodParameter.getParameterType().getSimpleName() + " " + methodParameter.getParameterName());
     }
 }
}

通过handlerMethod.getMethodParameters拿到方法对应的全部的参数,然后对参数内容进行解析,
RequestParamMethodArgumentResolver用来解析@RequestParam注解;
首先通过supportsParameter看当前参数是否满足解析要求;
如果满足则进行参数解析赋值;resolver.resolveArgument

使用组合解析器进行优化

每个参数的解析需要用到不同的参数解析器,那么我们可以定义一个组合的参数解析器,进行解析时逐个去解析我们组合解析器中参数解析找到满足的一个然后进行解析。

// 创建解析器组合对象内部会循环找到当前参数满足的解析器进行解析
HandlerMethodArgumentResolverComposite composite = new HandlerMethodArgumentResolverComposite();
composite.addResolvers(
       new RequestParamMethodArgumentResolver(beanFactory,false), // 解析@RequestParam
       new PathVariableMethodArgumentResolver(), // 解析@PathVariable
       new RequestHeaderMethodArgumentResolver(beanFactory), // 解析 @RequestHeader
       new ServletCookieValueMethodArgumentResolver(beanFactory), // 解析@Cookie()
       new ExpressionValueMethodArgumentResolver(beanFactory) // 解析@Value
       new ServletModelAttributeMethodProcessor(false), // 必须有@ModelAttribute注解
       new RequestResponseBodyMethodProcessor(List.of(new MappingJackson2HttpMessageConverter())), // @RequestBody 解析json
       new ServletModelAttributeMethodProcessor(true) // 可以不加@ModelAttribute注解
       // 其中ModelAttribute注解作用主要是用来将请求中的数据映射为一个Java对象.
);

// 拿到当前的参数
methodParameter.initParameterNameDiscovery(new DefaultParameterNameDiscoverer());
// 当前解析器支持这个参数进行处理 如果标注了@RequestParam注解从请求参数里找到对应的信息
if (composite.supportsParameter(methodParameter)) {
   Object v = composite.resolveArgument(methodParameter,container,new ServletWebRequest(multiRequest),factory);
   System.out.println("[" + methodParameter.getParameterIndex() + "]" + methodParameter.getParameterType().getSimpleName() + " " + methodParameter.getParameterName() + "->" + v);
}else{
   System.out.println("[" + methodParameter.getParameterIndex() + "]" + methodParameter.getParameterType().getSimpleName() + " " + methodParameter.getParameterName());
}

request请求的设置

private static HttpServletRequest mockRequest(){
    MockHttpServletRequest request = new MockHttpServletRequest();
    request.setParameter("name1","zhangsan");
    request.setParameter("name2","lisi");
    Map<String,String> map = new AntPathMatcher().extractUriTemplateVariables("/test/{id}","/test/123");
    request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, map);
    request.setParameter("age","18");
    return new StandardServletMultipartResolver().resolveMultipart(request);
}

controller中的设置

static class Controller{
  public void test(
          @RequestParam("name1") String name1,
          String name2,
          @RequestParam("age") int age,
          @RequestParam(value = "home",defaultValue = "${JAVA_HOME}") String home1,
          @PathVariable("id") int id,
          @RequestHeader("Content-Type") String header,
          @CookieValue("token") String token,
          @Value("${JAVA_HOME}") String home2,
          @ModelAttribute User user // name=zhangsan&age=18
          @RequestBody User user3 // json
  ){

  }
}

controller中执行器方法参数名的获取

  1. javac编译java文件之后生成的.class文件中,方法得参数名会被替换为var 1 var 2
    例如·
public void foo(String name,int age){
	
}

编制之后

public void foo(String var1,int var2){
	
}

编译时使用javac -parameters .\Bean2.java 加了这个之后编制之后的methodParameters会被保存起来;
对于这种方式可以通过反射来获取参数名

  1. javac -g .\Bean2.java 使用这个命令编译。
    会多出一个localVariableTable记录
    对于这种情况需要ASM获取。
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值