SpringBoot自定义参数解析器

一、背景

平常经常用 @RequestParam注解来获取参数,然后想到我能不能写个自己注解获取请求的ip地址呢?就像这样 @IP String ip

二、分析

于是开始分析 @RequestParam是如何实现的。

从@RequestParam注解开始入手,搜索该注解在源码中使用的地方
分别是类RequestParamMethodArgumentResolverRequestParamMapMethodArgumentResolver

类关系图
类关系图

RequestParamMethodArgumentResolver
RequestParamMethodArgumentResolver

可以看到两个类都最终实现了HandlerMethodArgumentResolver这个接口。

HandlerMethodArgumentResolver结构
HandlerMethodArgumentResolver结构

里面就两个方法,supportsParameter方法是检测该参数是否支持这个参数解析器,
如果supportsParameter方法返回true,则调用resolveArgument来进行参数解析工作。

三、代码编写

现在就可以写自己的参数解析器了,但是推荐继承AbstractNamedValueMethodArgumentResolver而不是直接实现HandlerMethodArgumentResolver接口。
1.注解@IP

  1. /** 
  2. * 获取参数 
  3. * Created by 2YSP on 2019/1/6. 
  4. */ 
  5. @Documented 
  6. @Retention(value = RetentionPolicy.RUNTIME) 
  7. @Target(ElementType.PARAMETER) 
  8. public @interface IP { 
  9.  
  10. String name() default "ip"
  11.  
  12. boolean required() default true
  13.  
  14. String defaultValue() default "0"

2.参数解析器IPAddressArgumentResolver

  1. /** 
  2. * Created by 2YSP on 2019/1/6. 
  3. */ 
  4. public class IPAddressArgumentResolver extends AbstractNamedValueMethodArgumentResolver
  5. @Override 
  6. protected NamedValueInfo createNamedValueInfo(MethodParameter parameter)
  7. IP annotation = parameter.getParameterAnnotation(IP.class); 
  8. return new IPAddressArgumentResolver.RequestIPNamedValueInfo(annotation); 
  9.  
  10. @Nullable 
  11. @Override 
  12. protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception
  13. HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class); 
  14. String ip = servletRequest.getRemoteAddr(); 
  15. return ip == null ? "127.0.0.1":ip; 
  16.  
  17. @Override 
  18. public boolean supportsParameter(MethodParameter parameter)
  19. return parameter.hasParameterAnnotation(IP.class) && !Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType()); 
  20.  
  21. private static class RequestIPNamedValueInfo extends NamedValueInfo
  22.  
  23. private RequestIPNamedValueInfo(IP annotation)
  24. super(annotation.name(), annotation.required(), annotation.defaultValue()); 
  25.  

这三个方法是必须实现的,还有一个可选重写的handleMissingValue。
3.添加配置

  1. @Configuration 
  2. @EnableWebMvc 
  3. public class MvcConfig implements WebMvcConfigurer
  4.  
  5.  
  6. @Override 
  7. public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers)
  8. resolvers.add(new IPAddressArgumentResolver()); 

4.controller

  1. @Slf4j 
  2. @RestController 
  3. public class VOTestController
  4.  
  5. @GetMapping("vo/test"
  6. public BaseVo test(@IP String ip)
  7.  
  8. log.info("请求的ip地址为:{}",ip); 
  9. BaseVo baseVo = new BaseVo(); 
  10. //设置为Null 
  11. baseVo.setResult(null); 
  12. return baseVo; 

四、测试总结

启动项目,游览器请求http://localhost/vo/test可以看到日志显示:

2019-01-11 10:30:24.284 [http-nio-80-exec-3] INFO  cn.sp.controller.VOTestController - 请求的ip地址为:0:0:0:0:0:0:0:1

代码已托管到我的github,点击访问,对@RequestParam实现原理感兴趣的童鞋可以自己看看源码。

posted @ 2019-01-11 10:41  烟味i  阅读(3032)  评论(4编辑  收藏  举报