Spring MVC系列(二):攔截器配置

Spring MVC 攔截器配置

1 簡介

攔截器,在程序進入核心邏輯之前和之後附加部分額外處理邏輯,實用場景舉例如下:

- 鑑權:在程序進入核心處理之前,判定是否爲非法請求;
- 統計:對請求次數做數量統計;
- 監控:在程序處理之前和之後對時間打點,計算核心邏輯消耗時間。```

與Struts類似,Spring MVC 可配置攔截器棧,先配先執行。Spring MVC可理解爲入棧一次(preHandler),出棧兩次(postHandler 和 afterCompletion)。

2 接口說明

Spring MVC攔截器接口爲HandlerInterceptor,通過實現該接口方法即可完成自定義攔截器。

public interface HandlerInterceptor {  
    boolean preHandle(  
            HttpServletRequest request, HttpServletResponse response,   
            Object handler)   
            throws Exception;  

    void postHandle(  
            HttpServletRequest request, HttpServletResponse response,   
            Object handler, ModelAndView modelAndView)   
            throws Exception;  

    void afterCompletion(  
            HttpServletRequest request, HttpServletResponse response,   
            Object handler, Exception ex)  
            throws Exception;  
}

可發現,HandlerInterceptor共有三個接口,分別爲preHandler,postHandler,afterCompletion,其功能介紹如下:
- preHandler:進入核心邏輯(即Controller)之前攔截器,返回值:true表示通過當前攔截邏輯,進入下一個攔截器的preHandler,當所有攔截器通過之後進入核心邏輯Controller;false表示未通過當前攔截邏輯,流程中斷,然後逆序執行所有返回true的攔截器的afterCompletion;
- postHandler:Controller執行之後,按照preHandler的處理順序,逆序執行所有攔截器的postHandler,然後進行視圖渲染,此爲第一次出棧;
- afterCompletion:在視圖渲染之後,再按照postHandler的處理順序執行所有afterCompletion,該部分可進行的工作包括資源清理、統計時間等,此爲第二次出棧。
Spring MVC攔截器執行順序圖
由於實現HandlerInterceptor每次都需要實現所有接口,爲了簡化開發,Spring非常貼心的爲我們提供了一個適配器HandlerInterceptorAdapter,允許我們只實現需要的回調方法。

3 代碼實現

3.1 攔截器配置

攔截器的攔截依據是:請求url,請注意以下url的 區別:
- / :攔截url爲/的請求
- /* :攔截父url爲/所有請求
- /** :攔截祖先url爲/所有請求

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--mvc需要的Controller必須在此聲明-->
    <context:component-scan base-package="spring.mvc"/>

    <!-- 啓用spring mvc 註解 -->
    <mvc:annotation-driven/>

    <!--攔截器配置,多個攔截器,順序執行-->
    <mvc:interceptors>
        <mvc:interceptor>
            <!--攔截url爲/的請求-->
            <mvc:mapping path="/"/>

            <!--攔截父url爲/所有請求-->
            <mvc:mapping path="/*"/>

            <!--攔截祖先url爲/的所有請求-->
            <mvc:mapping path="/**"/>

            <!--不攔截指定url的請求-->
            <mvc:exclude-mapping path="/mvc/setPerson"/>

            <!--自定義攔截器-->
            <bean id="interceptor" class="spring.interceptor.BaseInterceptor"/>
        </mvc:interceptor>
        <!-- 當設置多個攔截器時,先按順序調用preHandle方法,然後逆序調用每個攔截器的postHandle和afterCompletion方法 -->  
    </mvc:interceptors>

</beans>

3.2 自定義攔截器實現

public class BaseInterceptor implements HandlerInterceptor {
    /**
     * 在進入核心邏輯之前執行
     * 返回值:false
     *      從當前攔截器逆向執行所有攔截器的afterCompletion()
     * 返回值:true
     *      執行下一個攔截器,知道所有攔截器的preHandle()都執行完成(可以理解爲入棧過程)
     *      然後執行核心邏輯Controller
     *      接着對所有攔截器出棧,執行postHandle()
     *      最後在做一次出棧,執行所有的afterCompletion()
     */
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        System.out.println("==========BaseInterceptor.preHandle============");
        return true;
    }

    /**
     * 在覈心邏輯之後,視圖渲染之前執行
     * 可向modelAndView添加數據,如時間,cookie等
     */
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        System.out.println("==========BaseInterceptor.postHandle============");
    }

    /**
     * 在整個請求完成之後執行,可用於清理資源
     * 如果有攔截器拋異常,則從當前攔截器逆向執行所有afterCompletion()
     */
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        System.out.println("==========BaseInterceptor.afterCompletion============");
    }
}

3.3.3 測試結果

postman輸入鏈接:http://localhost:8070/mvc/setInfo/zhangsan?sex=male&addr=上海

控制檯輸出結果:

====BaseInterceptor.preHandle====
收到用戶名稱:zhangsan
收到用戶性別:male
收到用戶地址:上海
====BaseInterceptor.postHandle====
====BaseInterceptor.afterCompletion====

3.3.4 總結

從上述測試結果來看,成功配置了攔截器,器攔截器的執行順序是:preHandler -> Controller -> postHandler -> afterCompletion

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章