HandlerInterceptor簡介
攔截器我想大家都並不陌生,最常用的登錄攔截、或是權限校驗、或是防重復提交、或是根據業務像12306去校驗購票時間,總之可以去做很多的事情。
我仔細想了想
這里我分三篇博客來介紹HandlerInterceptor的使用,從基本的使用、到自定義注解、最后到讀取body中的流解決無法多次讀取的問題。
1、定義實現類
定義一個Interceptor 非常簡單方式也有幾種,我這里簡單列舉兩種
1、類要實現Spring 的HandlerInterceptor 接口
2、類繼承實現了HandlerInterceptor 接口的類,例如 已經提供的實現了HandlerInterceptor 接口的抽象類HandlerInterceptorAdapter
2、HandlerInterceptor方法介紹
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;
preHandle:在業務處理器處理請求之前被調用。預處理,可以進行編碼、安全控制、權限校驗等處理;
postHandle:在業務處理器處理請求執行完成后,生成視圖之前執行。后處理(調用了Service並返回ModelAndView,但未進行頁面渲染),有機會修改ModelAndView (這個博主就基本不怎么用了);
afterCompletion:在DispatcherServlet完全處理完請求后被調用,可用於清理資源等。返回處理(已經渲染了頁面);
接下來讓我們來實現一個登陸 and 訪問權限校驗的攔截器吧
攔截器實現
- 新建TestFilter
-
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 {} }
- 新建WebAppConfigurer 實現WebMvcConfigurer接口
其實以前都是繼承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("/**"); } .... }