攔截器是SpringMvc框架中常用的一個東東,它跟Filter相似,但是也有區別,以前也沒用過,今天看到就順便學習了一下。
SpirngMvc中的Interceptor主要是通過HandlerInterceptor和WebRequestInterceptor來實現,
HandlerInterceptor主要是下面三個方法:
public interface HandlerInterceptor { boolean preHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception; void postHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3, ModelAndView var4) throws Exception; void afterCompletion(HttpServletRequest var1, HttpServletResponse var2, Object var3, Exception var4) throws Exception; }
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 渲染了對應的視圖之后執行。這個方法的主要作用是用於進行資源清理工作的。
下面就是簡單代碼實現:
public class TestInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { System.out.println("Interceptor _ preHandle"); return true; } public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { System.out.println("Interceptor _ postHandle"); } public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { System.out.println("Interceptor _ afterCompletion"); } }
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 。
下面是一個簡單的代碼說明:
import org.springframework.ui.ModelMap; import org.springframework.web.context.request.WebRequest; import org.springframework.web.context.request.WebRequestInterceptor; public class AllInterceptor implements WebRequestInterceptor { /** * 在請求處理之前執行,該方法主要是用於准備資源數據的,然后可以把它們當做請求屬性放到WebRequest中 */ @Override public void preHandle(WebRequest request) throws Exception { // TODO Auto-generated method stub System.out.println("AllInterceptor..............................."); request.setAttribute("request", "request", WebRequest.SCOPE_REQUEST);//這個是放到request范圍內的,所以只能在當前請求中的request中獲取到 request.setAttribute("session", "session", WebRequest.SCOPE_SESSION);//這個是放到session范圍內的,如果環境允許的話它只能在局部的隔離的會話中訪問,否則就是在普通的當前會話中可以訪問 request.setAttribute("globalSession", "globalSession", WebRequest.SCOPE_GLOBAL_SESSION);//如果環境允許的話,它能在全局共享的會話中訪問,否則就是在普通的當前會話中訪問 } /** * 該方法將在Controller執行之后,返回視圖之前執行,ModelMap表示請求Controller處理之后返回的Model對象,所以可以在 * 這個方法中修改ModelMap的屬性,從而達到改變返回的模型的效果。 */ @Override public void postHandle(WebRequest request, ModelMap map) throws Exception { // TODO Auto-generated method stub for (String key:map.keySet()) System.out.println(key + "-------------------------");; map.put("name3", "value3"); map.put("name1", "name1"); } /** * 該方法將在整個請求完成之后,也就是說在視圖渲染之后進行調用,主要用於進行一些資源的釋放 */ @Override public void afterCompletion(WebRequest request, Exception exception) throws Exception { // TODO Auto-generated method stub System.out.println(exception + "-=-=--=--=-=-=-=-=-=-=-=-==-=--=-=-=-="); } }
下面就是需要在配置中加上攔截器的配置了:
<mvc:interceptors> <!-- 使用bean定義一個Interceptor,直接定義在mvc:interceptors根下面的Interceptor將攔截所有的請求 --> <!--<bean class="com.xxxx.xxx.xxx"/>--> <mvc:interceptor> <mvc:mapping path="/index.do"/> <bean class="com.springmvc.interceptor.TestInterceptor"/> </mvc:interceptor> </mvc:interceptors>
下面也來說下攔截器與過濾器之間的區別:
過濾器和攔截器的區別:
①攔截器是基於Java的反射機制的,而過濾器是基於函數回調。
②攔截器不依賴與servlet容器,過濾器依賴與servlet容器。
③攔截器只能對action請求起作用,而過濾器則可以對幾乎所有的請求起作用。
④攔截器可以訪問action上下文、值棧里的對象,而過濾器不能訪問。
⑤在action的生命周期中,攔截器可以多次被調用,而過濾器只能在容器初始化時被調用一次。
⑥攔截器可以獲取IOC容器中的各個bean,而過濾器就不行,這點很重要,在攔截器里注入一個service,可以調用業務邏輯。

以上全摘自網絡,感謝前輩的無私奉獻!
參考:http://blog.csdn.net/chenleixing/article/details/44573495
https://my.oschina.net/elim1/blog/811663
