Spring MVC 实现HandlerInterceptor接口
HandlerInterceptor接口是Spring MVC拦截器的核心接口,包含三个方法分别在不同时机执行。
接口定义
Java
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,
ModelAndView modelAndView) throws Exception {
}
default void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
}
}
基本实现方式
方式一:直接实现接口
Java
@Component
public class SimpleInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
log.info("preHandle: {}", request.getRequestURI());
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
log.info("postHandle: {}", request.getRequestURI());
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
log.info("afterCompletion: {}", request.getRequestURI());
}
}
方式二:继承HandlerInterceptorAdapter
Java
@Component
public class LegacyInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// 只覆盖需要的方法
return true;
}
}
HandlerInterceptorAdapter已废弃,推荐直接实现接口(接口方法均为default)。
preHandle方法实现
Java
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// 1. 获取请求信息
String uri = request.getRequestURI();
String method = request.getMethod();
String ip = request.getRemoteAddr();
// 2. 获取Handler信息
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
String controllerName = handlerMethod.getBeanType().getSimpleName();
String methodName = handlerMethod.getMethod().getName();
log.info("请求: {} -> {}.{}", uri, controllerName, methodName);
}
// 3. 前置处理逻辑
request.setAttribute("startTime", System.currentTimeMillis());
// 4. 返回true继续执行,返回false中断请求
return true;
}
返回false中断请求
Java
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
HttpSession session = request.getSession(false);
if (session == null || session.getAttribute("user") == null) {
// 未登录,中断请求并重定向
response.sendRedirect("/login");
return false;
}
return true;
}
postHandle方法实现
Java
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
// 1. 添加公共数据
if (modelAndView != null) {
modelAndView.addObject("timestamp", System.currentTimeMillis());
modelAndView.addObject("version", "1.0.0");
}
// 2. 计算处理时间
Long startTime = (Long) request.getAttribute("startTime");
long duration = System.currentTimeMillis() - startTime;
request.setAttribute("duration", duration);
// 3. 修改响应头
response.setHeader("X-Process-Time", String.valueOf(duration));
}
postHandle限制
Controller抛出异常时postHandle不执行。
afterCompletion方法实现
Java
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
// 1. 计算总耗时
Long startTime = (Long) request.getAttribute("startTime");
long duration = System.currentTimeMillis() - startTime;
// 2. 记录日志
if (ex != null) {
log.error("请求异常: {} {}, 耗时: {}ms, 异常: {}",
request.getMethod(), request.getRequestURI(), duration, ex.getMessage());
} else {
log.info("请求完成: {} {}, 耗时: {}ms, 状态: {}",
request.getMethod(), request.getRequestURI(), duration, response.getStatus());
}
// 3. 清理资源
UserContext.clear();
TraceContext.clear();
// 4. 清理请求属性
request.removeAttribute("startTime");
}
Handler参数详解
Java
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
// 获取Controller类
Class<?> controllerClass = handlerMethod.getBeanType();
// 获取方法
Method method = handlerMethod.getMethod();
// 获取方法参数
MethodParameter[] parameters = handlerMethod.getMethodParameters();
// 获取方法注解
Annotation[] annotations = method.getAnnotations();
// 获取方法上的特定注解
MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
// 获取类上的注解
MyAnnotation classAnnotation = controllerClass.getAnnotation(MyAnnotation.class);
}
return true;
}
注册拦截器
Java
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private SimpleInterceptor simpleInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(simpleInterceptor)
.addPathPatterns("/**") // 拦截所有路径
.excludePathPatterns("/static/**") // 排除静态资源
.order(1); // 设置执行顺序
}
}
拦截器注解配置
Java
// 定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
String value() default "";
}
// 拦截器实现
@Component
public class AnnotationInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Log logAnnotation = handlerMethod.getMethodAnnotation(Log.class);
if (logAnnotation != null) {
log.info("注解日志: {}", logAnnotation.value());
}
}
return true;
}
}
// Controller使用
@RestController
public class UserController {
@Log("查询用户列表")
@GetMapping("/users")
public List<User> listUsers() {
return userService.findAll();
}
}
异步请求拦截器
Java
@Component
public class AsyncInterceptor implements HandlerInterceptor, AsyncHandlerInterceptor {
@Override
public void afterConcurrentHandlingStarted(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
log.info("异步处理开始: {}", request.getRequestURI());
}
}
实现注意事项
| 注意点 | 说明 |
|---|---|
| preHandle返回值 | true继续执行,false中断请求 |
| postHandle执行条件 | Controller无异常时执行 |
| afterCompletion执行条件 | preHandle返回true的拦截器才执行 |
| ModelAndView参数 | REST接口返回null,传统接口有值 |
| Exception参数 | 无异常时为null |
| 资源清理 | afterCompletion中清理ThreadLocal |
要点总结
- 直接实现HandlerInterceptor接口,三个方法均为default
- preHandle返回true继续,返回false中断请求
- postHandle只在Controller无异常时执行
- afterCompletion无论是否有异常都执行
- handler参数可获取Controller和方法信息
- 必须在WebMvcConfigurer中注册拦截器
📝 发现内容有误?点击此处直接编辑