概述
总的来说不管是过滤器还是拦截器,他们都是用来拦截请求,并且做一些自己想要特殊处理。其本质都是AOP的提现。但是他们的实现方式、作用范围和处理的时机都不太一样。来看一个比较粗略的图:
在请求到达容器前,首先会进入Filter过滤器链,执行完过滤器链上每个Filter.doFilter()方法后,进入Servlet.service()方法,然后由dispatcher分发器将请求方法给对应映射成功的处理器controller,在进入controller具体方法之前,会被先进入Interceptor.preHandler()方法,然后再进入controller的具体返回,执行之后进入Interceptor.postHandler()这里主要是拦截了controller方法执行之后到返回的数据模型到达视图解析器之前,接着进入Interceptor.afterCompletion()方法,主要可以操作返回客户端之前的逻辑,最后返回到过滤链中各个Filter的调用点,可以处理返回到客户端的跳转等逻辑。下面是一个更为详细的执行流程图:
过滤器(Filter)
1. 过滤器定义
一个实现了特殊接口(Filter)的Java类,实现对请求资源(jsp、servlet、html)的过滤功能。过滤器是一个运行在服务器的程序,优先于请求资源(jsp、servlet、html)之前执行, 过滤器是javaweb技术中最为实用的技术之一。
2. 过滤器的应用场景
由于过滤器是在目标资源(Servlet,jsp)之前执行,所以比较适合的应用场景有:登录权限检查、解决乱码、敏感字符过滤等场景。
3. Filter接口方法
-
init()
该方法在容器启动初始化过滤器时被调用,它在 Filter 的整个生命周期只会被调用一次,这个方法必须执行成功,否则过滤器会不起作用。
-
doFilter()
容器中的每一次请求都会调用该方法, FilterChain 用来调用下一个过滤器 Filter。
-
destroy()
当容器销毁 过滤器实例时调用该方法,一般在方法中销毁或关闭资源,在过滤器 Filter 的整个生命周期也只会被调用一次。
4. 过滤器示例
-
Filter类
public class MyFilter1 implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("MyFilter1初始化方法"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("MyFilter1,客户端请求被拦截了"); chain.doFilter(request, response); System.out.println("MyFilter1,返回客户端的信息被拦截了"); } @Override public void destroy() { System.out.println("MyFilter1销毁方法"); } }这里可以再有一个MyFilter2类,可以用于观察多个过滤的前后执行顺序
-
配置web.xml
<!-- 配置两个过滤器,执行循序与配置的前后顺序有关 --> <filter> <filter-name>myFilter1</filter-name> <filter-class>com.mayuanfei.filter.MyFilter1</filter-class> </filter> <filter-mapping> <filter-name>myFilter1</filter-name> <!-- /*是对所有的文件进行拦截 --> <url-pattern>/*</url-pattern> </filter-mapping> <filter> <filter-name>myFilter2</filter-name> <filter-class>com.mayuanfei.filter.MyFilter2</filter-class> </filter> <filter-mapping> <filter-name>myFilter2</filter-name> <!-- /*是对所有的文件进行拦截 --> <url-pattern>/*</url-pattern> </filter-mapping>这里可以把myFilter2和myFilter1的配置顺序调整下,然后观察
-
测试Controller
@RestController public class MyController { @RequestMapping("/test") public UserInfo test() { UserInfo userInfo = new UserInfo(); userInfo.setUserid("1111"); userInfo.setUsername("张三"); userInfo.setAge(28); System.out.println(userInfo); return userInfo; } } -
观察请求
拦截器(Interceptor)
1. 拦截器定义
Spring MVC拦截器是一种用于拦截HTTP请求和响应的机制。它可以在请求到达控制器之前或响应返回客户端之前执行一些操作,是一种应用于业务处理的AOP技术。
需要实现HandlerInterceptor接口或者继承HandlerInterceptorAdapter类
2. 拦截器的应用场景
基本Filter的场景它也都适用,比如:记录日志、权限验证、设置字符编码等操作
3. 拦截器的核心API
SpringMVC拦截器提供三个方法分别是preHandle、postHandle、afterCompletion,我们就是通过这几个方法来对用户的请求进行拦截处理的。
- preHandle() :这个方法将在请求处理之前进行调用。「注意」:如果该方法的返回值为false ,将视为当前请求结束,不仅自身的拦截器会失效,还会导致其他的拦截器也不再执行。
- postHandle():只有在 preHandle() 方法返回值为true 时才会执行。会在Controller 中的方法调用之后,DispatcherServlet 返回渲染视图之前被调用。「有意思的是」:postHandle() 方法被调用的顺序跟 preHandle() 是相反的,先声明的拦截器 preHandle() 方法先执行,而postHandle()方法反而会后执行。
- afterCompletion():只有在 preHandle() 方法返回值为true 时才会执行,在整个请求结束之后, DispatcherServlet 渲染了对应的视图之后执行。
4. 拦截器示例
-
Interceptor类
public class MyInterceptor1 implements HandlerInterceptor { @Resource private LogMapper logMapper; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("MyInterceptor1的preHandle执行"); // 返回true代表放行,可以继续到handler;否则无法执行我们的handler方法. return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("MyInterceptor1的postHandle执行"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("MyInterceptor1的afterCompletion执行"); // 插入日志 this.logMapper.insertLog(); } }这里可以再有一个MyInterceptor2类,可以用于观察多个过滤的前后执行顺序
-
配置 springmvc.xml
<!--注册拦截器--> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean id="myInterceptor1" class="com.mayuanfei.interceptor.MyInterceptor1"></bean> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/**"/> <bean id="myInterceptor2" class="com.mayuanfei.interceptor.MyInterceptor2"></bean> </mvc:interceptor> </mvc:interceptors> -
观察请求
过滤器和拦截器的区别
- Filter是servlet的规范;而Interceptor是由spring框架支持的
- 正是由于Interceptor由spring框架支持,所以能在拦截器中很容易的注入各种对象;但在Filter中不行。
- Interceptor在其生命周期中,几个方法可以多次被调用;Filter除了doFilter,只能在容器初始化调用一次。
- Filter只能在servlet的前后起作用,而拦截器能在方法前后异常前后执行,更加灵活,粒度更小
代码地址
gitee.com/mayuanfei/s…下的springmvc03
记忆印记
- 过滤器时Servlet规范中的;拦截器是spring框架中的
- 过滤器中获得Spring框架容器中的对象很费劲;而拦截器很方便
- 过滤器是在拦截器前执行的,这意味着过滤器处理过的对象,在拦截器中可以直接使用。
- 过滤器和拦截器都以配置的前后,顺序执行的。