Servlet Filter和Spring mvc Interceptor

servlet filter和spring mvc Interceptor區別:
1.攔截器是基于java的反射機制的,而過濾器是基于函數回調。
2.攔截器不依賴與servlet容器,過濾器依賴與servlet容器。
3.攔截器只能對action請求起作用,而過濾器則可以對幾乎所有的請求起作用。
4.攔截器可以訪問action上下文、值棧里的對象,而過濾器不能訪問。
5.在action的生命周期中,攔截器可以多次被調用,而過濾器只能在容器初始化時被調用一次。
6.攔截器可以獲取IOC容器中的各個bean,而過濾器就不行,這點很重要,在攔截器里注入一個service,可以調用業務邏輯。
servlet filter和spring mvc Interceptor執行順序:

===========before doFilter1
===========before doFilter2
===========HandlerInterceptorAll preHandle
===========HandlerInterceptor1 preHandle
===========HandlerInterceptor2 preHandle
執行Controller
Controller return前
===========HandlerInterceptor2 postHandle
===========HandlerInterceptor1 postHandle
===========HandlerInterceptorAll preHandle
Controller return后,Jsp加載完成
===========HandlerInterceptor2 afterCompletion
===========HandlerInterceptor1 afterCompletion
===========HandlerInterceptorAll preHandle
===========before doFilter2
===========before doFilter1

Filter:
Java中的Filter并不是一個標準的Servlet ,它不能處理用戶請求,也不能對客戶端生成響應。 主要用于對HttpServletRequest 進行預處理,也可以對HttpServletResponse 進行后處理,是個典型的處理鏈。完整的流程是:Filter對用戶請求進行預處理,接著將請求交給Servlet進行處理并生成響應,最后Filter再對服務器響應進行后處理。在HttpServletRequest 到達Servlet 之前,攔截客戶的HttpServletRequest。根據需要檢查HttpServletRequest ,也可以修改HttpServletRequest 頭和數據。在HttpServletResponse 到達客戶端之前,攔截HttpServletResponse。根據需要檢查HttpServletResponse ,可以修改HttpServletResponse 頭和數據。

Filter隨web應用的啟動而啟動,只初始化一次,隨web應用的停止而銷毀。
1.啟動服務器時加載過濾器的實例,并調用init()方法來初始化實例;
2.每一次請求時都只調用方法doFilter()進行處理;
3.停止服務器時調用destroy()方法,銷毀實例。

自定義Servlet Filter:

    import java.io.IOException;
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;

    public class ErrorHandleFilter implements Filter {

        @Override
        public void destroy() {
            // ...
        }

        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            //
        }

        @Override
        public void doFilter(ServletRequest request,
                   ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

            try {
                long before = System.currentTimeMillis();
                System.out.println("===========before doFilter")
                chain.doFilter(request, response);
                long after = System.currentTimeMillis();
                System.out.println("===========after doFilter")
            } catch (Exception ex) {
                request.setAttribute("errorMessage", ex);
                request.getRequestDispatcher("/WEB-INF/views/jsp/error.jsp")
                                   .forward(request, response);
            }

        }

    }

上面程序實現了doFilter()方法,實現該方法就可實現對用戶請求進行預處理,也可實現對服務器響應進行后處理——它們的分界線為是否調用了chain.doFilter(),執行該方法之前,即對用戶請求進行預處理;執行該方法之后,即對服務器響應進行后處理。調用Servlet的doService()方法是就是在chain.doFilter(request, response)這個方法中進行的。

在web.xml中配置:

<filter>
    <filter-name>errorHandlerFilter</filter-name>
    <filter-class>com.mkyong.form.web.ErrorHandleFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>errorHandlerFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

使用Spring進行管理:
DelegatingFilterProxy就是一個對于servlet filter的代理,它沒有實現過濾器的任何邏輯。通過spring容器來管理ServletFilter的生命周期。如果filter中需要一些Spring容器的實例,可以通過spring直接注入。
在web.xml中配置:

    <filter>  
    < filter-name>myFilter</filter-name>  
    < filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
    </filter>  
    <filter-mapping>  
    < filter-name>myFilter</filter-name>  
    < url-pattern>/*</url-pattern>  
    </filter-mapping>  

在contextApplication.xml中,配置具體的Filter類的實例。在Spring中配置的bean的name要和web.xml中的<filter-name>一樣

    <bean name="myFilter" class="com.*.MyFilter"></bean>

Interceptor:
spring mvc中的Interceptor可以理解為是Spring MVC框架對AOP的一種實現方式。一般簡單的功能又是通用的,每個請求都要去處理的,比如判斷token是否失效可以使用spring mvc的HanlderInterceptor, 復雜的,比如緩存,需要高度自定義的就用spring aop。一般來說service層更多用spring aop,controller層有必要用到request和response的時候,可以用攔截器。

spring mvc中的Interceptor攔截請求是通過HandlerInterceptor來實現的。所以HandlerInteceptor攔截器只有在Spring Web MVC環境下才能使用。在SpringMVC中定義一個攔截器主要有兩種方式,第一種方式是要實現Spring的HandlerInterceptor接口,或者是其它實現了HandlerInterceptor接口的類,比如HandlerInterceptorAdapter。第二種方式是實現WebRequestInterceptor接口,或者其它實現了WebRequestInterceptor的類。

HandlerInterceptor接口中定義了三個方法preHandle, postHandle, 和afterCompletion:

  • preHandle:預處理回調方法,實現處理器的預處理(如登錄檢查),返回值:true表示繼續流程(如調用下一個攔截器或處理器),false表示流程中斷(如登錄檢查失敗),不會繼續調用其他的攔截器或處理器,此時我們需要通過response來產生響應。
  • postHandle:后處理回調方法,實現處理器的后處理(但在渲染視圖之前),此時我們可以通過modelAndView(模型和視圖對象)對模型數據進行處理或對視圖進行處理,modelAndView也可能為null。
  • afterCompletion:整個請求處理完畢回調方法,即在視圖渲染完畢時回調。該方法也是需要當前對應的Interceptor 的preHandle方法的返回值為true時才會執行。這個方法的主要作用是用于進行資源清理工作的,如性能監控中我們可以在此記錄結束時間并輸出消耗時間。

流程如下:
先聲明的Interceptor 的postHandle 方法反而會后執行。


有時候我們可能只需要實現三個回調方法中的某一個,如果實現HandlerInterceptor接口的話,三個方法必須實現。spring提供了一個HandlerInterceptorAdapter適配器(一種適配器設計模式的實現),允許我們只實現需要的回調方法。
HandlerInterceptor1,HandlerInterceptor2:

    public class HandlerInterceptor1 extends HandlerInterceptorAdapter {
        @Override  
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {  
            System.out.println("===========HandlerInterceptor1 preHandle");  
            return true;  
        }  
        @Override  
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {  
            System.out.println("===========HandlerInterceptor1 postHandle");  
        }  
        @Override  
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {  
            System.out.println("===========HandlerInterceptor1 afterCompletion");  
        }  
    }  

HandlerInterceptor2同理,只是輸出內容為“HandlerInterceptor2”。

TestController:

    public class TestController implements Controller {  
        @Override  
        public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse resp) throws Exception {  
            System.out.println("===========TestController");  
            return new ModelAndView("test");  
        }  
    }  

Spring配置文件:

    <bean id="handlerInterceptor1" class="cn.javass.chapter5.web.interceptor.HandlerInterceptor1"/>  
    <bean id="handlerInterceptor2" class="cn.javass.chapter5.web.interceptor.HandlerInterceptor2"/>  

    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">  
        <property name="interceptors">  
            <list>  
               //攔截器的執行順序就是此處添加攔截器的順序。
               <ref bean="handlerInterceptor1"/>  
               <ref bean="handlerInterceptor2"/>  
            </list>  
        </property>  
    </bean> 

如果使用了<mvc:annotation-driven />, 它會自動注冊BeanNameUrlHandlerMapping這兩個bean,所以就沒有機會再給它注入interceptors屬性,就無法指定攔截器。推薦使用mvc:interceptors標簽來聲明需要加入到SpringMVC攔截器鏈中的攔截器。

在SpringMVC的配置文件中加上支持MVC的schema:

    <beans xmlns:mvc="http://www.springframework.org/schema/mvc"  
    xsi:schemaLocation=" http://www.springframework.org/schema/mvc  
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd" >

    <mvc:interceptors>  
        <!-- 使用bean定義一個Interceptor,直接定義在mvc:interceptors根下面的Interceptor將攔截所有的請求
        <bean class="com.host.app.web.interceptor.HandlerInterceptorAll"/>   -->  
        <mvc:interceptor>  
            <mvc:mapping path="/test/number.do"/> 
            <mvc:exclude-mapping path="/test/goLogin.*"/> 
            <!-- 定義在mvc:interceptor下面的表示是對特定的請求才進行攔截的 -->  
            <bean class="com.host.app.web.interceptor.HandlerInterceptor1"/>  
            <!-- <ref bean="handlerInterceptor1"/> -->
        </mvc:interceptor>  
        <mvc:interceptor>  
            <mvc:mapping path="/test/number.do"/> 
            <mvc:exclude-mapping path="/test/goLogin.*"/> 
            <bean class="com.host.app.web.interceptor.HandlerInterceptor2"/>  
            <!-- <ref bean="handlerInterceptor2"/> -->
        </mvc:interceptor>  
    </mvc:interceptors>  

在mvc:interceptors標簽下聲明interceptor主要有兩種方式:
1.直接定義一個Interceptor實現類的bean對象。使用這種方式聲明的Interceptor攔截器將會對所有的請求進行攔截。
2.使用mvc:interceptor標簽進行聲明。這種方式進行聲明的Interceptor可以通過mvc:mapping子標簽來定義需要進行攔截的請求路徑。

視圖頁面WEB-INF/jsp/test.jsp:

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>  
    <%System.out.println("==========test.jsp");%>

參考:
http://983836259.blog.51cto.com/7311475/1880286
http://www.cnblogs.com/dreamroute/p/4198087.html
http://www.cnblogs.com/ctxsdhy/p/6421067.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,443評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,530評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,407評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,981評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,759評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,204評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,263評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,415評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,955評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,650評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,892評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,675評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,967評論 2 374

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,785評論 18 139
  • Spring Boot 參考指南 介紹 轉載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,898評論 6 342
  • Spring MVC一、什么是 Spring MVCSpring MVC 屬于 SpringFrameWork 的...
    任任任任師艷閱讀 3,401評論 0 32
  • 攔截一些請求進行處理,比如通過它來進行權限驗證,或者是來判斷用戶是否登陸,日志記錄,編碼,或者限制時間點訪問等等,...
    JackFrost_fuzhu閱讀 1,998評論 0 7
  • 場景需求:在沒有一個類的實現源碼的情況下,想改變其中一個方法(一般指系統的方法)的實現,除了繼承它重寫、和借助類別...
    船長_閱讀 2,120評論 0 17