文档章节

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

architect刘源源
 architect刘源源
发布于 2018/05/04 11:28
字数 1497
阅读 79
收藏 0
web

一 简介

(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:

[java] view plain copy

  1. <a href="http://www.07net01.com/tags-package-0.html" class="infotextkey" style="background:transparent;color:rgb(66,139,202);" target="_blank">package</a> 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 TestFilter1 extends OncePerRequestFilter {  
  13.   
  14.     protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)  
  15.             throws ServletException, IOException {  
  16.         //在DispatcherServlet之前执行  
  17.         <a href="http://www.07net01.com/tags-system-0.html" class="infotextkey" style="background:transparent;color:rgb(66,139,202);" target="_blank">system</a>.out.println("############TestFilter1 doFilterInternal executed############");  
  18.         filterChain.doFilter(request, response);  
  19.         //在视图页面返回给<a 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);" target="_blank">客户端</a>之前执行,但是执行顺序在Interceptor之后  
  20.         System.out.println("############TestFilter1 doFilter after############");  
  21. //      try {  
  22. //          Thread.sleep(10000);  
  23. //      } catch (InterruptedException e) {  
  24. //          e.printStackTrace();  
  25. //      }  
  26.     }  
  27.   
  28. }  

ii)过滤器2:

[java] view plain copy

  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中注册这两个过滤器:

[xml] view plain copy

  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,基本拦截器:

[java] view plain copy

  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请求的拦截器:

[java] view plain copy

  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的配置文件中注册这两个拦截器:

[java] view plain copy

  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:

[java] view plain copy

  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:

[html] view plain copy

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

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

wKioL1hHhYrRCpQYAABafsYR7go378.png

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

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

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

wKiom1hHhaPRQuBxAACG4WdOJbM758.png

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

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

wKiom1hHhbmxseDtAACidU9Y84s787.png

© 著作权归作者所有

architect刘源源

architect刘源源

粉丝 167
博文 554
码字总数 934264
作品 0
浦东
程序员
私信 提问
加载中

评论(2)

architect刘源源
architect刘源源 博主
但是缺点是一个过滤器实例只能在容器初始化时调用一次。”这句话看到了好多次了,怎么感觉都不对啊,过滤器时在容器初始化的时候初始化一次,而不是调用一次吧,当符合filter的url-pattern时这个过滤器会调用一次吧,就是请求一次调用一次,而拦截器可以在一次请求中多次调用吧
architect刘源源
architect刘源源 博主
拦截器是在controller前后执行的
基于SpringMVC的拦截器(Interceptor)和过滤器(Filter)的区别与联系

2016/10/07 Spring admin 5 条评论 1587 views 一 简介 (1)过滤器: 依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时...

Airship
2017/11/03
80
0
springmvc java对象转json,上传下载,拦截器Interceptor以及源码解析

只是写一个<a href = "testJson">测试json</a> 然后再springmvc.xml中开启注解驱动mvc:annotation-driven/ 然后需要印如jackson的三个jar包,jackson是阿里巴巴产品,能够自动将java对象转为......

architect刘源源
06/20
111
0
基于SpringMVC的拦截器(Interceptor)和过滤器(Filter)的区别与联系

一 简介 (1)过滤器: 依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操...

pangfc
2016/12/07
0
0
SpringBoot入坑指南之六:使用过滤器或拦截器

开篇 在Web应用中,常常存在拦截全部或部分请求进行统一处理的应用场景,如权限校验、参数校验、性能监控等。 在SpringMVC框架中,我们可以通过过滤器或拦截器实现相关功能,spring-boot-sta...

centychen
03/05
2.3K
5
【SpringBoot】RESTful API拦截-过滤器、拦截器、切片

前言 这里了解一下restful api的拦截,文本主要介绍三种方式来对api进行拦截,参考本文可实现拦截api,进行一些附加操作,比如打印拦截到的方法所在类名,获取原始的request,拦截到api的调用...

zlt995768025
2018/05/02
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Giraph源码分析(八)—— 统计每个SuperStep中参与计算的顶点数目

作者|白松 目的:科研中,需要分析在每次迭代过程中参与计算的顶点数目,来进一步优化系统。比如,在SSSP的compute()方法最后一行,都会把当前顶点voteToHalt,即变为InActive状态。所以每次...

数澜科技
今天
2
0
Xss过滤器(Java)

问题 最近旧的系统,遇到Xss安全问题。这个系统采用用的是spring mvc的maven工程。 解决 maven依赖配置 <properties><easapi.version>2.2.0.0</easapi.version></properties><dependenci......

亚林瓜子
今天
7
0
Navicat 快捷键

操作 结果 ctrl+q 打开查询窗口 ctrl+/ 注释sql语句 ctrl+shift +/ 解除注释 ctrl+r 运行查询窗口的sql语句 ctrl+shift+r 只运行选中的sql语句 F6 打开一个mysql命令行窗口 ctrl+l 删除一行 ...

低至一折起
今天
8
0
Set 和 Map

Set 1:基本概念 类数组对象, 内部元素唯一 let set = new Set([1, 2, 3, 2, 1]); console.log(set); // Set(3){ 1, 2, 3 } [...set]; // [1, 2, 3] 接收数组或迭代器对象 ...

凌兮洛
今天
2
0
PyTorch入门笔记一

张量 引入pytorch,生成一个随机的5x3张量 >>> from __future__ import print_function>>> import torch>>> x = torch.rand(5, 3)>>> print(x)tensor([[0.5555, 0.7301, 0.5655],......

仪山湖
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部