一、背景

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

二、分析

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

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

分别是类RequestParamMethodArgumentResolver和RequestParamMapMethodArgumentResolver


类关系图

RequestParamMethodArgumentResolver

可以看到两个类都最终实现了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. String name() default "ip"; 


  10. boolean required() default true; 


  11. 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. @Nullable 

  10. @Override 

  11. protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception { 

  12. HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class); 

  13. String ip = servletRequest.getRemoteAddr(); 

  14. return ip == null ? "127.0.0.1":ip; 




  15. @Override 

  16. public boolean supportsParameter(MethodParameter parameter) { 

  17. return parameter.hasParameterAnnotation(IP.class) && !Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType()); 




  18. private static class RequestIPNamedValueInfo extends NamedValueInfo{ 


  19. private RequestIPNamedValueInfo(IP annotation) { 

  20. super(annotation.name(), annotation.required(), annotation.defaultValue()); 








这三个方法是必须实现的,还有一个可选重写的handleMissingValue。

3.添加配置

  1. @Configuration 

  2. @EnableWebMvc 

  3. public class MvcConfig implements WebMvcConfigurer { 



  4. @Override 

  5. public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { 

  6. resolvers.add(new IPAddressArgumentResolver()); 





4.controller

  1. @Slf4j 

  2. @RestController 

  3. public class VOTestController { 


  4. @GetMapping("vo/test") 

  5. public BaseVo test(@IP String ip){ 


  6. log.info("请求的ip地址为:{}",ip); 

  7. BaseVo baseVo = new BaseVo(); 

  8. //设置为Null 

  9. baseVo.setResult(null); 

  10. 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实现原理感兴趣的童鞋可以自己看看源码。

SpringBoot自定义参数解析器的更多相关文章

  1. SpringBoot系列教程web篇之如何自定义参数解析器

    title: 190831-SpringBoot系列教程web篇之如何自定义参数解析器 banner: /spring-blog/imgs/190831/logo.jpg tags: 请求参数 cat ...

  2. springmvc 源码分析(三) -- 自定义处理器映射器和自定义处理器适配器,以及自定义参数解析器 和错误跳转自定页面

    测试环境搭建: 本次搭建是基于springboot来实现的,代码在码云的链接:https://gitee.com/yangxioahui/thymeleaf.git DispatcherServlet ...

  3. SpringMVC 自定义参数解析器.

    一.简述 有没有想过像 @RequestParam.@RequestBody 这些注解的工作原理呢?为什么 form 表单.application/json 的参数能够直接封装进 Bean 对象中呢? ...

  4. Spring自定义参数解析器

    结合redis编写User自定义参数解析器UserArgumentResolver import javax.servlet.http.Cookie; import javax.servlet.htt ...

  5. SpringMVC自动封装List对象 —— 自定义参数解析器

    前台传递的参数为集合对象时,后台Controller希望用一个List集合接收数据. 原生SpringMVC是不支持,Controller参数定义为List类型时,接收参数会报如下错误: org.sp ...

  6. SpringBoot自定义参数验证器

    前要 之前我们介绍了JSR-303验证方式,十分的方便Spring都帮我们封装好了,但是对一些复杂的验证,还是需要更加灵活的验证器的. JSR-303验证器传送门:https://www.jiansh ...

  7. 自定义springmvc参数解析器

    实现spring HandlerMethodArgumentResolver接口 通过使用@JsonArg自定义注解来解析json数据(通过fastjson的jsonPath),支持多个参数(@Req ...

  8. 一步一步自定义SpringMVC参数解析器

    随心所欲,自定义参数解析器绑定数据. 题图:from Zoommy 干货 SpringMVC解析器用于解析request请求参数并绑定数据到Controller的入参上. 自定义一个参数解析器需要实现 ...

  9. 自定义HandlerMethodArgumentResolver参数解析器和源码分析

    在初学springmvc框架时,我就一直有一个疑问,为什么controller方法上竟然可以放这么多的参数,而且都能得到想要的对象,比如HttpServletRequest或HttpServletRe ...

随机推荐

  1. 浅谈JS中的!=、== 、!==、===的用法和区别 JS中Null与Undefined的区别 读取XML文件 获取路径的方式 C#中Cookie,Session,Application的用法与区别? c#反射 抽象工厂

    浅谈JS中的!=.== .!==.===的用法和区别   var num = 1;     var str = '1';     var test = 1;     test == num  //tr ...

  2. Android--向SD卡读写数据

    // 向SD卡写入数据 private void writeSDcard(String str) { try { // 推断是否存在SD卡 if (Environment.getExternalSto ...

  3. 【万里征程——Windows App开发】控件大集合1

    加入控件的方式有多种.大家更喜欢哪一种呢? 1)使用诸如 Blend for Visual Studio 或 Microsoft Visual Studio XAML 设计器的设计工具. 2)在 Vi ...

  4. 细说linux IPC(三):mmap系统调用共享内存

    [版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途]         前面讲到socket的进程间通 ...

  5. ajax的异步操作及页面重定向跳转

    今天主要分享一个简单的ajax的异步操作数据,用javascript也有一段时间了,刚开始看到一些页面在没有页面刷新的情况下就可以实现数据的保存或者获取,觉得挺不可思议的,感觉速度很快,做了几个项目之 ...

  6. 浅谈JavaScript的事件(事件委托)

    事件处理程序为Web程序提供了系统交互,但是如果页面中的事件处理程序太多,则会影响页面的性能.每个函数都是对象,都会占用内存,内存中对象越多,性能越差.需要事先为DOM对象指定事件处理程序,导致访问D ...

  7. Java,多个线程对同一个数据源的访问

    当多个线程对同一个数据源进行访问时,应对线程同步或加锁.为何?举个简单的例子:有一个共享的数据源dataSource,其值为0.有两个线程,Thread1和Thread2.Thread1的任务是将da ...

  8. js生成随机编码并赋值给input文本框

    效果图如下: 页面代码: <div class="form-item form-width-in fr"> <label>产 品 编 码</label ...

  9. linux初级学习笔记三:linux操作系统及常用命令,及如何复制和移动文件!(视频序号:02_4)

    本节学习的命令:cp,mv,install,du,read 本节学习的技能:文件的移动与复制 cp( copy):复制和移动文件 cp SRC DEST -r:递归复制一个目录及其目录中的所有文件 - ...

  10. 用于JS日期格式化,以及简单运算的Date包装工具类

    1. [文件] yDate.js/** * | yDate.js | Copyright (c) 2013 yao.yl | email: redrainyi@126.com | Date: 2012 ...