拦截器我想大家都并不陌生,最常用的登录拦截、或是权限校验、或是防重复提交、或是根据业务像12306去校验购票时间,总之可以去做很多的事情。
我仔细想了想
这里我分三篇博客来介绍HandlerInterceptor的使用,从基本的使用、到自定义注解、最后到读取body中的流解决无法多次读取的问题。
定义一个Interceptor 非常简单方式也有几种,我这里简单列举两种
1、类要实现Spring 的HandlerInterceptor 接口
2、类继承实现了HandlerInterceptor 接口的类,例如 已经提供的实现了HandlerInterceptor 接口的抽象类HandlerInterceptorAdapter
这里博主用的是第二种方法继承HandlerInterceptorAdapter
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; void postHandle( HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception; void afterCompletion( HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception;
接下来让我们来实现一个登陆 and 访问权限校验的拦截器吧
package com.xxx.core.filter; import com.xxx.common.exception.FastRuntimeException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class TestFilter extends HandlerInterceptorAdapter { private final Logger logger = LoggerFactory.getLogger(TestFilter.class); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { logger.info("request请求地址path[{}] uri[{}]", request.getServletPath(),request.getRequestURI()); //request.getHeader(String) 从请求头中获取数据 //从请求头中获取用户token(登陆凭证根据业务而定) Long userId= getUserId(request.getHeader("H-User-Token")); if (userId != null && checkAuth(userId,request.getRequestURI())){ return true; } //这里的异常是我自定义的异常,系统抛出异常后框架捕获异常然后转为统一的格式返回给前端, 其实这里也可以返回false throw new FastRuntimeException(20001,"No access"); } /** * 根据token获取用户ID * @param userToken * @return */ private Long getUserId(String userToken){ Long userId = null; return userId; } /** * 校验用户访问权限 * @param userId * @param requestURI * @return */ private boolean checkAuth(Long userId,String requestURI){ return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {} @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {} }
其实以前都是继承WebMvcConfigurerAdapter类 不过springBoot2.0以上 WebMvcConfigurerAdapter 方法过时,有两种替代方案:
1、继承WebMvcConfigurationSupport
2、实现WebMvcConfigurer
但是继承WebMvcConfigurationSupport会让Spring-boot对mvc的自动配置失效。根据项目情况选择。现在大多数项目是前后端分离,并没有对静态资源有自动配置的需求所以继承WebMvcConfigurationSupport也未尝不可。
@Configuration public class WebAppConfigurer implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { // 可添加多个 registry.addInterceptor(new TestFilter()).addPathPatterns("/**"); } .... }
其实下面还有很多方法我这里就省略了,过滤器可以添加多个,可以指定Path,这里的/**是对所有的请求都做拦截。
是否感觉配置这个地址是不特别方便?下一篇博客介绍2.0版本引入注解来协助完成一系列的拦截任务。
SpringBoot之HandlerInterceptor拦截器的使用 ——(二)自定义注解
SpringBoot之HandlerInterceptor拦截器的使用 ——(三)获取请求参数解决java.io.IOException: Stream closed
SpringBoot之HandlerInterceptor拦截器的使用 ——(四)防重复提交