SpringMVC中的Interceptor攔截器也是相當重要和相當有用的,它的主要作用是攔截用戶的請求並進行相應的處理。
比如通過它來進行權限驗證,或者是來判斷用戶是否登陸,或者是像12306那樣子判斷當前時間是否是購票時間。
SpringMVC中的Interceptor攔截請求是通過HandlerInterceptor來實現的。在SpringMVC中定義一個Interceptor非常簡單,主要有兩種方式,第一種方式是要定義的Interceptor類要實現了Spring的HandlerInterceptor接口,或者是這個類繼承實現了HandlerInterceptor接口的類,比如Spring已經提供的實現了HandlerInterceptor接口的抽象類HandlerInterceptorAdapter;第二種方式是實現Spring的WebRequestInterceptor接口,或者是繼承實現了WebRequestInterceptor的類。
HandlerInterceptor接口中定義了三個方法,我們就是通過這三個方法來對用戶的請求進行攔截處理的。
(1)preHandle(HttpServletRequest request, HttpServletResponse response, Object handle) 方法,顧名思義,該方法將在請求處理之前進行調用。SpringMVC中的Interceptor是鏈式的調用的,在一個應用中或者說是在一個請求中可以同時存在多個Interceptor。每個Interceptor的調用會依據它的聲明順序依次執行,而且最先執行的都是Interceptor中的preHandle方法,所以可以在這個方法中進行一些前置初始化操作或者是對當前請求的一個預處理,也可以在這個方法中進行一些判斷來決定請求是否要繼續進行下去。該方法的返回值是布爾值Boolean類型的,當它返回為false時,表示請求結束,後續的Interceptor和Controller都不會再執行;當返回值為true時就會繼續調用下一個Interceptor的preHandle方法,如果已經是最後一個Interceptor的時候就會是調用當前請求的Controller方法。
(2)postHandle(HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView) 方法,由preHandle方法的解釋我們知道這個方法包括後面要說到的afterCompletion方法都只能是在當前所屬的Interceptor的preHandle方法的返回值為true時才能被調用。postHandle方法,顧名思義就是在當前請求進行處理之後,也就是Controller方法調用之後執行,但是它會在DispatcherServlet進行視圖返回渲染之前被調用,所以我們可以在這個方法中對Controller處理之後的ModelAndView對象進行操作。postHandle方法被調用的方向跟preHandle是相反的,也就是說先聲明的Interceptor的postHandle方法反而會後執行,這和Struts2裡面的Interceptor的執行過程有點類型。Struts2裡面的Interceptor的執行過程也是鏈式的,只是在Struts2裡面需要手動調用ActionInvocation的invoke方法來觸發對下一個Interceptor或者是Action的調用,然後每一個Interceptor中在invoke方法調用之前的內容都是按照聲明順序執行的,而invoke方法之後的內容就是反向的。
(3)afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex)方法,該方法也是需要當前對應的Interceptor的preHandle方法的返回值為true時才會執行。顧名思義,該方法將在整個請求結束之後,也就是在DispatcherServlet渲染了對應的視圖之後執行。這個方法的主要作用是用於進行資源清理工作的。
下面是一個簡單的代碼說明:
Java代碼WebRequestInterceptor中也定義了三個方法,我們也是通過這三個方法來實現攔截的。這三個方法都傳遞了同一個參數WebRequest,那麼這個WebRequest是什麼呢?這個WebRequest是Spring定義的一個接口,它裡面的方法定義都基本跟HttpServletRequest一樣,在WebRequestInterceptor中對WebRequest進行的所有操作都將同步到HttpServletRequest中,然後在當前請求中一直傳遞。
(1)preHandle(WebRequest request)方法。該方法將在請求處理之前進行調用,也就是說會在Controller方法調用之前被調用。這個方法跟HandlerInterceptor中的preHandle是不同的,主要區別在於該方法的返回值是void,也就是沒有返回值,所以我們一般主要用它來進行資源的准備工作,比如我們在使用Hibernate的時候可以在這個方法中准備一個Hibernate的Session對象,然後利用WebRequest的setAttribute(name, value, scope)把它放到WebRequest的屬性中。這裡可以說說這個setAttribute方法的第三個參數scope,該參數是一個Integer類型的。在WebRequest的父層接口RequestAttributes中對它定義了三個常量:
SCOPE_REQUEST:它的值是0,代表只有在request中可以訪問。
SCOPE_SESSION:它的值是1,如果環境允許的話它代表的是一個局部的隔離的session,否則就代表普通的session,並且在該session范圍內可以訪問。
SCOPE_GLOBAL_SESSION:它的值是2,如果環境允許的話,它代表的是一個全局共享的session,否則就代表普通的session,並且在該session范圍內可以訪問。
(2)postHandle(WebRequest request, ModelMap model)方法。該方法將在請求處理之後,也就是在Controller方法調用之後被調用,但是會在視圖返回被渲染之前被調用,所以可以在這個方法裡面通過改變數據模型ModelMap來改變數據的展示。該方法有兩個參數,WebRequest對象是用於傳遞整個請求數據的,比如在preHandle中准備的數據都可以通過WebRequest來傳遞和訪問;ModelMap就是Controller處理之後返回的Model對象,我們可以通過改變它的屬性來改變返回的Model模型。
(3)afterCompletion(WebRequest request, Exception ex)方法。該方法會在整個請求處理完成,也就是在視圖返回並被渲染之後執行。所以在該方法中可以進行資源的釋放操作。而WebRequest參數就可以把我們在preHandle中准備的資源傳遞到這裡進行釋放。Exception參數表示的是當前請求的異常對象,如果在Controller中拋出的異常已經被Spring的異常處理器給處理了的話,那麼這個異常對象就是是null。
下面是一個簡單的代碼說明:
Java代碼下面是我的聲明示例:
Xml代碼這樣在SpringMVC的配置文件中就可以使用mvc標簽了,mvc標簽中有一個mvc:interceptors是用於聲明SpringMVC的攔截器的。
由上面的示例可以看出可以利用mvc:interceptors標簽聲明一系列的攔截器,然後它們就可以形成一個攔截器鏈,攔截器的執行順序是按聲明的先後順序執行的,先聲明的攔截器中的preHandle方法會先執行,然而它的postHandle方法和afterCompletion方法卻會後執行。
在mvc:interceptors標簽下聲明interceptor主要有兩種方式:
(1)直接定義一個Interceptor實現類的bean對象。使用這種方式聲明的Interceptor攔截器將會對所有的請求進行攔截。
(2)使用mvc:interceptor標簽進行聲明。使用這種方式進行聲明的Interceptor可以通過mvc:mapping子標簽來定義需要進行攔截的請求路徑。
經過上述兩步之後,定義的攔截器就會發生作用對特定的請求進行攔截了。