SpringMVC的拦截器(Interceptor)和过滤器(Filter)的区别与联系

Easter79
• 阅读 827

一 简介

(1)过滤器:

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

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

(2)拦截器:

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

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

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

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

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

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

i)过滤器1:

 1 [java] view plain copy
 2 <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;  
 3   
 4 import java.io.IOException;  
 5   
 6 import javax.servlet.FilterChain;  
 7 import javax.servlet.ServletException;  
 8 import javax.servlet.http.HttpServletRequest;  
 9 import javax.servlet.http.HttpServletResponse;  
10   
11 import org.springframework.web.filter.OncePerRequestFilter;  
12   
13 public class TestFilter1 extends OncePerRequestFilter {  
14   
15     protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)  
16             throws ServletException, IOException {  
17         //在DispatcherServlet之前执行  
18         <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############");  
19         filterChain.doFilter(request, response);  
20         //在视图页面返回给<a target="_blank" href="https://my.oschina.net//u/4268457/blog/4201520/span>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之后  
21         System.out.println("############TestFilter1 doFilter after############");  
22 //      try {  
23 //          Thread.sleep(10000);  
24 //      } catch (InterruptedException e) {  
25 //          e.printStackTrace();  
26 //      }  
27     }  
28   
29 }

ii)过滤器2:

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

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

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

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

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   
 3 import org.springframework.stereotype.Controller;  
 4 import org.springframework.web.bind.annotation.RequestMapping;  
 5 import org.springframework.web.servlet.ModelAndView;  
 6   
 7 @Controller  
 8 public class TestController {  
 9       
10     @RequestMapping("/test.html")  
11     public ModelAndView handleRequest(){  
12         System.out.println("---------TestController executed--------");  
13         return new ModelAndView("test");  
14     }  
15 }

(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)测试效果:

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

SpringMVC的拦截器(Interceptor)和过滤器(Filter)的区别与联系

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

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

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

SpringMVC的拦截器(Interceptor)和过滤器(Filter)的区别与联系

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

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

SpringMVC的拦截器(Interceptor)和过滤器(Filter)的区别与联系

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Easter79 Easter79
3年前
springcloud gateway高级功能之根据参数自定义路由Predicate
背景我们使用了springcloudgateway作为也给路由转发功能,由于历史遗留问题,不仅仅需要根据path转发,还需要根据get或者post中的参数进行转发解决方案这里我们使用自定义的Predicate进行转发简介这里简单介绍下相关术语(1)Filter(过滤器):和Zuul的过滤器在概念上类似,可以使
Wesley13 Wesley13
3年前
java ee 部分分析
1logfilteranalysis分析filter:与Servlet相似,过滤器是一些web应用程序组件,可以绑定到一个web应用程序中。但是与其他web应用程序组件不同的是,过滤器是"链"在容器的处理过程中的。这就意味着它们会在servlet处理器之前访问一个进入的请求,并且在外发响应信息返回到客户前访问这些响应信息。这种访问使得过滤器可以检查
Stella981 Stella981
3年前
SpringBoot 的过滤器 Filter 配置的三种方式
SpringBoot过滤器配置有三种方式1\.@ServletComponentScan@WebFilter,可配置过滤路径,但没有顺序(顺序是由过滤器命名决定)在启动类上使用 @ServletComponentScan,在过滤器类上使用 @WebFilter(urlPatterns{"/test/path"})
Wesley13 Wesley13
3年前
Spring MVC 自带的字符编码过滤器以及Tomcat字符编码设置,彻底解决中文参数乱码问题
一、SpringMVC字符编码配置javaWeb项目添加Spring支持后,可使用Spring自带的字符编码过滤器。源码在springweb4.1.0.RELEASE.jar包下的org.springframework.web.filter目录的CharacterEncodingFilter.java。在web.xml文件中配置:
Stella981 Stella981
3年前
HBase
1过滤器HBase的基本API,包括增、删、改、查等。增、删都是相对简单的操作,与传统的RDBMS相比,这里的查询操作略显苍白,只能根据特性的行键进行查询(Get)或者根据行键的范围来查询(Scan)。HBase不仅提供了这些简单的查询,而且提供了更加高级的过滤器(Filter)来查询。1.1过滤器的两类参数过滤器可
Stella981 Stella981
3年前
Google布隆过滤器与Redis布隆过滤器详解
一、什么是布隆过滤器?布隆过滤器可以用来判断一个元素是否在一个集合中。它的优势是只需要占用很小的内存空间以及有着高效的查询效率。对于布隆过滤器而言,它的本质是一个位数组:位数组就是数组的每个元素都只占用1bit,并且每个元素只能是0或者1布隆过滤器除了一个位数组,还有K个哈希函数。当一个元素加入布隆过滤器中的时候,会进行如下操作:
Stella981 Stella981
3年前
Flask基础(14)
Flask基础(13)自定义过滤器什么是过滤器?    过滤器的本质就是函数。有时候我们不仅仅只是需要输出变量的值,我们还需要修改变量的显示,甚至格式化、运算等等,而在模板中是不能直接调用Python中的某些方法,那么这就用到了过滤器。使用方式:过滤器的使用方式为:变量名|过滤器。
Wesley13 Wesley13
3年前
Java过滤器与SpringMVC拦截器的差异学习笔记
学习摘录地址:http://blog.csdn.net/chenleixing/article/details/44573495今天学习和认识了一下,过滤器和SpringMVC的拦截器的区别,学到了不少的东西,以前一直以为拦截器就是过滤器实现的,现在想想还真是一种错误啊,而且看的比较粗浅,没有一个全局而又细致的认识,由于已至深夜,时间原因,我就把一些网友
Easter79
Easter79
Lv1
今生可爱与温柔,每一样都不能少。
文章
2.8k
粉丝
5
获赞
1.2k