一 简介

(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. ThinkPHP处理海量数据分表机制详细代码及说明

    ThinkPHP处理海量数据分表机制详细代码及说明   应用ThinkPHP内置的分表算法处理百万级用户数据. 数据表: house_member_0 house_member_1 house_mem ...

  2. Matlab中struct的用法

    struct在matlab中是用来建立结构体数组的.通常有两种用法: s = struct('field1',{},'field2',{},...)  这是建立一个空的结构体,field1,field ...

  3. Coherence装载数据的研究 - Invocation Service

    这里验证第三个方法,原理是将需要装载的数据分载在所有的存储节点上,不同的地方是利用了存储节点提供的InvocationService进行装载,而不是PreloadRequest, 原理如图 前提条件是 ...

  4. mysql 初始化报错 /usr/local/mysql/bin/mysqld:error while loading shared libraries :libaio.so.1

    安装mysql在初始化的时候,出现/usr/local/mysql/bin/mysqld:error while loading shared libraries:libaio.so.1 :canno ...

  5. 依据出生日期Date 计算年龄

    依据出生日期计算年龄 public class DateGetAge { public static int getAge(Date birthDay) throws Exception { Cale ...

  6. 【MySQL】海量量数据查询优化

    参考资料: mysql处理海量数据时的一些优化查询速度方法:http://www.cnblogs.com/lingiu/p/3414134.html mysql千万级大数据SQL查询优化:http:/ ...

  7. ThreadLocal的简单使用(读书笔记)

         从ThreadLocal的名字上可以看到,这是一个线程局部变量,也就是说,只有当前线程可以访问,既然是只有当前线程可以访问的数据,自然是线程安全的. public class ThreadL ...

  8. ubuntu各版本代号(更新至15.04)及各版本下载地址等

    版本号 代号 发布时间 15.04 Vivid Vervet 2015/04/22 14.10 Utopic Unicorn 2014/10/23 14.04 LTS Trusty Tahr 2014 ...

  9. centos 6.5 下使用nginx 反向代理 多个tornado

    centos 6.5 nginx 1.4.4 /etc/nginx/conf.d 下创建tornado.conf upstream tornado { server 127.0.0.1:8887; s ...

  10. lodash _.size

    返回collection(集合)的长度,如果集合是类数组或字符串,返回其 length :如果集合是对象,返回其可枚举属性的个数. _.size([1, 2, 3]); // => 3 _.si ...