Spring MVC HandlerInterceptor 提供三個切面方法:preHandle、postHandle、afterCompletion,可實現通用日志記錄、執行耗時統計、異常捕獲等橫切關注點。本文演示基於 SLF4J 的完整實現。
package org.xs.demo1;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.NamedThreadLocal;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
public class LogInterceptor implements HandlerInterceptor {
private static final Logger log = LoggerFactory.getLogger(LogInterceptor.class);
private static final ThreadLocal START_TIME_THREAD_LOCAL = new NamedThreadLocal<>("ThreadLocal StartTime");
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
long start = System.currentTimeMillis();
START_TIME_THREAD_LOCAL.set(start);
log.info("開始計時: {}", new SimpleDateFormat("HH:mm:ss.SSS").format(start));
return true; // true=繼續執行,false=中斷
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
if (modelAndView != null) {
log.info("ViewName: {}", modelAndView.getViewName());
}
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
long start = START_TIME_THREAD_LOCAL.get();
long end = System.currentTimeMillis();
log.info("訪問地址: {}, 請求方式: {}", request.getRequestURI(), request.getMethod());
log.info("計時結束: {}, 耗時: {} ms", new SimpleDateFormat("HH:mm:ss.SSS").format(end), end - start);
// 可選:保存訪問日志到數據庫
// LogUtils.saveLog(request, handler, ex, null);
}
}
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/> <!-- 攔截所有請求 -->
<bean class="org.xs.demo1.LogInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
或 Java Config:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor()).addPathPatterns("/**");
}
}
訪問 https://localhost:8080/demo1/hello/list2,控制台輸出:
[INFO ] 14:30:45.123 LogInterceptor - 開始計時: 14:30:45.123 [INFO ] 14:30:45.125 LogInterceptor - ViewName: hello/list [INFO ] 14:30:45.126 LogInterceptor - 訪問地址: /demo1/hello/list2, 請求方式: GET [INFO ] 14:30:45.126 LogInterceptor - 計時結束: 14:30:45.126, 耗時: 3 ms

preHandle 中檢查 Session/Token,失敗返回 false 並重定向登錄頁preHandle 中統一 XSS 過濾、SQL 注入防護afterCompletion 中 ex != null 記錄錯誤日志、發送告警| 維度 | HandlerInterceptor | Filter |
|---|---|---|
| 屬於 | Spring MVC 體系 | Servlet 規範 |
| 攔截範圍 | 僅 Controller 處理流程 | 所有進入容器請求(含靜態資源) |
| 獲取上下文 | 方便獲取 Handler、ModelAndView | 僅 ServletRequest/Response |
| 配置方式 | Spring 配置類/XML | web.xml 或 @WebFilter |
| 執行順序 | Filter → Interceptor → Controller | 最外層 |
NamedThreadLocal 避免線程池復用導致數據洩漏preHandle 返回 false 時務必手動響應(如 response.sendRedirect()),否則客戶端無響應System.nanoTime() 精度更高INFO,關鍵路徑 DEBUGAsyncAppender) 避免阻塞業務線程掌握 HandlerInterceptor 三階段生命周期,能優雅實現日志、監控、安全等橫切功能,保持控制器代碼純淨專注業務邏輯。