节
春
度
欢

SpringBoot自定义参数解析器

一、背景

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

二、分析

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

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

类关系图
类关系图

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"; 
  15. } 

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.  
  11. @Nullable 
  12. @Override 
  13. protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception { 
  14. HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class); 
  15. String ip = servletRequest.getRemoteAddr(); 
  16. return ip == null ? "127.0.0.1":ip; 
  17. } 
  18.  
  19. @Override 
  20. public boolean supportsParameter(MethodParameter parameter) { 
  21. return parameter.hasParameterAnnotation(IP.class) && !Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType()); 
  22. } 
  23.  
  24. private static class RequestIPNamedValueInfo extends NamedValueInfo{ 
  25.  
  26. private RequestIPNamedValueInfo(IP annotation) { 
  27. super(annotation.name(), annotation.required(), annotation.defaultValue()); 
  28. } 
  29. } 
  30.  
  31. } 

这三个方法是必须实现的,还有一个可选重写的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()); 
  9. } 
  10. } 

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; 
  13. } 
  14. } 

四、测试总结

启动项目,游览器请求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  阅读(3137)  评论(4)    收藏  举报