摘自: http://blog.csdn.net/xiaoyaotan_111/article/details/53817918

一 简介

(1)过滤器:

依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,获取我们想要获取的数据,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等

关于过滤器的一些用法可以参考我写过的这些文章

  • 继承HttpServletRequestWrapper以实现在Filter中修改HttpServletRequest的参数:https://www.zifangsky.cn/677.html

  • 在SpringMVC中使用过滤器(Filter)过滤容易引发XSS的危险字符:https://www.zifangsky.cn/683.html

(2)拦截器:

依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理

关于过滤器的一些用法可以参考我写过的这些文章:

  • 在SpringMVC中使用拦截器(interceptor)拦截CSRF攻击(修):https://www.zifangsky.cn/671.html

  • SpringMVC中使用Interceptor+cookie实现在一定天数之内自动登录:https://www.zifangsky.cn/700.html

二 多个过滤器与拦截器的代码执行顺序

如果在一个项目中仅仅只有一个拦截器或者过滤器,那么我相信相对来说理解起来是比较容易的。但是我们是否思考过:如果一个项目中有多个拦截器或者过滤器,那么它们的执行顺序应该是什么样的?或者再复杂点,一个项目中既有多个拦截器,又有多个过滤器,这时它们的执行顺序又是什么样的呢?

下面我将用简单的代码来测试说明:

(1)先定义两个过滤器:

i)过滤器1:

  1. <a target="_blank" href="http://www.07net01.com/tags-package-0.html" class="infotextkey" style="background:transparent; color:rgb(66,139,202)">package</a> cn.zifangsky.filter;
  2. import java.io.IOException;
  3. import javax.servlet.FilterChain;
  4. import javax.servlet.ServletException;
  5. import javax.servlet.http.HttpServletRequest;
  6. import javax.servlet.http.HttpServletResponse;
  7. import org.springframework.web.filter.OncePerRequestFilter;
  8. public class TestFilter1 extends OncePerRequestFilter {
  9. protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
  10. throws ServletException, IOException {
  11. //在DispatcherServlet之前执行
  12. <a target="_blank" href="http://www.07net01.com/tags-system-0.html" class="infotextkey" style="background:transparent; color:rgb(66,139,202)">system</a>.out.println("############TestFilter1 doFilterInternal executed############");
  13. filterChain.doFilter(request, response);
  14. //在视图页面返回给<a target="_blank" href="http://www.07net01.com/tags-%E5%AE%A2%E6%88%B7%E7%AB%AF-0.html" class="infotextkey" style="background:transparent; color:rgb(66,139,202)">客户端</a>之前执行,但是执行顺序在Interceptor之后
  15. System.out.println("############TestFilter1 doFilter after############");
  16. //      try {
  17. //          Thread.sleep(10000);
  18. //      } catch (InterruptedException e) {
  19. //          e.printStackTrace();
  20. //      }
  21. }
  22. }

ii)过滤器2:

  1. package cn.zifangsky.filter;
  2. import java.io.IOException;
  3. import javax.servlet.FilterChain;
  4. import javax.servlet.ServletException;
  5. import javax.servlet.http.HttpServletRequest;
  6. import javax.servlet.http.HttpServletResponse;
  7. import org.springframework.web.filter.OncePerRequestFilter;
  8. public class TestFilter2 extends OncePerRequestFilter {
  9. protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
  10. throws ServletException, IOException {
  11. System.out.println("############TestFilter2 doFilterInternal executed############");
  12. filterChain.doFilter(request, response);
  13. System.out.println("############TestFilter2 doFilter after############");
  14. }
  15. }

iii)在web.xml中注册这两个过滤器:

  1. <!-- 自定义过滤器:testFilter1 -->
  2. <filter>
  3. <filter-name>testFilter1</filter-name>
  4. <filter-class>cn.zifangsky.filter.TestFilter1</filter-class>
  5. </filter>
  6. <filter-mapping>
  7. <filter-name>testFilter1</filter-name>
  8. <url-pattern>/*</url-pattern>
  9. </filter-mapping>
  10. <!-- 自定义过滤器:testFilter2 -->
  11. <filter>
  12. <filter-name>testFilter2</filter-name>
  13. <filter-class>cn.zifangsky.filter.TestFilter2</filter-class>
  14. </filter>
  15. <filter-mapping>
  16. <filter-name>testFilter2</filter-name>
  17. <url-pattern>/*</url-pattern>
  18. </filter-mapping>

(2)再定义两个拦截器:

i)拦截器1,基本拦截器:

  1. package cn.zifangsky.interceptor;
  2. import javax.servlet.http.HttpServletRequest;
  3. import javax.servlet.http.HttpServletResponse;
  4. import org.springframework.web.servlet.HandlerInterceptor;
  5. import org.springframework.web.servlet.ModelAndView;
  6. public class BaseInterceptor implements HandlerInterceptor{
  7. /**
  8. * 在DispatcherServlet之前执行
  9. * */
  10. public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
  11. System.out.println("************BaseInterceptor preHandle executed**********");
  12. return true;
  13. }
  14. /**
  15. * 在controller执行之后的DispatcherServlet之后执行
  16. * */
  17. public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
  18. throws Exception {
  19. System.out.println("************BaseInterceptor postHandle executed**********");
  20. }
  21. /**
  22. * 在页面渲染完成返回给客户端之前执行
  23. * */
  24. public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
  25. throws Exception {
  26. System.out.println("************BaseInterceptor afterCompletion executed**********");
  27. //      Thread.sleep(10000);
  28. }
  29. }

ii)指定controller请求的拦截器:

  1. package cn.zifangsky.interceptor;
  2. import javax.servlet.http.HttpServletRequest;
  3. import javax.servlet.http.HttpServletResponse;
  4. import org.springframework.web.servlet.HandlerInterceptor;
  5. import org.springframework.web.servlet.ModelAndView;
  6. public class TestInterceptor implements HandlerInterceptor {
  7. public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
  8. System.out.println("************TestInterceptor preHandle executed**********");
  9. return true;
  10. }
  11. public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
  12. throws Exception {
  13. System.out.println("************TestInterceptor postHandle executed**********");
  14. }
  15. public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
  16. throws Exception {
  17. System.out.println("************TestInterceptor afterCompletion executed**********");
  18. }
  19. }

iii)在SpringMVC的配置文件中注册这两个拦截器:

  1. <!-- 拦截器 -->
  2. nbsp;   <mvc:interceptors>
  3. <!-- 对所有请求都拦截,公共拦截器可以有多个 -->
  4. <bean name="baseInterceptor" class="cn.zifangsky.interceptor.BaseInterceptor" />
  5. <!-- <bean name="testInterceptor" class="cn.zifangsky.interceptor.TestInterceptor" /> -->
  6. <mvc:interceptor>
  7. <!-- 对/test.html进行拦截 -->
  8. <mvc:mapping path="/test.html"/>
  9. <!-- 特定请求的拦截器只能有一个 -->
  10. <bean class="cn.zifangsky.interceptor.TestInterceptor" />
  11. </mvc:interceptor>
  12. </mvc:interceptors>

(3)定义一个测试使用的controller:

  1. package cn.zifangsky.controller;
  2. import org.springframework.stereotype.Controller;
  3. import org.springframework.web.bind.annotation.RequestMapping;
  4. import org.springframework.web.servlet.ModelAndView;
  5. @Controller
  6. public class TestController {
  7. @RequestMapping("/test.html")
  8. public ModelAndView handleRequest(){
  9. System.out.println("---------TestController executed--------");
  10. return new ModelAndView("test");
  11. }
  12. }

(4)视图页面test.jsp:

  1. <%@ page language="java" contentType="text/html; charset=UTF-8"
  2. pageEncoding="UTF-8"%>
  3. <%
  4. String path = request.getContextPath();
  5. String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
  6. %>
  7. <html>
  8. <head>
  9. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  10. <base href="http://983836259.blog.51cto.com/7311475/">
  11. <title>FilterDemo</title>
  12. </head>
  13. <body>
  14. <%
  15. System.out.println("test.jsp is loading");
  16. %>
  17. <div align="center">
  18. This is test page
  19. </div>
  20. </body>
  21. </html>

(5)测试效果:

启动此测试项目,可以看到控制台中输出如下:

这就说明了过滤器的运行是依赖于servlet容器的,跟springmvc等框架并没有关系。并且,多个过滤器的执行顺序跟xml文件中定义的先后关系有关

接着清空控制台中的输出内容并访问:http://localhost:9180/FilterDemo/test.html

可以看到,此时的控制台输出结果如下:

相信从这个打印输出,大家就可以很清晰地看到有多个拦截器和过滤器存在时的整个执行顺序了。当然,对于过个拦截器它们之间的执行顺序跟在SpringMVC的配置文件中定义的先后顺序有关

注:对于整个SpringMVC的执行流程来说,如果加上上面的拦截器和过滤器,其最终的执行流程就如下图所示:

 
7

0
 
 
 
查看评论
4楼 SHENZHOUCHEN912017-07-16 17:02发表 [回复]
最后一张图 Interceptor PreHandler位置 是不是应该在 Dispatcher后面?
3楼 正怒月神2017-05-23 10:08发表 [回复]
通俗易懂,赞一个
2楼 wkk1234532017-05-09 10:17发表 [回复]
很好,如果能针对拦截器preHandle返回参数(true or false)再作详细说明就更好了
1楼 lee_1262017-03-27 14:09发表 [回复]
很好!

SpringMVC的拦截器(Interceptor)和过滤器(Filter)的区别与联系的更多相关文章

  1. 拦截器Interceptor和过滤器Filter的区别

    (1)过滤器(Filter):当你有一堆东西的时候,你只希望选择符合你要求的某一些东西.定义这些要求的工具,就是过滤器.(理解:就是一堆字母中取一个B) (2)拦截器(Interceptor):在一个 ...

  2. SSM-SpringMVC-33:SpringMVC中拦截器Interceptor讲解

     ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 拦截器Interceptor: 对处理方法进行双向的拦截,可以对其做日志记录等 我选择的是实现Handler ...

  3. Java过滤器(Filter)与SpringMVC拦截器(Interceptor)之间的关系与区别

    过滤器和拦截器的区别: ①拦截器是基于java的反射机制的,而过滤器是基于函数回调. ②拦截器不依赖与servlet容器,过滤器依赖与servlet容器. ③拦截器只能对action请求起作用,而过滤 ...

  4. struts2的拦截器(Interceptor)与过滤器(Filter)

    一.拦截器与过滤器的区别: 1.filter基于回调函数,我们需要实现的filter接口中doFilter方法就是回调函数,而interceptor则基于Java本身的反射机制,这是两者最本质的区别. ...

  5. SpringMVC处理器拦截器 Interceptor

    拦截器概念 Java 里的拦截器是动态拦截action调用的对象.它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行,同时也提供了一种 ...

  6. java 过滤器(Filter)与springMVC 拦截器(interceptor)的实现案例

    java 过滤器Filter: package com.sun.test.aircraft.filter;import javax.servlet.*;import java.io.IOExcepti ...

  7. 过滤器(Filter)和拦截器(Interceptor)

    过滤器(Filter) Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序.它依赖于servlet容器,在实现上,基于函数回调,它可以对几乎所有请求 ...

  8. 二十五、过滤器Filter,监听器Listener,拦截器Interceptor的区别

    1.Servlet:运行在服务器上可以动态生成web页面.servlet的声明周期从被装入到web服务器内存,到服务器关闭结束.一般启动web服务器时会加载servelt的实例进行装入,然后初始化工作 ...

  9. Spring filter和拦截器(Interceptor)的区别和执行顺序

    转载自:http://listenup.iteye.com/blog/1559553 1.Filter过滤器只过滤jsp文件不过滤action请求解决方案 解决办法:在web.xml中将filter的 ...

  10. Java 中的过滤器Filter 和拦截器 Interceptor

    1.先说拦截器 Interceptor 本项目以springboot为例: 新建 InterceptorConfig package com.opendev.mystudy.MyInterceptor ...

随机推荐

  1. BZOJ4237 稻草人 分治 单调栈

    原文链接https://www.cnblogs.com/zhouzhendong/p/8682572.html 题目传送门 - BZOJ4237 题意 平面上有$n(n\leq 2\times 10^ ...

  2. 020000——00001_使用 PyCharm

    1.快速上手的中文视频 简单介绍了如何安装.如何创建文件.如何设置皮肤. http://v.youku.com/v_show/id_XODMyMzM1NzQ4.html 2.Pychram 官方的快速 ...

  3. python面试题之python下多线程的限制

    python多线程有个全局解释器锁(global interpreter lock). 这个锁的意思是任一时间只能有一个线程使用解释器,跟单cpu跑多个程序一个意思,大家都是轮着用的,这叫“并发”,不 ...

  4. LoadRunner脚本参数化之自动关联和手动关联

    一.关联的意义  1.关联的含义 关联(correlation):在脚本回放过程中,客户端发出请求,通过关联函数所定义的左右边界值(也就是关联规则),在服务器所响应的内容中查找,得到相应的值,以变量的 ...

  5. Python编程基础[函数和面向对象](三)

    Python 函数 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率.你已经知道Python提供了许多内建函数,比如print().但你也 ...

  6. 总结mysql的三种外键约束方式

    如果表A的主关键字是表B中的字段,则该字段称为表B的外键,表A称为主表,表B称为从表.外键是用来实现参照完整性的,不同的外键约束方式将可以使两张表紧密的结合起来,特别是修改或者删除的级联操作将使得日常 ...

  7. ECMAScript6 入门 Module

    目的:将大程序拆分成互相依赖的小模块文件.CommonJS 和 AMD 两种,前者用于服务器,后者用于浏览器.他俩都是运行时才确定 :ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖 ...

  8. 003.MySQL高可用主从复制新增slave

    一 基础环境 主机名 系统版本 MySQL版本 主机IP master CentOS 6.8 MySQL 5.6 172.24.8.10 slave01 CentOS 6.8 MySQL 5.6 17 ...

  9. 利用"SQL"语句自动生成序号的两种方式

    1.首先,我们来介绍第一种方式: ◆查询的SQL语句如下: select row_number() over (order by name) as rowid, sysobjects.[id] fro ...

  10. 直接存储器存取(Direct Memory Access,DMA)详细讲解

    一.理论理解部分. 1.直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输. 2.无须CPU干预,数据可以通过DMA快速移动,这就节省了CPU的资源来做其他操作. ...