拦截器是 Spring MVC 框架的组件,基于 AOP(面向切面编程) 实现。它允许在请求处理的不同阶段(如Controller方法执行前后)插入自定义逻辑。
过滤器是 Java Servlet规范 定义的组件,作用于所有进入容器的请求(如Tomcat)。它可以在请求到达Servlet前或响应返回客户端前进行预处理和后处理。
特性 | 拦截器(Interceptor) | 过滤器(Filter) |
---|---|---|
所属框架 | Spring MVC | Servlet API |
作用范围 | 仅Spring MVC管理的请求 | 所有请求(包括静态资源) |
依赖 | 依赖Spring容器 | 依赖Servlet容器(如Tomcat) |
执行时机 | Controller方法前后 | Servlet处理前后 |
获取Bean | 支持(通过Spring上下文) | 不支持(需通过其他方式注入) |
步骤:
HandlerInterceptor
接口,重写以下方法:
preHandle()
:在Controller方法执行前调用。postHandle()
:在Controller方法执行后、视图渲染前调用。afterCompletion()
:在请求完成后调用(视图渲染后)。代码示例:
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 检查用户是否登录
if (request.getSession().getAttribute("user") == null) {
response.sendRedirect("/login");
return false; // 中断请求
}
return true;
}
}
注册拦截器:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/login", "/static/**");
}
}
注册多个拦截器:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 第一个拦截器:日志(优先级高)
registry.addInterceptor(new LogInterceptor())
.addPathPatterns("/**") // 拦截所有路径
.excludePathPatterns("/static/**"); // 排除静态资源
// 第二个拦截器:权限(优先级低)
registry.addInterceptor(new AuthInterceptor())
.addPathPatterns("/api/**"); // 仅拦截/api路径
}
}
关键配置选项
配置方法 | 说明 |
---|---|
addPathPatterns("/api") |
指定拦截的路径(支持Ant风格) |
excludePathPatterns("/login") |
排除特定路径 |
order(1) |
显式设置顺序(默认按注册顺序) |
若要手动指定顺序,可添加:
registry.addInterceptor(new LogInterceptor()).order(1);
registry.addInterceptor(new AuthInterceptor()).order(2);
步骤:
javax.servlet.Filter
接口,重写 doFilter
方法。代码示例:
@WebFilter(urlPatterns = "/*")
public class LoggingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("请求开始: " + ((HttpServletRequest) request).getRequestURI());
chain.doFilter(request, response); // 继续执行后续过滤器或Servlet
System.out.println("请求结束");
}
}
注册过滤器(若未使用@WebFilter):
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<LoggingFilter> loggingFilter() {
FilterRegistrationBean<LoggingFilter> bean = new FilterRegistrationBean<>();
bean.setFilter(new LoggingFilter());
bean.addUrlPatterns("/*");
bean.setOrder(1); // 设置执行顺序
return bean;
}
}
注意: 确保主类添加 @ServletComponentScan
以启用 @WebFilter
注解。
客户端 → Filter.doFilter() → Interceptor.preHandle()
→ Controller → Interceptor.postHandle()
→ 视图渲染 → Interceptor.afterCompletion()
→ Filter.doFilter()后续处理 → 客户端
registry.addInterceptor()
的顺序决定。FilterRegistrationBean.setOrder()
设置优先级(值越小越先执行)。直接从Spring容器注入:
public class AuthInterceptor implements HandlerInterceptor {
@Autowired
private UserService userService; // 直接注入
}
通过自定义 HttpServletRequestWrapper
:
public class ModifyRequestWrapper extends HttpServletRequestWrapper {
// 重写getParameter等方法以修改参数
}
// 在Filter中替换Request对象
chain.doFilter(new ModifyRequestWrapper(request), response);
afterCompletion
中处理异常。try-catch
包裹 chain.doFilter()
。使用 addPathPatterns("/**")
:
registry.addInterceptor(new LogInterceptor())
.addPathPatterns("/**");
在 preHandle
中返回 false
:
@Override
public boolean preHandle(...) {
if (跳过条件) {
return false; // 后续拦截器和Controller不会执行
}
return true;
}
通过 request.setAttribute
传递:
// 在第一个拦截器中存储数据
request.setAttribute("key", "value");
// 在后续拦截器中获取
String value = (String) request.getAttribute("key");
选择拦截器还是过滤器?
最佳实践: