在 Spring MVC 中,HandlerInterceptor 是一种常用的拦截器,用于在处理请求的不同阶段插入逻辑(如认证、日志记录等)。多个拦截器的执行顺序由它们的配置顺序决定。以下是配置和执行顺序的完整指南。


拦截器的执行阶段

  1. preHandle:

    • 在请求被处理之前调用。
    • 返回 true 表示继续执行,返回 false 表示中断请求。
  2. postHandle:

    • 在请求处理之后,但在生成视图之前调用。
    • 可以修改返回的数据。
  3. afterCompletion:

    • 在整个请求完成后调用(包括视图渲染)。

拦截器的执行顺序

  • preHandle

    • 按照拦截器的添加顺序执行。
  • postHandleafterCompletion

    • 按照拦截器的添加顺序 倒序 执行。

完整配置步骤

1. 创建拦截器类

实现 HandlerInterceptor 接口或继承 HandlerInterceptorAdapter(已过时,推荐直接实现接口)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class FirstInterceptor implements HandlerInterceptor {

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("FirstInterceptor - preHandle");
return true; // 继续执行下一个拦截器
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("FirstInterceptor - postHandle");
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("FirstInterceptor - afterCompletion");
}
}

类似的创建第二个拦截器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Component
public class SecondInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("SecondInterceptor - preHandle");
return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("SecondInterceptor - postHandle");
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("SecondInterceptor - afterCompletion");
}
}

2. 配置拦截器顺序

WebMvcConfigurer 中添加拦截器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import org.springframework.beans.factory.annotation.Autowired;
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 WebConfig implements WebMvcConfigurer {

@Autowired
private FirstInterceptor firstInterceptor;

@Autowired
private SecondInterceptor secondInterceptor;

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(firstInterceptor)
.addPathPatterns("/**") // 应用到所有路径
.order(1); // 设置优先级,越小优先级越高

registry.addInterceptor(secondInterceptor)
.addPathPatterns("/**")
.order(2);
}
}

执行顺序

以请求 /example 为例,两个拦截器的执行顺序如下:

请求进入时:

  1. FirstInterceptor - preHandle
  2. SecondInterceptor - preHandle

处理完成时:

  1. SecondInterceptor - postHandle
  2. FirstInterceptor - postHandle

请求完成后:

  1. SecondInterceptor - afterCompletion
  2. FirstInterceptor - afterCompletion

常见场景和配置

1. 拦截特定路径

1
2
3
registry.addInterceptor(firstInterceptor)
.addPathPatterns("/api/**") // 拦截 `/api` 开头的路径
.excludePathPatterns("/api/login"); // 排除 `/api/login`

2. 优先级控制

order() 控制顺序:

  • order(1) 会在 order(2) 之前执行。
  • 如果未设置 order,默认顺序由添加的先后决定。

3. 动态逻辑中断请求

preHandle 返回 false 可以中断请求,例如:

1
2
3
4
5
6
7
8
9
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (!isAuthorized(request)) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("Unauthorized");
return false;
}
return true;
}

总结

  • 顺序控制:通过 order() 明确拦截器的优先级,preHandle 按顺序,postHandleafterCompletion 倒序。
  • 灵活配置:支持路径匹配和排除规则。
  • 统一管理:通过实现 WebMvcConfigurer 管理所有拦截器,逻辑清晰易维护。