前言
Spring框架中的拦截器(Interceptor)和过滤器(Filter)是用于处理请求和响应的不同机制,但它们在Spring中的角色和实现方式有所不同。
1)过滤器(Filter):
-
角色:Filter 是 Servlet 规范中定义的组件,用于在 Servlet 容器处理请求和响应之前或之后拦截这些请求和响应。
-
实现:Filter 实现了 javax.servlet.Filter 接口,并在 web.xml 中配置或使用注解进行声明。
-
实例代码:
@WebFilter(filterName = "exampleFilter", urlPatterns = "/*")
public class ExampleFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 初始化代码
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 在请求处理前执行的逻辑
chain.doFilter(request, response); // 传递请求到下一个过滤器或目标资源
// 在请求处理后执行的逻辑
}
@Override
public void destroy() {
// 销毁代码
}
}
2)拦截器(Interceptor):
-
角色:Interceptor 是 Spring MVC 框架中的组件,用于在控制器方法处理之前、处理中和处理后添加行为。
-
实现:Interceptor 实现了 org.springframework.web.servlet.HandlerInterceptor 接口,并在 Spring 配置中注册。
-
实例代码:
public class ExampleInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 在请求处理前执行的逻辑
return true; // 继续请求处理
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// 在请求处理后模型视图返回前执行的逻辑
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) throws Exception {
// 在完全处理完请求后执行的逻辑
}
}
在 Spring 配置中注册拦截器:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new ExampleInterceptor());
}
}
过滤器和拦截器的主要区别在于它们的实现方式和它们在请求处理生命周期中的位置:
-
Filter 在 Servlet 容器中工作,而拦截器是在 Spring MVC 框架中工作。
-
Filter 依赖于 Servlet 容器,而拦截器不依赖于 Servlet 容器,可以在任何 Servlet 或 Spring 应用程序中使用。
-
Filter 可以拦截所有类型的请求,而拦截器只能拦截发送到 Spring MVC 控制器的请求。
-
Filter 可以访问原始的 ServletRequest 和 ServletResponse,而拦截器只能访问包装过的 HttpServletRequest 和 HttpServletResponse。
过滤器的定义
过滤器是JavaWeb的三大组件之一,是实现Filter接口的Java类。
过滤器是实现对请求资源(jsp、servlet、html)的过滤功能,是一个运行在服务器的程序,优先于请求资源(jsp、servlet、html)之前执行。
当浏览器发送请求给服务器的时候,先执⾏过滤器,然后才访问Web的资源。服务器响应Response,从Web资源抵达浏览器之前,也会途径过滤器。
在很多Web开发中,都会用到过滤器(Filter),如参数过滤、防止SQL注入、防止页面攻击、过滤敏感字符、解决网站乱码、空参数矫正、Token验证、Session验证、点击率统计等。
代码案例
在启动类添加一个注解,找到定义的拦截器
@ServletComponentScan(basePackages = "com.binlog.study.filter")
写一个过滤器,实现Filter
@Slf4j
@Order(1) //如果有多个Filter,则序号越小,越早被执行
//@Component//无需添加此注解,在启动类添加@ServletComponentScan注解后,会自动将带有@WebFilter的注解进行注入!
//这里的urlPatterns为接口里的路径过滤条件
@WebFilter(filterName = "timeFilter", urlPatterns = "/api/filter/*")
public class TimeFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("初始化过滤器:{}", filterConfig.getFilterName());
}
@Override
public void destroy() {
log.info("销毁过滤器");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
log.info("开始执行");
long startTime = System.currentTimeMillis();
filterChain.doFilter(servletRequest, servletResponse);
long endTime = System.currentTimeMillis();
log.info("请求:{},耗时:{}ms", getUrlFrom(servletRequest), (endTime - startTime));
log.info("结束执行");
}
private String getUrlFrom(ServletRequest servletRequest) {
if (servletRequest instanceof HttpServletRequest) {
return ((HttpServletRequest) servletRequest).getRequestURL().toString();
}
return "";
}
}
拦截器的定义
SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦截器来实现特定的功能。
拦截器它是链式调用,一个应用中可以同时存在多个拦截器Interceptor,一个请求也可以触发多个拦截器,而每个拦截器的调用会依据它的声明顺序依次执行。
拦截器的核心API
SpringMVC拦截器提供三个方法分别是preHandle、postHandle、afterCompletion,我们就是通过重写这几个方法来对用户的请求进行拦截处理的。
- preHandle() :这个方法将在请求处理之前进行调用。如果该方法的返回值为false ,将视为当前请求结束,不仅自身的拦截器会失效,还会导致其他的拦截器也不再执行。
- postHandle():只有在 preHandle() 方法返回值为true 时才会执行。会在Controller 中的方法调用之后,DispatcherServlet 返回渲染视图之前被调用。postHandle() 方法被调用的顺序跟 preHandle() 是相反的,先声明的拦截器 preHandle() 方法先执行,而postHandle()方法反而会后执行。
- afterCompletion():只有在 preHandle() 方法返回值为true 时才会执行,在整个请求结束之后, DispatcherServlet 渲染了对应的视图之后执行。
Interceptor 的应用场景:
-
日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算 PV(Page View)等;
-
权限检查:如登录检测,进入处理器检测是否登录;
-
性能监控:通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间。(反向代理,如 Apache 也可以自动记录)
-
通用行为:读取 Cookie 得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取 Locale、Theme 信息等,只要是多个处理器都需要的即可使用拦截器实现。