SpringMVC的攔截器(Interceptor)和過濾器(Filter)的區別與聯繫

一 簡介

(1)過濾器:html

依賴於servlet容器。在實現上基於函數回調,能夠對幾乎全部請求進行過濾,可是缺點是一個過濾器實例只能在容器初始化時調用一次。使用過濾器的目的是用來作一些過濾操做,獲取咱們想要獲取的數據,好比:在過濾器中修改字符編碼;在過濾器中修改HttpServletRequest的一些參數,包括:過濾低俗文字、危險字符等java

關於過濾器的一些用法能夠參考我寫過的這些文章web

  • 繼承HttpServletRequestWrapper以實如今Filter中修改HttpServletRequest的參數:https://www.zifangsky.cn/677.htmlspring

  • 在SpringMVC中使用過濾器(Filter)過濾容易引起XSS的危險字符:https://www.zifangsky.cn/683.html編程

(2)攔截器:cookie

依賴於web框架,在SpringMVC中就是依賴於SpringMVC框架。在實現上基於Java的反射機制,屬於面向切面編程(AOP)的一種運用。因爲攔截器是基於web框架的調用,所以能夠使用Spring的依賴注入(DI)進行一些業務操做,同時一個攔截器實例在一個controller生命週期以內能夠屢次調用。可是缺點是隻能對controller請求進行攔截,對其餘的一些好比直接訪問靜態資源的請求則沒辦法進行攔截處理mvc

關於過濾器的一些用法能夠參考我寫過的這些文章:app

  • 在SpringMVC中使用攔截器(interceptor)攔截CSRF攻擊(修):https://www.zifangsky.cn/671.html框架

  • SpringMVC中使用Interceptor+cookie實如今必定天數以內自動登陸:https://www.zifangsky.cn/700.htmljsp

二 多個過濾器與攔截器的代碼執行順序

若是在一個項目中僅僅只有一個攔截器或者過濾器,那麼我相信相對來講理解起來是比較容易的。可是咱們是否思考過:若是一個項目中有多個攔截器或者過濾器,那麼它們的執行順序應該是什麼樣的?或者再複雜點,一個項目中既有多個攔截器,又有多個過濾器,這時它們的執行順序又是什麼樣的呢?

下面我將用簡單的代碼來測試說明:

(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="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)測試效果:

啓動此測試項目,能夠看到控制檯中輸出以下:

wKioL1hHhYrRCpQYAABafsYR7go378.png

這就說明了過濾器的運行是依賴於servlet容器的,跟springmvc等框架並無關係。而且,多個過濾器的執行順序跟xml文件中定義的前後關係有關

接着清空控制檯中的輸出內容並訪問:http://localhost:9180/FilterDemo/test.html

能夠看到,此時的控制檯輸出結果以下:

wKiom1hHhaPRQuBxAACG4WdOJbM758.png

相信從這個打印輸出,你們就能夠很清晰地看到有多個攔截器和過濾器存在時的整個執行順序了。固然,對於過個攔截器它們之間的執行順序跟在SpringMVC的配置文件中定義的前後順序有關

注:對於整個SpringMVC的執行流程來講,若是加上上面的攔截器和過濾器,其最終的執行流程就以下圖所示:

wKiom1hHhbmxseDtAACidU9Y84s787.png

相關文章
相關標籤/搜索