一、背景

平常经常用 @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. HDU 1312 Red and Black 第一题搜索!

    Red and Black Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tot ...

  2. CSS属性中Display与Visibility的不同

    大多数人很容易将CSS属性display和visibility混淆,它们看似没有什么不同,其实它们的差别却是很大的.visibility属性用来确定元素是显示还是隐藏,这用visibility=&qu ...

  3. ViewPagerTransforms

    https://github.com/eltld/ViewPagerTransforms

  4. QEMU+GDB调试方法

    两年前调试usb/ip开源项目时,就曾用虚拟机远程调试过Windows和Linux系统内核,当时在VMware Workstation上创建两个虚拟机进行调试,也没有记录下如何配置调试,只是大体的还记 ...

  5. 【IOS工具类】IOS9的CoreSpotlight(OC语言)

    什么是CoreSpotlight?就是在IOS9下.让用户在下拉的搜索页面里能够搜索到你的应用. #import <Foundation/Foundation.h> @interface ...

  6. CSS3 (二)

    translate() 方法 通过 translate() 方法,元素从其当前位置移动,根据给定的 left(x 坐标) 和 top(y 坐标) 位置参数: 示例: div { transform: ...

  7. STM32的低功耗设置

    因为产品需求,系统功耗是一个很重要的考虑方面.好好看下STM32F103的低功耗问题,以便编写驱动. 1.STM32的电源 1.1 STM32电源框图 上面的电源中需要注意的是后备供电区域,这个部分由 ...

  8. js 原型继承和class继承

    摘自http://www.liaoxuefeng.com/ 在传统的基于Class的语言如Java.C++中,继承的本质是扩展一个已有的Class,并生成新的Subclass. 由于这类语言严格区分类 ...

  9. 如何查看一个Application是32位的还是64位的?

    使用process explorer查看,找到对应的进程. 注册表的路径是Computer\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\ 使用powershell查 ...

  10. Caused by: java.lang.IllegalArgumentException: Malformed \uxxxx encoding.

    application.properties中不能含有\符号.  只要遇到就会报这个错误. 解决方式:将application.properties中的 \ 改为 \\ 或者 /