有些时候我们需要在后台处理一些常用的通用参数,
如:获取客户端ip,又比如 用户登录完成后,后台返回前天一个登陆成功后的token,每次调用接口都在header或者url中带上token,后台根据这个token去校验用户(登录、权限等等)
这个时候,在后台添加一个注解,并对该注解通过参数解析器进行处理,可以很好的解决上上述问题。
扩展:为什么不用过滤器、拦截器或者切面来实现?
——过滤器一般用于过滤web请求,是用来处理servlet的,一般用来处理web页面相关的设置
——拦截器用于拦截action,即后台action方法,拦截器会拦截所有的action,而上述问题可能涉及到只有部分接口需要解析某个参数
——切面,切面通过设置pointcut切入点,切入方法,理论上可以解决上述问题,但有点大材小用
参考:
https://www.cnblogs.com/2YSP/p/10253927.html
https://www.jianshu.com/p/5790ea68f522
https://www.jianshu.com/p/838cd9956a14
https://www.jianshu.com/p/f4653fe8c935
以增加ip解析器为例
实现:
创建IP地址获取工具类IpUtil.java
package com.flysand.demo.util; import org.apache.commons.lang3.StringUtils; import javax.servlet.http.HttpServletRequest; import java.net.InetAddress; import java.net.UnknownHostException; /** * @author flysand **/ public class IpUtil { private static final String LOCALHOST = "127.0.0.1"; private static final String INTERNAL_HOST = "0:0:0:0:0:0:0:1"; private static final String UNKNOWN = "unknown"; public static String getIp(HttpServletRequest request) { String ipAddress; try { ipAddress = request.getHeader("x-forwarded-for"); if (ipAddress == null || ipAddress.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("WL-Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddress)) { ipAddress = request.getRemoteAddr(); if (ipAddress.equals(LOCALHOST) || ipAddress.equals(INTERNAL_HOST)) { // 根据网卡取本机配置的IP InetAddress inetAddress = null; try { inetAddress = InetAddress.getLocalHost(); } catch (UnknownHostException e) { e.printStackTrace(); } ipAddress = inetAddress != null ? inetAddress.getHostAddress() : null; } } // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 if (StringUtils.isNotBlank(ipAddress) ) { ipAddress = ipAddress.split(",")[0]; } } catch (Exception e) { ipAddress = ""; } return ipAddress; } }
增加ip注解Ip.java
package com.flysand.demo.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @author flysand **/ @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface Ip { }
增加ip解析器——新增的参数解析器需要加入到spring容器中
IpAddressArgumentResolver.java ,需实现HandlerMethodArgumentResolver接口,并重写方法
package com.flysand.demo.resolver; import com.flysand.demo.annotation.Ip; import com.flysand.demo.util.IpUtil; import org.springframework.core.MethodParameter; import org.springframework.lang.Nullable; import org.springframework.stereotype.Component; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; import javax.servlet.http.HttpServletRequest; /** * 自定义ip地址参数解析器 * * @author flysand on 2019/07/12 **/ @Component public class IpAddressArgumentResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(Ip.class); } /** * 返回ip * @param parameter * @param mavContainer * @param webRequest * @param binderFactory * @return * @throws Exception */ @Override public String resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest(); return IpUtil.getIp(request); } }
自定义springmvc配置,加入ip参数解析器
package com.flysand.demo.config; import com.flysand.demo.resolver.IpAddressArgumentResolver; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.data.web.PageableHandlerMethodArgumentResolver; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.List; /** * @author flysand **/ @Configuration @EnableWebMvc public class MyMvcConfig implements WebMvcConfigurer { @Autowired private IpAddressArgumentResolver ipAddressArgumentResolver; @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { resolvers.add(new PageableHandlerMethodArgumentResolver());
// 加入ip解析器 resolvers.add(ipAddressArgumentResolver); } }
使用 - Controller代码片段
@GetMapping("/getIp") public String getIp(@Ip String ip) { return ip; }
执行过程:
启动springboot,spring容器加载新增的ip解析器,页面访问getIp接口,根据@ip注解,找到对应的ip解析器,返回ip