Java案例怎么配置拦截器?从入门到实战的完整指南
目录导读
-
什么是拦截器?为什么需要它?

- 拦截器的核心作用与适用场景
- 与过滤器的区别及选择建议
-
Spring Boot中配置拦截器的3步法
- 实现HandlerInterceptor接口
- 注册拦截器到WebMvcConfigurer
- 指定拦截路径与排除路径
-
实战案例:用户登录权限校验
- 场景分析:未登录用户无法访问受保护资源
- 代码实现:拦截器逻辑 + 前后端交互示例
-
常见问题与解决方案(问答环节)
- 拦截器不生效怎么办?
- 如何获取请求体中的参数?
- 拦截器与AOP的区别?
-
性能优化与最佳实践
- 避免在拦截器中执行耗时操作
- 使用注解方式代替路径匹配
-
总结与扩展
- 拦截器的其他应用场景(日志记录、国际化等)
- 推荐学习资源
什么是拦截器?为什么需要它?
拦截器(Interceptor)是Java Web开发中一种对请求进行预处理和后处理的机制,它类似于弹簧,在请求到达Controller之前(preHandle)和Controller处理完成后(postHandle、afterCompletion)插入自定义逻辑。
核心作用:
- 权限校验:检查用户是否登录,是否有访问权限。
- 日志记录:记录请求参数、响应时间、异常信息。
- 性能监控:统计接口响应时长。
- 参数预处理:对请求参数进行解密、校验、格式转换。
与过滤器的区别:
| 特性 | 过滤器(Filter) | 拦截器(Interceptor) |
|---------------|-------------------------------|-------------------------------|
| 作用范围 | 所有Web请求(包括静态资源) | 仅针对Spring MVC的Controller |
| 实现方式 | 基于Servlet规范 | 基于Spring AOP思想 |
| 获取容器资源 | 较难直接注入Spring Bean | 可直接注入Service、Dao等 |
| 典型场景 | 编码设置、XSS过滤 | 权限校验、日志记录 |
建议:跨多个框架的通用处理(如编码)用过滤器,而针对Controller的业务逻辑用拦截器。
Spring Boot中配置拦截器的3步法
第一步:实现HandlerInterceptor接口
创建一个类,重写以下三个方法(最常用的是preHandle):
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 1. 检查用户是否已登录(假设使用Session存储登录状态)
Object user = request.getSession().getAttribute("user");
if (user == null) {
// 未登录,返回错误信息或重定向到登录页
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"code\":401,\"message\":\"请先登录\"}");
return false; // 拦截请求
}
return true; // 放行
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// 在Controller执行后、视图渲染前执行(可修改ModelAndView)
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 在视图渲染后执行(一般用于资源清理)
}
}
关键点:
return false表示拦截请求,不再执行后续的Controller方法。- 如果返回
true但响应已提交(比如直接写入了response),后续操作可能失效。
第二步:注册拦截器到WebMvcConfigurer
使用@Configuration类实现WebMvcConfigurer接口,重写addInterceptors方法:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/api/**") // 拦截所有以/api/开头的路径
.excludePathPatterns("/api/login") // 排除登录接口
.excludePathPatterns("/api/register"); // 排除注册接口
}
}
路径匹配规则:
- 匹配一级路径,如
/user,但不匹配/user/abc。 - 匹配任意层级路径。
- 支持Ant风格通配符:
/api/v1/**匹配/api/v1/xxx。
第三步:验证配置是否生效
启动Spring Boot应用,访问受保护的/api/user/info(未登录时),应返回JSON错误信息或重定向到登录页。
常见问题排查:
- 确保
LoginInterceptor上有@Component注解。 - 检查
WebConfig类是否被Spring扫描到(如放在启动类同级或子包下)。 - 若使用Spring Security,需注意拦截器优先级在Security之后。
实战案例:用户登录权限校验
场景描述
假设有一个博客系统,用户必须登录后才能发表评论(/api/comment/add),未登录时返回“请先登录”提示。
代码实现结构
项目结构:
src/main/java/com/example/demo
├── config
│ └── WebConfig.java (注册拦截器)
├── interceptor
│ └── LoginInterceptor.java (拦截器逻辑)
├── controller
│ └── CommentController.java (评论接口)
└── DemoApplication.java (启动类)
拦截器逻辑(LoginInterceptor):
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 从请求头获取token(实际项目常用JWT)
String token = request.getHeader("Authorization");
if (token == null || !"valid_token".equals(token)) { // 简化示例
response.setStatus(401);
response.getWriter().write("{\"error\":\"请先登录\"}");
return false;
}
return true;
}
}
注册拦截器(WebConfig):
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/api/comment/**"); // 仅拦截评论相关接口
}
}
Controller接口:
@RestController
@RequestMapping("/api/comment")
public class CommentController {
@PostMapping("/add")
public String addComment(@RequestBody String content) {
// 只有登录用户才能到达这里
return "评论成功:" + content;
}
}
测试结果:
- 调用
POST /api/comment/add时未携带token → 返回401 + “请先登录”。 - 携带正确的token → 返回“评论成功”。
常见问题与解决方案(问答环节)
Q1:拦截器不生效怎么办?
可能原因:
- 未将拦截器类标记为
@Component。 WebMvcConfigurer的配置类未被Spring扫描。- 使用了
@EnableWebMvc注解(会覆盖Spring Boot的自动配置)。
解决步骤:
- 检查拦截器类是否有
@Component。 - 确保配置类在启动类同包或子包下。
- 如果必须用
@EnableWebMvc,需手动配置所有MVC相关组件,不建议一般项目使用。
Q2:如何在拦截器中获取请求体(POST请求的JSON数据)?
注意:HttpServletRequest的getInputStream()和getReader()只能读取一次,直接读取会导致Controller中无法再获取请求体。
解决方案:
- 使用Filter + 包装Request:创建一个
RequestWrapper,缓存请求体数据。 - 在拦截器中通过
request.getParameter()获取(仅适用于表单提交)。 - 使用Spring的
ContentCachingRequestWrapper:@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper((HttpServletRequest) request); // 读取一次(会在wrapper中缓存) String body = new String(requestWrapper.getContentAsByteArray(), StandardCharsets.UTF_8); // 后续Controller依然能通过getInputStream读取 return true; }
Q3:拦截器和AOP有什么区别?何时使用拦截器?
| 维度 | 拦截器 | AOP(面向切面编程) |
|---|---|---|
| 作用对象 | Controller的请求/响应 | 任意类、方法 |
| 访问上下文 | 可直接获取HttpServletRequest | 需通过RequestContextHolder获取 |
| 典型用途 | 登录校验、日志、跨域处理 | 事务管理、缓存、权限注解 |
建议:
- 需要操作
HttpServletResponse(如重定向、设置响应头)时用拦截器。 - 需要增强Service层或任意方法时用AOP。
性能优化与最佳实践
1 避免在拦截器中执行耗时操作
问题:拦截器会在每次请求时执行,阻塞后续流程。
优化方案:
- 将数据库查询等耗时操作移到Service层,使用异步处理。
- 使用Redis缓存权限数据,减少DB访问。
2 使用注解方式代替路径匹配
场景:有些接口需要认证,有些不需要,路径匹配导致配置复杂。
做法:自定义注解@LoginRequired,在拦截器中检查方法上是否有该注解:
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod method = (HandlerMethod) handler;
LoginRequired annotation = method.getMethodAnnotation(LoginRequired.class);
if (annotation != null) {
// 需要登录的接口,执行校验逻辑
}
}
return true;
}
}
3 拦截器是单例的
影响:多个请求共享同一个拦截器实例,注意不要在拦截器中定义可变的成员变量(除非使用ThreadLocal)。
总结与扩展
拦截器还能做什么?
- 接口防重复提交:在拦截器中检查请求是否在短时间内重复。
- 国际化处理:根据请求头中的语言设置响应内容。
- 请求/响应加密:在
postHandle中对响应体加密,在preHandle中对请求解密。
推荐学习资源
- 官方文档:Spring Framework Reference Documentation → Web on Servlet Stack → Interceptors
- 实战项目:GitHub搜索“spring-boot-interceptor-example”
- 进阶阅读:《Spring实战(第6版)》第8章“处理Web请求”
最后提示:拦截器配置成功后,记得写单元测试验证路径匹配是否正确,使用MockMvc可以模拟请求并检查拦截器行为。
核心心法:拦截器是Spring MVC提供给开发者的一道“网”,你可以决定哪些请求通过,哪些被过滤,配置时牢记“先注册,后排除;注解优先,路径辅助;单例谨慎,异步优秀”,掌握它,你的Java Web应用将更健壮、更安全。