1. HandlerInterceptor簡介
org.springframework.web.servlet.HandlerInterceptor
?是 Spring MVC 中用于攔截 HTTP 請求的核心接口。
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 {}
}
HandlerInterceptor 的核心方法介紹
-
preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
- 作用:在請求處理之前執行(即在控制器方法執行前)。
- 返回值:返回?
true
?表示繼續后續處理;返回?false
?表示中斷請求(直接返回響應)。 - 典型用途:權限校驗、請求日志記錄。
-
postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
- 作用:在請求處理完成后、視圖渲染之前執行。
- 參數說明:
modelAndView
?是控制器方法返回的結果。 - 典型用途:修改模型數據、記錄響應日志。
-
afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
- 作用:在整個請求完成時執行(即視圖渲染結束后)。
- 典型用途:資源清理、異常處理、性能統計。
它允許開發者在請求處理的不同階段插入自定義邏輯,例如權限驗證、日志記錄、性能監控等。通過實現該接口的三個關鍵方法,可以靈活控制請求的處理流程。
2. 使用示例
2.1?日志攔截器demo
下面以一個 日志攔截器 為例,演示如何使用HandlerInterceptor。
step1.
實現?HandlerInterceptor
?接口
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;public class LoggingHandlerInterceptor implements HandlerInterceptor {// 請求處理前執行@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {String requestId = UUID.randomUUID().toString();request.setAttribute("requestId", requestId);System.out.println("=== PreHandle ===");System.out.println("Request ID: " + requestId);System.out.println("Request URL: " + request.getRequestURL());return true; // 繼續后續處理}// 請求處理后、視圖渲染前執行@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) {System.out.println("=== PostHandle ===");if (modelAndView != null) {System.out.println("View Name: " + modelAndView.getViewName());return;}System.out.println("No view");}// 請求完成時執行@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,Exception ex) {System.out.println("=== AfterCompletion ===");if (ex != null) {System.out.println("Exception occurred: " + ex.getMessage());}System.out.println("Response Status: " + response.getStatus());System.out.println("Request ID: " + request.getAttribute("requestId"));}
}
step2.注冊攔截器到 Spring MVC 配置
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 HandlerInterceptorWebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new LoggingHandlerInterceptor()).addPathPatterns("/**") // 攔截所有路徑.excludePathPatterns("/public/**"); // 排除特定路徑;}
}
step3.創建測試controller
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class HandlerInterceptorController {@GetMapping("HandlerInterceptorController/test")public String test() {return "test";}
}
step4. 測試
啟動應用,瀏覽器輸入??http://127.0.0.1:8080/HandlerInterceptorController/test ,日志輸出如下:
2.2 其他使用場景demo
2.2.1 權限驗證
在?preHandle
?中檢查用戶是否登錄,未登錄則重定向到登錄頁面:
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {if (userNotAuthenticated(request)) {response.sendRedirect("/login");return false; // 中斷請求}return true;
}
2.2.2?性能監控
在?preHandle
?記錄開始時間,在?afterCompletion
?計算耗時:
private Long startTime;@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {startTime = System.currentTimeMillis();return true;
}@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {long duration = System.currentTimeMillis() - startTime;System.out.println("Request took " + duration + " ms");
}
2.3 注意事項
- 攔截器順序:多個攔截器時,注冊順序決定執行順序(
preHandle
?按注冊順序執行,afterCompletion
?按逆序執行)。 - 異常處理:
afterCompletion
?中可以通過?Exception ex
?參數捕獲控制器拋出的異常。 - 線程安全:攔截器默認是單例的,避免在攔截器中使用成員變量存儲請求相關數據(可通過?
request.setAttribute
?傳遞)。