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實現原理感興趣的童鞋可以自己看看源碼。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM