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

一 简介

(1)过滤器:

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

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

(2)拦截器:

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

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

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

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

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

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

i)过滤器1:

1 1 [java] view plain copy 2 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 3 4 4 import java.io.IOException; 5 5 6 6 import javax.servlet.FilterChain; 7 7 import javax.servlet.ServletException; 8 8 import javax.servlet.http.HttpServletRequest; 9 9 import javax.servlet.http.HttpServletResponse; 1010 1111 import org.springframework.web.filter.OncePerRequestFilter; 1212 1313 public class TestFilter1 extends OncePerRequestFilter { 1414 1515 protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) 1616 throws ServletException, IOException { 1717 //在DispatcherServlet之前执行 1818 <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############"); 1919 filterChain.doFilter(request, response); 2020 //在视图页面返回给<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之后 2121 System.out.println("############TestFilter1 doFilter after############"); 2222 // try { 2323 // Thread.sleep(10000); 2424 // } catch (InterruptedException e) { 2525 // e.printStackTrace(); 2626 // } 2727 } 2828 2929 }

ii)过滤器2:

1 1 package cn.zifangsky.filter; 2 2 3 3 import java.io.IOException; 4 4 5 5 import javax.servlet.FilterChain; 6 6 import javax.servlet.ServletException; 7 7 import javax.servlet.http.HttpServletRequest; 8 8 import javax.servlet.http.HttpServletResponse; 9 9 1010 import org.springframework.web.filter.OncePerRequestFilter; 1111 1212 public class TestFilter2 extends OncePerRequestFilter { 1313 1414 protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) 1515 throws ServletException, IOException { 1616 System.out.println("############TestFilter2 doFilterInternal executed############"); 1717 filterChain.doFilter(request, response); 1818 System.out.println("############TestFilter2 doFilter after############"); 1919 2020 } 2121 2222 }

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

1 1 <!-- 自定义过滤器:testFilter1 --> 2 2 <filter> 3 3 <filter-name>testFilter1</filter-name> 4 4 <filter-class>cn.zifangsky.filter.TestFilter1</filter-class> 5 5 </filter> 6 6 <filter-mapping> 7 7 <filter-name>testFilter1</filter-name> 8 8 <url-pattern>/*</url-pattern> 9 9 </filter-mapping> 1010 <!-- 自定义过滤器:testFilter2 --> 1111 <filter> 1212 <filter-name>testFilter2</filter-name> 1313 <filter-class>cn.zifangsky.filter.TestFilter2</filter-class> 1414 </filter> 1515 <filter-mapping> 1616 <filter-name>testFilter2</filter-name> 1717 <url-pattern>/*</url-pattern> 1818 </filter-mapping>

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

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

1 1 package cn.zifangsky.interceptor; 2 2 3 3 import javax.servlet.http.HttpServletRequest; 4 4 import javax.servlet.http.HttpServletResponse; 5 5 6 6 import org.springframework.web.servlet.HandlerInterceptor; 7 7 import org.springframework.web.servlet.ModelAndView; 8 8 9 9 public class BaseInterceptor implements HandlerInterceptor{ 1010 1111 /** 1212 * 在DispatcherServlet之前执行 1313 * */ 1414 public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception { 1515 System.out.println("************BaseInterceptor preHandle executed**********"); 1616 return true; 1717 } 1818 1919 /** 2020 * 在controller执行之后的DispatcherServlet之后执行 2121 * */ 2222 public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) 2323 throws Exception { 2424 System.out.println("************BaseInterceptor postHandle executed**********"); 2525 } 2626 2727 /** 2828 * 在页面渲染完成返回给客户端之前执行 2929 * */ 3030 public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) 3131 throws Exception { 3232 System.out.println("************BaseInterceptor afterCompletion executed**********"); 3333 // Thread.sleep(10000); 3434 } 3535 3636 }

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

1 1 package cn.zifangsky.interceptor; 2 2 3 3 import javax.servlet.http.HttpServletRequest; 4 4 import javax.servlet.http.HttpServletResponse; 5 5 6 6 import org.springframework.web.servlet.HandlerInterceptor; 7 7 import org.springframework.web.servlet.ModelAndView; 8 8 9 9 public class TestInterceptor implements HandlerInterceptor { 1010 1111 public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception { 1212 System.out.println("************TestInterceptor preHandle executed**********"); 1313 return true; 1414 } 1515 1616 public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) 1717 throws Exception { 1818 System.out.println("************TestInterceptor postHandle executed**********"); 1919 } 2020 2121 public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) 2222 throws Exception { 2323 System.out.println("************TestInterceptor afterCompletion executed**********"); 2424 } 2525 }

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

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

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

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

(4)视图页面test.jsp:

1 1 <%@ page language="java" contentType="text/html; charset=UTF-8" 2 2 pageEncoding="UTF-8"%> 3 3 <% 4 4 String path = request.getContextPath(); 5 5 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 6 6 %> 7 7 <html> 8 8 <head> 9 9 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 1010 <base href="http://983836259.blog.51cto.com/7311475/"> 1111 <title>FilterDemo</title> 1212 </head> 1313 <body> 1414 <% 1515 System.out.println("test.jsp is loading"); 1616 %> 1717 <div align="center"> 1818 This is test page 1919 </div> 2020 </body> 2121 </html>

(5)测试效果:

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

wKioL1hHhYrRCpQYAABafsYR7go378.png

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

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

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

wKiom1hHhaPRQuBxAACG4WdOJbM758.png

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

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

wKiom1hHhbmxseDtAACidU9Y84s787.png

点赞
收藏

评论区

加载中...

相关推荐

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

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

java ee 部分分析

1logfilteranalysis分析filter:与Servlet相似,过滤器是一些web应用程序组件,可以绑定到一个web应用程序中。但是与其他web应用程序组件不同的是,过滤器是"链"在容器的处理过程中的。这就意味着它们会在servlet处理器之前访问一个进入的请求,并且在外发响应信息返回到客户前访问这些响应信息。这种访问使得过滤器可以检查

SpringBoot 的过滤器 Filter 配置的三种方式

SpringBoot过滤器配置有三种方式1\.@ServletComponentScan@WebFilter,可配置过滤路径,但没有顺序(顺序是由过滤器命名决定)在启动类上使用 @ServletComponentScan,在过滤器类上使用 @WebFilter(urlPatterns{"/test/path"})

Spring MVC 自带的字符编码过滤器以及Tomcat字符编码设置,彻底解决中文参数乱码问题

一、SpringMVC字符编码配置javaWeb项目添加Spring支持后,可使用Spring自带的字符编码过滤器。源码在springweb4.1.0.RELEASE.jar包下的org.springframework.web.filter目录的CharacterEncodingFilter.java。在web.xml文件中配置: