文章目录
一、先说结论
1.拦截器Interceptor与过滤器Filter的区别
《JAVA编程思想》截图
两者最大的区别在于:过滤器是在 Servlet 规范中定义的,是由 Servlet 容器支持的;拦截器是在 Spring 容器内的,由 Spring 框架支持。
因此,作为 Spring 的一个组件,拦截器可以通过IOC容器进行管理,获取其中的各个 bean 实例,对 spring 中的各种资源、对象,如 Service 对象、数据源、事务管理等进行调用;而过滤器则不能。
总的来说,两者主要在如下方面存在着差异 :
- 过滤器是基于函数的回调,而拦截器是基于 Java 反射机制的
- 过滤器可以修改 request,而拦截器则不能(待证,Intercepter的preHandle可以向request添加attribute,不知道这个结论是否是个人的理解错了)
- 过滤器需要在 servlet 容器中实现,拦截器可以适用于 JavaEE、JavaSE 等各种环境
- 拦截器可以调用 IOC 容器中的各种依赖,而过滤器不能
- 过滤器只能在请求的前后使用,而拦截器可以详细到每个方法
2.拦截器链与过滤器链的执行顺序
Filter 链执行顺序
1.根据web.xml中配置的顺序决定过滤器的先后关系
2.在doFilter方法中,位于FilterChain.doFilter方法之前的代码先于Servlet执行
3.位于FilterChain.doFilter方法之后的代码在Servlet执行之后执行
Interceptor 执行顺序
1.根据springmvc.xml中配置的顺序决定拦截器的先后关系
3.拦截器与过滤器的执行时机
过滤器先于拦截器执行
4.拦截器与过滤器的适用场景
拦截器Interceptor
- 日志记录 :几率请求信息的日志,以便进行信息监控、信息统计等等
- 权限检查 :对用户的访问权限,认证,或授权等进行检查
- 性能监控 :通过拦截器在进入处理器前后分别记录开始时间和结束时间,从而得到请求的处理时间
- 通用行为 :读取 cookie 得到用户信息并将用户对象放入请求头中,从而方便后续流程使用
过滤器Filter
为shiro权限过滤器,编码过滤器,微信接口过滤器,上传文件过滤器等。
二、拦截器与过滤器的使用及验证
1.配置Filter
新建TestFilter类,实现过滤器中的逻辑
package com.framework;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
@author sunhongmin 2019-12-19
Filter执行类,实现Filter接口,覆写init、doFilter、destory方法
*/
public class TestFilter implements Filter{
@Override
public void destroy() {
//Filter销毁
//web容器调用destroy方法销毁Filter。destroy方法在Filter的生命周期中仅执行一次。在destroy方法中,可以释放过滤器使用的资源。
System.out.println("Filter1 destroy");
}
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
throws IOException, ServletException {
//Filter 先拦截request, doFilter放行, response响应回来, Filter再次拦截 ,执行doFilter()后面的代码
//arg0.setAttribute("key0", "from Filter doFilter");
System.out.println("Filter1 doFilter1");//doFilter之前的代码,用于对请求进行处理
arg2.doFilter(arg0, arg1);
System.out.println("Filter1 doFilter2");//doFilter之后的代码,用于对请求响应进行处理
}
@Override
public void init(FilterConfig arg0) throws ServletException {
//Filter初始化
// web应用程序启动时,web服务器将创建Filter的实例对象,并调用其init方法,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作,filter对象只会创建一次,init方法也只会执行一次。通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象。
System.out.println("Filter1 init");
}
}
在web.xml配置过滤器名称,过滤路径与class路径,拦截所有请求
<!--配置过滤器-->
<filter>
<filter-name>FilterTest</filter-name>
<filter-class>com.framework.TestFilter</filter-class>
</filter>
<!--映射过滤器-->
<filter-mapping>
<filter-name>FilterTest</filter-name>
<!--“/*”表示拦截所有的请求 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
2.配置Interceptor
新建TestInterceptor拦截器类,实现HandlerInterceptor接口
package com.framework;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class TestIntercepter implements HandlerInterceptor{
/**
* preHandle
调用时间:Controller方法处理之前
执行顺序:链式Intercepter情况下,Intercepter按照声明的顺序一个接一个执行
若返回false,则中断执行,注意:不会进入afterCompletion
处理参数,校验权限,决定是否继续执行
postHandle
调用前提:preHandle返回true
调用时间:Controller方法处理完之后,DispatcherServlet进行视图的渲染之前,也就是说在这个方法中你可以对ModelAndView进行操作
执行顺序:链式Intercepter情况下,Intercepter按照声明的顺序倒着执行。
备注:postHandle虽然post打头,但post、get方法都能处理
一般可以通过它对 Controller 处理之后的 ModelAndView 对象进行操作。
afterCompletion
调用前提:preHandle返回true
调用时间:DispatcherServlet进行视图的渲染之后
在整个请求处理完成(包括视图渲染)后执行,主要用来进行一些资源的清理工作。
* */
@Override
public void afterCompletion(HttpServletRequest req, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
//System.out.println("key2:-->"+req.getAttribute("key2"));
System.out.println(" Intercepter1 doAfterCompletion...");
}
@Override
public void postHandle(HttpServletRequest req, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
throws Exception {
//System.out.println("key2:-->"+req.getAttribute("key2"));
System.out.println(" Intercepter1 doPostHandle...");
}
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
//arg0.setAttribute("key1", "from intercepter preHandle");
System.out.println(" Intercepter1 doPreHandle...");
return true;
}
}
配置springmvc.xml文件
<mvc:interceptors>
<mvc:interceptor>
<!-- /** 表示拦截所有请求-->
<mvc:mapping path="/**"/>
<!-- 为了排除干扰,将静态资源请求排除,如果前后端分离可以忽略 -->
<mvc:exclude-mapping path="/js/**" />
<mvc:exclude-mapping path="/css/**" />
<mvc:exclude-mapping path="/images/**" />
<bean class="com.framework.TestIntercepter"/>
</mvc:interceptor>
</mvc:interceptors>
3.验证执行顺序
为了查看拦截器与过滤器执行链的总体顺序,加入TestFilter2与TestInterceptor2
web.xml
查看执行结果
总结
Filter只在Servlet前后起作用,而拦截器能够深入到方法前后、异常抛出前后等,因此拦截器的使用具有更大的弹性。所以在spring结构的程序中,要优先使用拦截器。