一、背景
平常經常用 @RequestParam注解來獲取參數,然后想到我能不能寫個自己注解獲取請求的ip地址呢?就像這樣 @IP String ip
二、分析
於是開始分析 @RequestParam是如何實現的。
從@RequestParam注解開始入手,搜索該注解在源碼中使用的地方
分別是類RequestParamMethodArgumentResolver和RequestParamMapMethodArgumentResolver
類關系圖
RequestParamMethodArgumentResolver
可以看到兩個類都最終實現了HandlerMethodArgumentResolver這個接口。
HandlerMethodArgumentResolver結構
里面就兩個方法,supportsParameter方法是檢測該參數是否支持這個參數解析器,
如果supportsParameter方法返回true,則調用resolveArgument來進行參數解析工作。
三、代碼編寫
現在就可以寫自己的參數解析器了,但是推薦繼承AbstractNamedValueMethodArgumentResolver而不是直接實現HandlerMethodArgumentResolver接口。
1.注解@IP
- /**
- * 獲取參數
- * Created by 2YSP on 2019/1/6.
- */
- (value = RetentionPolicy.RUNTIME)
- (ElementType.PARAMETER)
- public IP {
- String name() default "ip";
- boolean required() default true;
- String defaultValue() default "0";
- }
2.參數解析器IPAddressArgumentResolver
- /**
- * Created by 2YSP on 2019/1/6.
- */
- public class IPAddressArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
- protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
- IP annotation = parameter.getParameterAnnotation(IP.class);
- return new IPAddressArgumentResolver.RequestIPNamedValueInfo(annotation);
- }
- protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
- HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
- String ip = servletRequest.getRemoteAddr();
- return ip == null ? "127.0.0.1":ip;
- }
- public boolean supportsParameter(MethodParameter parameter) {
- return parameter.hasParameterAnnotation(IP.class) && !Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType());
- }
- private static class RequestIPNamedValueInfo extends NamedValueInfo{
- private RequestIPNamedValueInfo(IP annotation) {
- super(annotation.name(), annotation.required(), annotation.defaultValue());
- }
- }
- }
這三個方法是必須實現的,還有一個可選重寫的handleMissingValue。
3.添加配置
- public class MvcConfig implements WebMvcConfigurer {
- public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
- resolvers.add(new IPAddressArgumentResolver());
- }
- }
4.controller
- 4j
- public class VOTestController {
- ("vo/test")
- public BaseVo test(@IP String ip){
- log.info("請求的ip地址為:{}",ip);
- BaseVo baseVo = new BaseVo();
- //設置為Null
- baseVo.setResult(null);
- 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實現原理感興趣的童鞋可以自己看看源碼。
