一、背景

平常经常用 @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. iOS应用崩溃日志分析 iOS应用崩溃日志揭秘

    转自:http://www.raywenderlich.com/zh-hans/30818/ios%E5%BA%94%E7%94%A8%E5%B4%A9%E6%BA%83%E6%97%A5%E5%BF ...

  2. 不是技术牛人,如何拿到国内IT巨头的Offer--转

    http://blog.csdn.net/lsldd/article/details/13506263 不久前,byvoid面阿里星计划的面试结果截图泄漏,引起无数IT屌丝的羡慕敬仰.看看这些牛人,N ...

  3. 中科燕园GIS外包---交通运输综合地理信息平台

      集地图.服务.应用于一身交通运输综合性的GIS门户   交通运输综合地理信息平台,是集地图.服务.应用于一身交通运输综合性的GIS门户.无需复杂的设置和部署,就可以高速创建交互式地图和应用程序,并 ...

  4. 使用JavaScript获取浏览器Chrome版本信息

    Navigator对象包含了有关浏览器的信息 可通过访问其属性appVersion或userAgent来获取浏览器Chrome版本 例如,我所使用的QQ浏览器的appVersion和userAgent ...

  5. Java中的final具体解释以及用途实战

    浅析Java中的finalkeyword 谈到finalkeyword,想必非常多人都不陌生.在使用匿名内部类的时候可能会经经常使用到finalkeyword. 另外.Java中的String类就是一 ...

  6. Model drivern

    <s:hidden name="id" value="%{role.id}"></s:hidden> 其中的value传到后台是有类型的 ...

  7. golang基础-WaitGroup、kafka消费者

    kafka消费者 以下博客是通过生产者创建.发送消息至kafka 博客链接 现在我们站在消费者的角度,来进行收取消息 package main import ( "fmt" &qu ...

  8. js中数组遍历的几种方法及其区别

    参考网站: http://www.cnblogs.com/lvmh/p/6104397.html 第一种最常用的:for循环 for(j = 0; j < arr.length; j++) { ...

  9. java 开发面试题小整理(二)

    51.Anonymous Inner Class(匿名内部类)是否可以继承其它类?是否可以实现接口? 答:可以继承其他类或实现其他接口,在Swing编程和Android开发中常用此方式来实现事件监听和 ...

  10. 书写优雅的shell脚本(四) - kill命令的合理使用

    Linux中的kill命令用来终止指定的进程(terminate a process)的运行,是Linux下进程管理的常用命令.通常,终止一个前台进程可以使用Ctrl+C键,但是,对于一个后台进程就须 ...