拦截器 (Interception)
所有的 HandlerMapping 实现都支持处理器拦截,这在你需要对请求应用横切关注点(Cross-cutting Concerns)时非常有用。
HandlerInterceptor 接口
一个拦截器需要实现 org.springframework.web.servlet.HandlerInterceptor 接口,它包含三个主要的回调方法:
preHandle(..):在实际处理器运行之前调用。返回值是一个布尔值。如果返回true,则继续执行链;如果返回false,则中断执行链,处理器将不会被调用。postHandle(..):在处理器运行之后调用。afterCompletion(..):在整个请求完成后调用(即视图渲染完成后)。
注意
对于使用 @ResponseBody 或 ResponseEntity 的控制器方法,响应会在 HandlerAdapter 内部被写入并提交,这发生在 postHandle 调用之前。这意味着在 postHandle 中添加响应头已经太晚了。对于此类需求,请使用 ResponseBodyAdvice。
安全警告
拦截器并不适合作为核心安全层(Security Layer)。由于其路径匹配可能与注解控制器的路径匹配存在细微的不一致,可能会产生绕过风险。通常,我们强烈建议使用 Spring Security,或者基于 Servlet 过滤器的类似方法,并尽可能早地应用安全策略。
补充教学
1. 过滤器 (Filter) vs 拦截器 (Interceptor)
这是 Spring MVC 开发者最常混淆的一点:
| 特性 | 过滤器 (Servlet Filter) | 拦截器 (HandlerInterceptor) |
|---|---|---|
| 所属规范 | Servlet 规范 | Spring MVC 框架 |
| 执行时机 | 在 DispatcherServlet 处理之前/后 | 在进入 Controller 之前/后 |
| 访问能力 | 只能访问 Request/Response | 可以访问 Spring 上下文、Bean、以及具体的 Handler 对象 |
| 适用场景 | 字符编码、敏感词过滤、通用安全 | 业务权限校验、性能监控、模型属性注入 |
2. 执行顺序详解
如果你有多个拦截器,它们的执行顺序如下(假设顺序为 A, B):
Interceptor A.preHandleInterceptor B.preHandle- Controller 业务逻辑
Interceptor B.postHandle(逆序)Interceptor A.postHandle(逆序)- 渲染视图
Interceptor B.afterCompletion(逆序)Interceptor A.afterCompletion(逆序)
核心理解:preHandle 是顺序执行,而 postHandle 和 afterCompletion 是逆序执行(类似栈的结构)。
3. 如何解决 postHandle 无法修改 JSON 的问题?
如文档所述,当你的 Controller 返回 JSON 时,数据已经通过 Jackson 写进流里了。如果你非要对全局的响应 JSON 做修改(比如统一包装一个 code: 200):
- 方案:实现
ResponseBodyAdvice<Object>。 - 原理:它允许你在 Spring 真正把对象转成 JSON 字符串的一瞬间进行拦截和修改。