博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringMVC的拦截器(Interceptor)和过滤器(Filter)的区别与联系
阅读量:7003 次
发布时间:2019-06-27

本文共 7554 字,大约阅读时间需要 25 分钟。

一 简介

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

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

  • 在SpringMVC中使用拦截器(interceptor)拦截CSRF攻击(修):https://www.zifangsky.cn/671.html

  • SpringMVC中使用Interceptor+实现在一定天数之内自动登录:https://www.zifangsky.cn/700.html

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

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

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

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

i)过滤器1:

1 [java] view plain copy 2 package 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         system.out.println("############TestFilter1 doFilterInternal executed############");  19         filterChain.doFilter(request, response);  20         //在视图页面返回给客户端之前执行,但是执行顺序在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 
2
3
testFilter1
4
cn.zifangsky.filter.TestFilter1
5
6
7
testFilter1
8
/*
9
10
11
12
testFilter2
13
cn.zifangsky.filter.TestFilter2
14
15
16
testFilter2
17
/*
18

(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;
3
4
5
6
7
8
9
10
11
12

(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    8    9 
10 11 FilterDemo 12 13 14 <% 15 System.out.println("test.jsp is loading"); 16 %> 17
18 This is test page 19
20 21

(5)测试效果:

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

wKioL1hHhYrRCpQYAABafsYR7go378.png

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

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

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

wKiom1hHhaPRQuBxAACG4WdOJbM758.png

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

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

wKiom1hHhbmxseDtAACidU9Y84s787.png

转载于:https://www.cnblogs.com/front-end-develop/p/8268510.html

你可能感兴趣的文章
[Android Studio 权威教程]断点调试和高级调试
查看>>
hdu1866 A + B forever!(面积并)题解
查看>>
C#中string.format用法详解
查看>>
回档|数字三角形3,4
查看>>
PHP & 符号详解(转)
查看>>
php 获取半年内每个月的订单数量, 总价, 月份
查看>>
linux idea 创建安卓模拟器失败
查看>>
js实现弹窗后选择信息填入text标签中以及需要注意的问题
查看>>
[转载]Thread.Sleep(0)妙用
查看>>
读了前半本<Thinking in Java>
查看>>
如何批量修改Jenkins job的配置?
查看>>
[转载] 高级人工智能——第10章 分布式人工智能
查看>>
Git 概念&常用命令
查看>>
LeetCode 418. Sentence Screen Fitting
查看>>
LeetCode 403. Frog Jump
查看>>
常用分页查询绑定GridView的取数方式
查看>>
Next permutation
查看>>
SDUT-3402_数据结构实验之排序五:归并求逆序数
查看>>
2590: [Usaco2012 Feb]Cow Coupons
查看>>
JavaScript 日期与时间戳互转
查看>>