Spring拦截器(Interceptor)学习笔记

一、拦截器概述

1.1 什么是拦截器?

拦截器是Spring框架提供的一种动态拦截方法调用的机制,类似于Servlet中的过滤器(Filter)。主要特点包括:

  • 动态拦截控制器方法的执行
  • 指定方法调用前后执行预设代码
  • 用于处理通用性的业务逻辑(如登录校验、权限检查、日志记录等)

1.2 拦截器 vs 过滤器

特性 拦截器(Interceptor) 过滤器(Filter)
所属框架 Spring MVC Servlet规范
拦截范围 只拦截Spring环境中的资源 拦截所有资源
依赖 依赖Spring容器 不依赖任何框架
执行时机 Controller方法前后 Servlet处理前后
实现接口 HandlerInterceptor Filter

二、拦截器快速入门

2.1 实现步骤

  1. 定义拦截器:实现HandlerInterceptor接口
  2. 注册配置:通过WebMvcConfigurer配置

2.2 代码实现

1) 自定义拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Component
public class DemoInterceptor implements HandlerInterceptor {
// 目标方法执行前调用
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle执行...");
return true; // true放行,false拦截
}

// 目标方法执行后调用(视图渲染前)
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle执行...");
}

// 整个请求完成后调用(视图渲染后)
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion执行...");
}
}

2) 注册拦截器

1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
public class WebConfig implements WebMvcConfigurer {

@Autowired
private DemoInterceptor demoInterceptor;

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(demoInterceptor)
.addPathPatterns("/**"); // 拦截所有路径
}
}

2.3 执行顺序验证

当访问一个Controller方法时,控制台输出:

1
2
3
4
preHandle执行...
Controller方法执行...
postHandle执行...
afterCompletion执行...

注意:如果preHandle返回false,则后续流程都不会执行!

三、登录校验拦截器实战

3.1 令牌校验实现

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
@Slf4j
@Component
public class TokenInterceptor implements HandlerInterceptor {

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 1. 获取请求URL
String url = request.getRequestURL().toString();

// 2. 登录请求直接放行
if(url.contains("login")) {
log.info("登录请求,放行");
return true;
}

// 3. 获取token
String jwt = request.getHeader("token");

// 4. token不存在返回未登录
if(!StringUtils.hasLength(jwt)) {
log.error("令牌为空");
response.setStatus(HttpStatus.SC_UNAUTHORIZED); // 401
return false;
}

// 5. 解析token
try {
JwtUtils.parseJWT(jwt);
} catch (Exception e) {
log.error("令牌解析失败");
response.setStatus(HttpStatus.SC_UNAUTHORIZED);
return false;
}

// 6. 放行
log.info("令牌校验通过");
return true;
}
}

3.2 配置拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
@Configuration
public class WebConfig implements WebMvcConfigurer {

@Autowired
private TokenInterceptor tokenInterceptor;

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(tokenInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/login"); // 排除登录接口
}
}

四、拦截器详解

4.1 拦截路径配置

1) 基本配置方法

  • addPathPatterns():添加拦截路径
  • excludePathPatterns():添加排除路径
1
2
3
registry.addInterceptor(interceptor)
.addPathPatterns("/**") // 拦截所有
.excludePathPatterns("/login"); // 排除登录

2) 常见路径模式

模式 说明
/* 一级路径(如/user
/** 任意级路径(如/user/1
/admin/** 拦截/admin下的所有路径
/secure/*.do 拦截/secure下的所有.do请求

4.2 拦截器执行流程

完整请求生命周期

  1. 过滤器前置处理
  2. DispatcherServlet接收请求
  3. 拦截器preHandle
    • 返回true:继续执行
    • 返回false:终止流程
  4. Controller方法执行
  5. 拦截器postHandle
  6. 视图渲染
  7. 拦截器afterCompletion
  8. 过滤器后置处理

执行流程图

image.png

五、最佳实践建议

  1. 登录校验:推荐使用拦截器而非过滤器

    • 能利用Spring的依赖注入
    • 更精准控制Spring环境中的请求
  2. 路径配置

    1
    2
    3
    4
    // 推荐配置方式
    registry.addInterceptor(authInterceptor)
    .addPathPatterns("/api/**")
    .excludePathPatterns("/api/public/**");
  3. 性能优化

    • preHandle中进行轻量级检查
    • 避免在拦截器中执行耗时操作
  4. 多拦截器顺序

    • 通过order()方法控制执行顺序
    1
    2
    registry.addInterceptor(interceptor1).order(1);
    registry.addInterceptor(interceptor2).order(2);

六、常见问题解答

Q1:拦截器和过滤器如何选择?

  • 需要处理Spring相关功能(如自动注入、AOP等)→ 拦截器
  • 需要处理静态资源、非Spring请求 → 过滤器

Q2:拦截器能获取Controller方法信息吗?
可以,通过handler参数:

1
2
3
4
5
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
// 可以获取方法注解等信息
}

Q3:拦截器中如何修改响应数据?
可以在postHandle中操作ModelAndView

1
2
3
4
@Override
public void postHandle(...) {
modelAndView.addObject("newData", "value");
}