一 简介

(1)过滤器:

依赖于servlet容器,是JavaEE标准,是在请求进入容器之后,还未进入Servlet之前进行预处理,并且在请求结束返回给前端这之间进行后期处理。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作。过滤器可以简单理解为“取你所想取”,忽视掉那些你不想要的东西,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等

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

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

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

(2)拦截器:

拦截器不依赖与servlet容器,依赖于web框架。在SpringMVC中就是依赖于SpringMVC框架,在SSH框架中,就是依赖于Struts框架。在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于web框架的调用,因此可以使用spring的依赖注入(DI)获取IOC容器中的各个bean,进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是只能对controller请求进行拦截,即⑴请求还没有到controller层时进行拦截,⑵请求走出controller层次,还没有到渲染时图层时进行拦截,⑶结束视图渲染,但是还没有到servlet的结束时进行拦截。对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理,拦截器功在对请求权限鉴定方面确实很有用处。它可以简单理解为“拒你所想拒”。

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

  • 在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" >客户端</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的执行流程来说,如果加上上面的拦截器和过滤器,其最终的执行流程就如下图所示:

大家还可以参考一下这个电子书的截图:

本文转自:http://blog.csdn.net/xiaoyaotan_111/article/details/53817918

spring过滤器和拦截器的区别和联系的更多相关文章

  1. Struts2之过滤器和拦截器的区别

    刚学习Struts2这个框架不久,心中依然有一个疑惑未解那就是过滤器和拦截器的区别,相信也有不少人跟我一样对于这个问题没有太多的深入了解 那么下面我们就一起来探讨探讨 过滤器,是在java web中, ...

  2. Struts2中过滤器和拦截器的区别

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

  3. JavaWeb过滤器.监听器.拦截器-原理&区别-个人总结

    对比项 拦截器 过滤器 机制 反射机制 函数回调 是否依赖servlet容器 是 否 请求处理 只能对action请求起作用 几乎所有的请求起作用 对action处理 可以访问action上下文.值栈 ...

  4. struts2 过滤器和拦截器的区别和使用

    java web 过滤器和拦截器的区别和使用  1.1 什么是拦截器:      拦截器,在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然 ...

  5. JavaWeb过滤器.监听器.拦截器-原理&区别(转)

    1.拦截器是基于java的反射机制的,而过滤器是基于函数回调 2.过滤器依赖与servlet容器,而拦截器不依赖与servlet容器 3.拦截器只能对action请求起作用,而过滤器则可以对几乎所有的 ...

  6. spring boot 过滤器、拦截器的区别与使用

    原文:https://blog.csdn.net/heweimingming/article/details/79993591 拦截器与过滤器的区别: 1.过滤器和拦截器触发时机不一样,过滤器是在请求 ...

  7. spring:过滤器和拦截器

    过滤器:网络通信模型的会话层控制: 拦截器:事务处理的aop注入(生命周期监控). 对于Servlet Filter,官方文档中说的很好, 并且给出了常见的应用场景. A filter is an o ...

  8. struts过滤器和拦截器的区别

    拦截器的工作原理:当接收到一个httprequest ,a) 当外部的httpservletrequest到来时 b) 初始到了servlet容器 传递给一个标准的过滤器链 c) FilterDisp ...

  9. Java Web 中 过滤器与拦截器的区别

    过滤器,是在java web中,你传入的request,response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者struts的 action进行业务逻辑,比如过滤掉非法u ...

随机推荐

  1. [HNOI/AHOI2018]寻宝游戏

    题目大意: $n(n\le1000)$个$m(m\le5000)$位的二进制数,第$0$个数为$0$.用$\wedge$和$\vee$将这些数连接起来.$q(q\le1000)$次询问,每次给定一个$ ...

  2. Problem H: 零起点学算法28——参加程序设计竞赛

    #include<stdio.h> int main() { int a,b; while(scanf("%d %d",&a,&b)!=EOF) ||b ...

  3. 使用Arraylist产生不重复的随机数

    在Java中主要有两种方法来获取随机数,分别是通过Math.random方法和Random类获得随机数,不过Math.random方法其实也是通过生成一个Random类实例,然后再生成随机数的,也就是 ...

  4. 将SeqReader打包成可执行的jar包

    SeqReader是我定义的一个读取SequenceFile文件,并将部分(key,value)打印到控制台窗口的类,其完整代码如下: /** * Created with IntelliJ IDEA ...

  5. SQL Server 事务隔离级别的解析

    近来在项目中遇到的一些有关事务的问题,跟同事间讨论了一下,后面翻看了一些书籍和做了一些测试,趁有点时间把它写下来,一来加深印象,二来希望对大家有所帮助,当然,由于自身水平问题,如理解有误,还请大牛指出 ...

  6. Debian6 安装Kscope(也适用于Ubuntu)

    参考:http://soft.chinabyte.com/os/134/12307634.shtml kscope1.6.2在这里下载,下载后解压出kscope-1.6.2.tar.gz. 在ubun ...

  7. Zookeeper的集群安装和配置

    zk服务器集群规模不小于3个节点,要求各服务器之间系统时间要保持一致. 在master节点的/home/hadoop目录下,解压缩zk....tar.gz,具体安装的路径自选 解压后重命名该文件夹为z ...

  8. 向Solr数据集提交Json格式数据(Scala,Post)

    import scalaj.http.Http class SolrAdd () {// 方法接受两个参数,dataType为数据集名称,jsonString为数据json字符串 def postTo ...

  9. 【招聘App】—— React/Nodejs/MongoDB全栈项目:项目准备

    前言:最近在学习Redux+react+Router+Nodejs全栈开发高级课程,这里对实践过程作个记录,方便自己和大家翻阅.最终成果github地址:https://github.com/66We ...

  10. 倍福TwinCAT(贝福Beckhoff)常见问题(FAQ)-可以用软件自带NC工具驱动但是程序无法让电机转动怎么办

    新建一个项目,当扫描的时候务必勾选YES,使用网上最新的XML文件   如果不使用,则有些设备可能被扫描出来是无效的(图标不正常)   如果完全删除XML描述文件,可能也能扫描出来,而且可以用Twin ...