摘自: 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. 利用vcard和qrcode.js生成二维码导入联系人

    vCard是一种容许交换个人信息的数据规范,vCard数据格式的标识符是VCARD,vCard数据格式行是: 类型 [;参数]:值,具体的介绍百度都有,我们可以通过vcard来进行通讯录的保存,名片的 ...

  2. django 文件下载

    1. 最简单下载:将文件流放入HttpResponse对象即可,适合小文件的下载,但如果这个文件非常大,这种方式会占用大量. 如: def file_download(request): # do s ...

  3. Django项目和Django初体验和创建、目录结构认识

    .MVC的设计方式(跟Flask一样,都是MVC的设计模式) .开发效率高 .功能强大(丰富的第三方组件) .安全性高(帮助开发者规避安全漏洞) 目前市面上使用:Django>Flask #使用 ...

  4. BZOJ3295 [Cqoi2011]动态逆序对 分治 树状数组

    原文链接http://www.cnblogs.com/zhouzhendong/p/8678185.html 题目传送门 - BZOJ3295 题意 对于序列$A$,它的逆序对数定义为满足$i< ...

  5. BZOJ2212 [Poi2011]Tree Rotations 线段树合并 逆序对

    原文链接http://www.cnblogs.com/zhouzhendong/p/8079786.html 题目传送门 - BZOJ2212 题意概括 给一棵n(1≤n≤200000个叶子的二叉树, ...

  6. Python交互图表可视化Bokeh:5 柱状图| 堆叠图| 直方图

    柱状图/堆叠图/直方图 ① 单系列柱状图② 多系列柱状图③ 堆叠图④ 直方图 1.单系列柱状图 import numpy as np import pandas as pd import matplo ...

  7. 在jsp页面上方定义<style> 可以自定义class的样式

    <style>.border-orange{ border:1px solid orange; width:120px; box-sizing: border-box; margin-bo ...

  8. java、python与留下迷点的php hash collision

    JAVA 生成java的碰撞数据比较简单 根据网上资料可知: at,bU,c6的在java中的hash值是相同的 则可以根据这三个不断做 笛卡尔积 简单明了就是做字符串拼接. 举个例子 把A当做at, ...

  9. Service Discovery And Health Checks In ASP.NET Core With Consul

    在这篇文章中,我们将快速了解一下服务发现是什么,使用Consul在ASP.NET Core MVC框架中,并结合DnsClient.NET实现基于Dns的客户端服务发现 这篇文章的所有源代码都可以在G ...

  10. 大数据技术 - MapReduce的Combiner介绍

    本章来简单介绍下 Hadoop MapReduce 中的 Combiner.Combiner 是为了聚合数据而出现的,那为什么要聚合数据呢?因为我们知道 Shuffle 过程是消耗网络IO 和 磁盘I ...