SpringBoot之HandlerInterceptorAdapter
在SpringBoot中我們可以使用HandlerInterceptorAdapter這個適配器來實現自己的攔截器。這樣就可以攔截所有的請求並做相應的處理。
應用場景
- 日志記錄,可以記錄請求信息的日志,以便進行信息監控、信息統計等。
- 權限檢查:如登陸檢測,進入處理器檢測是否登陸,如果沒有直接返回到登陸頁面。
- 性能監控:典型的是慢日志。
在HandlerInterceptorAdapter中主要提供了以下的方法:
preHandle:在方法被調用前執行。在該方法中可以做類似校驗的功能。如果返回true,則繼續調用下一個攔截器。如果返回false,則中斷執行,也就是說我們想調用的方法 不會被執行,但是你可以修改response為你想要的響應。
postHandle:在方法執行后調用。
afterCompletion:在整個請求處理完畢后進行回調,也就是說視圖渲染完畢或者調用方已經拿到響應。
在HandlerInterceptorAdapter中主要提供了以下的方法:
- preHandle:在方法被調用前執行。在該方法中可以做類似校驗的功能。如果返回true,則繼續調用下一個攔截器。如果返回false,則中斷執行,也就是說我們想調用的方法 不會被執行,但是你可以修改response為你想要的響應。
- postHandle:在方法執行后調用。
- afterCompletion:在整個請求處理完畢后進行回調,也就是說視圖渲染完畢或者調用方已經拿到響應。
HandlerInterceptor
攔截器適配器HandlerInterceptorAdapter
public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor { /** * This implementation always returns {@code true}. */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } /** * This implementation is empty. */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { } /** * This implementation is empty. */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { } /** * This implementation is empty. */ @Override public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { } }
有時候我們可能只需要實現三個回調方法中的某一個,如果實現HandlerInterceptor接口的話,三個方法必須實現,不管你需不需要,此時spring提供了一個HandlerInterceptorAdapter適配器(種適配器設計模式的實現),允許我們只實現需要的回調方法。
這樣在我們業務中比如要記錄系統日志,日志肯定是在afterCompletion之后記錄的,否則中途失敗了,也記錄了,那就扯淡了。一定是程序正常跑完后,我們記錄下那些對數據庫做個增刪改的操作日志進數據庫。所以我們只需要繼承HandlerInterceptorAdapter,並重寫afterCompletion一個方法即可,因為preHandle默認是true。
運行流程總結如下:
- 攔截器執行順序是按照Spring配置文件中定義的順序而定的。
- 會先按照順序執行所有攔截器的preHandle方法,一直遇到return false為止,比如第二個preHandle方法是return false,則第三個以及以后所有攔截器都不會執行。若都是return true,則按順序加載完preHandle方法。
- 然后執行主方法(自己的controller接口),若中間拋出異常,則跟return false效果一致,不會繼續執行postHandle,只會倒序執行afterCompletion方法。
- 在主方法執行完業務邏輯(頁面還未渲染數據)時,按倒序執行postHandle方法。若第三個攔截器的preHandle方法return false,則會執行第二個和第一個的postHandle方法和afterCompletion(postHandle都執行完才會執行這個,也就是頁面渲染完數據后,執行after進行清理工作)方法。(postHandle和afterCompletion都是倒序執行)
下面用一個demo來演示執行流程
定義一個類繼承HandlerInterceptorAdapter,並重寫方法
快捷鍵ctrl+o打開可以重寫的方法面板選擇
package com.example.demo.config; 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 LogInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.err.println("================================== preHandle1 ==========================================="); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.err.println("================================== postHandle1 ==========================================="); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.err.println("================================== afterCompletion1 ==========================================="); } }
WebMvcConfigurerAdapter 抽象類是對WebMvcConfigurer接口的簡單抽象(增加了一些默認實現),但在在SpringBoot2.0及Spring5.0中WebMvcConfigurerAdapter已被廢棄 。官方推薦直接實現WebMvcConfigurer或者直接繼承WebMvcConfigurationSupport
實現WebMvcConfigurer配置攔截器
package com.example.demo.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LogInterceptor()); } }
在控制器中寫一個方法並訪問
@ApiOperation(value = "test mybatis", notes = "") @RequestMapping(value = "getuser", method = RequestMethod.GET) public User getUser() { return userService.getUser(); }
會在控制台輸出
此時在加入一個攔截器,會按照配置的順序執行,配置如下
package com.example.demo.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LogInterceptor()); registry.addInterceptor(new LogInterceptor2()); } }
控制的輸出反映了配置多個攔截器的執行流程:
如果controller出現異常,則不會繼續執行postHandle,只會倒序執行afterCompletion方法