一、引言
??本來想記錄一下關于用戶登陸和登陸之后的權限管理、選單管理的問題,想到解決這個問題用到Interceptor,但想到了Interceptor,就想到了Filter,于是就想說一下它們的執行順序和區別,關于Interceptor解決權限和選單管理的問題,在放在下一篇寫吧,就醬紫,
二、區別
1、過濾器(Filter)
首先說一下Filter的使用地方,我們在配置web.xml時,總會配置下面一段設定字符編碼,不然會導致亂碼問題:
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<servlet-name>/*</servlet-name>
</filter-mapping>
配置這個地方的目的,是讓所有的請求都需要進行字符編碼的設定,下面來介紹一下Filter,
(1)過濾器(Filter):它依賴于servlet容器,在實作上,基于函式回呼,它可以對幾乎所有請求進行過濾,但是缺點是一個過濾器實體只能在容器初始化時呼叫一次,使用過濾器的目的,是用來做一些過濾操作,獲取我們想要獲取的資料,比如:在Javaweb中,對傳入的request、response提前過濾掉一些資訊,或者提前設定一些引數,然后再傳入servlet或者Controller進行業務邏輯操作,通常用的場景是:在過濾器中修改字符編碼(CharacterEncodingFilter)、在過濾器中修改HttpServletRequest的一些引數(XSSFilter(自定義過濾器)),如:過濾低俗文字、危險字符等,
2、攔截器(Interceptor)
攔截器的配置一般在SpringMVC的組態檔中,使用Interceptors標簽,具體配置如下:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" />
<bean class="com.scorpios.atcrowdfunding.web.LoginInterceptor"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**" />
<bean class="com.scorpios.atcrowdfunding.web.AuthInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
(2)攔截器(Interceptor):它依賴于web框架,在SpringMVC中就是依賴于SpringMVC框架,在實作上,基于Java的反射機制,屬于面向切面編程(AOP)的一種運用,就是在service或者一個方法前,呼叫一個方法,或者在方法后,呼叫一個方法,比如動態代理就是攔截器的簡單實作,在呼叫方法前列印出字串(或者做其它業務邏輯的操作),也可以在呼叫方法后列印出字串,甚至在拋出例外的時候做業務邏輯的操作,由于攔截器是基于web框架的呼叫,因此可以使用Spring的依賴注入(DI)進行一些業務操作,同時一個攔截器實體在一個controller生命周期之內可以多次呼叫,但是缺點是只能對controller請求進行攔截,對其他的一些比如直接訪問靜態資源的請求則沒辦法進行攔截處理,
三、代碼
下面在一個專案中我們使用既有多個過濾器,又有多個攔截器,并觀察它們的執行順序:
(1)第一個過濾器:
public class TestFilter1 implements Filter {
@Override
protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
//在DispatcherServlet之前執行
System.out.println("############TestFilter1 doFilterInternal executed############");
filterChain.doFilter(request, response);
//在視圖頁面回傳給客戶端之前執行,但是執行順序在Interceptor之后
System.out.println("############TestFilter1 doFilter after############");
}
}
(2)第二個過濾器:
public class TestFilter2 implements Filter {
@Override
protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
//在DispatcherServlet之前執行
System.out.println("############TestFilter2 doFilterInternal executed############");
filterChain.doFilter(request, response);
//在視圖頁面回傳給客戶端之前執行,但是執行順序在Interceptor之后
System.out.println("############TestFilter2 doFilter after############");
}
}
(3)在web.xml中注冊這兩個過濾器:
<!-- 自定義過濾器:testFilter1 -->
<filter>
<filter-name>testFilter1</filter-name>
<filter-class>com.scorpios.filter.TestFilter1</filter-class>
</filter>
<filter-mapping>
<filter-name>testFilter1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 自定義過濾器:testFilter2 -->
<filter>
<filter-name>testFilter2</filter-name>
<filter-class>com.scorpios.filter.TestFilter2</filter-class>
</filter>
<filter-mapping>
<filter-name>testFilter2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
再定義兩個攔截器:
(4)第一個攔截器:
public class BaseInterceptor implements HandlerInterceptor{
/**
* 在DispatcherServlet之前執行
* */
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
System.out.println("************BaseInterceptor preHandle executed**********");
return true;
}
/**
* 在controller執行之后的DispatcherServlet之后執行
* */
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception {
System.out.println("************BaseInterceptor postHandle executed**********");
}
/**
* 在頁面渲染完成回傳給客戶端之前執行
* */
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
System.out.println("************BaseInterceptor afterCompletion executed**********");
}
}
(5)第二個攔截器:
public class TestInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
System.out.println("************TestInterceptor preHandle executed**********");
return true;
}
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception {
System.out.println("************TestInterceptor postHandle executed**********");
}
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception {
System.out.println("************TestInterceptor afterCompletion executed**********");
}
}
(6)、在SpringMVC的組態檔中,加上攔截器的配置:
<!-- 攔截器 -->
<mvc:interceptors>
<!-- 對所有請求都攔截,公共攔截器可以有多個 -->
<bean name="baseInterceptor" class="com.scorpios.interceptor.BaseInterceptor" />
<mvc:interceptor>
<!-- 對/test.html進行攔截 -->
<mvc:mapping path="/test.html"/>
<!-- 特定請求的攔截器只能有一個 -->
<bean class="com.scorpios.interceptor.TestInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
(7)、定義一個Controller控制器:
package com.scorpios.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class TestController {
@RequestMapping("/test")
public ModelAndView handleRequest(){
System.out.println("---------TestController executed--------");
return new ModelAndView("test");
}
}
(8)、測驗結果:
啟動測驗專案,地址如下:http://www.localhost:8080/demo,可以看到控制臺中輸出如下:

這就說明了過濾器的運行是依賴于servlet容器,跟springmvc等框架并沒有關系,并且,多個過濾器的執行順序跟xml檔案中定義的先后關系有關,
接著清空控制臺,并訪問:http://www.localhost:8080/demo/test,再次看控制臺的輸出:

從這個控制臺列印輸出,就可以很清晰地看到有多個攔截器和過濾器存在時的整個執行順序了,當然,對于多個攔截器它們之間的執行順序跟在SpringMVC的組態檔中定義的先后順序有關,
四、總結
對于上述過濾器和攔截器的測驗,可以得到如下結論:
(1)、Filter需要在web.xml中配置,依賴于Servlet;
(2)、Interceptor需要在SpringMVC中配置,依賴于框架;
(3)、Filter的執行順序在Interceptor之前,具體的流程見下圖;

(4)、兩者的本質區別:攔截器(Interceptor)是基于Java的反射機制,而過濾器(Filter)是基于函式回呼,從靈活性上說攔截器功能更強大些,Filter能做的事情,都能做,而且可以在請求前,請求后執行,比較靈活,Filter主要是針對URL地址做一個編碼的事情、過濾掉沒用的引數、安全校驗(比較泛的,比如登錄不登錄之類),太細的話,還是建議用interceptor,不過還是根據不同情況選擇合適的,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/259421.html
標籤:其他
