我是陳皮,一個在網際網路 Coding 的 ITer,微信搜尋「陳皮的JavaLib」第一時間閱讀最新文章,回覆【資料】,即可獲得我精心整理的技術資料,電子書籍,一線大廠面試資料和優秀簡歷模板。
HandlerInterceptor 詳解
HandlerInterceptor
允許定製 handler
處理器執行鏈的工作流介面。我們可以自定義攔截器用於攔截 handlers 處理器(你可以理解為 controller 層的介面),從而可以新增一些共同的重複性的處理行為(例如介面鑑權,介面日誌記錄,效能監控等),而不用修改每一個 handler 的實現。
注意,此基於 SpringBoot 2.3.12.RELEASE
版本講解。
HandlerInterceptor 介面只有三個預設空實現方法,在低版本中這三個方法不是預設方法,而是抽象方法。
public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
}
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
}
}
這三個方法的執行順序圖如下:
preHandle
preHandle
前置處理,攔截一個處理器(handler)的執行,preHandle 方法會在 HandlerMapping
確定一個適當的處理器物件之後,但在 HandlerAdapter
呼叫處理器之前被呼叫。可以簡單理解為 controller 介面被呼叫之前執行。
Intercepter 是鏈式的,就是一個接著一個執行。如果此方法返回 true,則會執行下一個攔截器或者直接執行處理器。如果此方法返回 false 或者丟擲異常則終止執行鏈,也不再呼叫處理器。
注意,此方法如果不返回 true,那麼 postHandle
和 afterCompletion
不會被執行。
那這個方法有什麼用呢?其實可以做一些介面被呼叫前的預處理,例如使用者許可權校驗。
package com.chenpi;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
/**
* @Description 使用者許可權驗證攔截
* @Author 陳皮
* @Date 2021/6/27
* @Version 1.0
*/
@Component
public class UserPermissionInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
// 獲取使用者許可權校驗註解
UserAuthenticate userAuthenticate =
handlerMethod.getMethod().getAnnotation(UserAuthenticate.class);
if (null == userAuthenticate) {
userAuthenticate = handlerMethod.getMethod().getDeclaringClass()
.getAnnotation(UserAuthenticate.class);
}
if (userAuthenticate != null && userAuthenticate.permission()) {
// 驗證使用者資訊
UserContext userContext = userContextManager.getUserContext(request);
if (null == userContext) {
return false;
}
}
}
return true;
}
}
postHandle
postHandle
後置處理,會在 HandlerAdapter
呼叫處理器之後,但在 DispatcherServlet
渲染檢視之前被呼叫。可以在此對 ModelAndView
做一些額外的處理。可以簡單理解為 controller 介面被呼叫之後執行。
注意,此方法在執行鏈中的執行順序是倒著執行的,即先宣告的攔截器後執行。
afterCompletion
afterCompletion 完成之後,在請求處理完之後被執行,也就是渲染完檢視之後。一般用於做一些資源的清理工作,配合 preHandle 計算介面執行時間等。
注意,和 postHandle 一樣,此方法在執行鏈中的執行順序也是倒著執行的,即先宣告的攔截器後執行。
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, @Nullable Exception ex) {
// 請求完後,清除當前執行緒的使用者資訊
UserContextHolder.removeUserContext();
}
註冊攔截器
注意,我們自定義的攔截器要通過 WebMvcConfigurer
的實現類進行註冊,才能生效。
package com.yzj.ehr.common.config;
import com.yzj.ehr.common.context.UserContextResolver;
import org.springframework.stereotype.Component;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import com.yzj.ehr.common.interceptor.UserPermissionInterceptor;
/**
* @Description 註冊攔截器
* @Author 陳皮
* @Date 2021/6/27
* @Version 1.0
*/
@Component
public class WebAppConfigurer implements WebMvcConfigurer {
private UserPermissionInterceptor userPermissionInterceptor;
public WebAppConfigurer(final UserPermissionInterceptor userPermissionInterceptor) {
this.userPermissionInterceptor = userPermissionInterceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 匹配所有介面,排除/base/test介面
registry.addInterceptor(userPermissionInterceptor).addPathPatterns("/**")
.excludePathPatterns("/base/test");
}
}