HandlerInterceptor介绍-笔记
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
传递)。