SpringMvc攔截器

一、定義Interceptor實(shí)現(xiàn)類

SpringMVC 中的Interceptor 攔截請求是通過HandlerInterceptor 來實(shí)現(xiàn)的。在SpringMVC 中定義一個(gè)Interceptor 非常簡單,主要有兩種方式,第一種方式是要定義的Interceptor類要實(shí)現(xiàn)了Spring 的HandlerInterceptor 接口,或者是這個(gè)類繼承實(shí)現(xiàn)了HandlerInterceptor 接口的類,比如Spring 已經(jīng)提供的實(shí)現(xiàn)了HandlerInterceptor 接口的抽象類HandlerInterceptorAdapter ;第二種方式是實(shí)現(xiàn)Spring的WebRequestInterceptor接口,或者是繼承實(shí)現(xiàn)了WebRequestInterceptor的類。

(一)實(shí)現(xiàn)HandlerInterceptor接口

HandlerInterceptor 接口中定義了三個(gè)方法,我們就是通過這三個(gè)方法來對用戶的請求進(jìn)行攔截處理的。
(1 )preHandle (HttpServletRequest request, HttpServletResponse response, Object handle) 方法,顧名思義,該方法將在請求處理之前進(jìn)行調(diào)用。SpringMVC 中的Interceptor 是鏈?zhǔn)降恼{(diào)用的,在一個(gè)應(yīng)用中或者說是在一個(gè)請求中可以同時(shí)存在多個(gè)Interceptor 。每個(gè)Interceptor 的調(diào)用會(huì)依據(jù)它的聲明順序依次執(zhí)行,而且最先執(zhí)行的都是Interceptor 中的preHandle 方法,所以可以在這個(gè)方法中進(jìn)行一些前置初始化操作或者是對當(dāng)前請求的一個(gè)預(yù)處理,也可以在這個(gè)方法中進(jìn)行一些判斷來決定請求是否要繼續(xù)進(jìn)行下去。該方法的返回值是布爾值Boolean 類型的,當(dāng)它返回為false 時(shí),表示請求結(jié)束,后續(xù)的Interceptor 和Controller 都不會(huì)再執(zhí)行;當(dāng)返回值為true 時(shí)就會(huì)繼續(xù)調(diào)用下一個(gè)Interceptor 的preHandle 方法,如果已經(jīng)是最后一個(gè)Interceptor 的時(shí)候就會(huì)是調(diào)用當(dāng)前請求的Controller 方法。
(2 )postHandle (HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView) 方法,由preHandle 方法的解釋我們知道這個(gè)方法包括后面要說到的afterCompletion 方法都只能是在當(dāng)前所屬的Interceptor 的preHandle 方法的返回值為true 時(shí)才能被調(diào)用。postHandle 方法,顧名思義就是在當(dāng)前請求進(jìn)行處理之后,也就是Controller 方法調(diào)用之后執(zhí)行,但是它會(huì)在DispatcherServlet 進(jìn)行視圖返回渲染之前被調(diào)用,所以我們可以在這個(gè)方法中對Controller 處理之后的ModelAndView 對象進(jìn)行操作。postHandle 方法被調(diào)用的方向跟preHandle 是相反的,也就是說先聲明的Interceptor 的postHandle 方法反而會(huì)后執(zhí)行,這和Struts2里面的Interceptor 的執(zhí)行過程有點(diǎn)類型。Struts2 里面的Interceptor 的執(zhí)行過程也是鏈?zhǔn)降模皇窃赟truts2 里面需要手動(dòng)調(diào)用ActionInvocation 的invoke 方法來觸發(fā)對下一個(gè)Interceptor 或者是Action 的調(diào)用,然后每一個(gè)Interceptor 中在invoke 方法調(diào)用之前的內(nèi)容都是按照聲明順序執(zhí)行的,而invoke 方法之后的內(nèi)容就是反向的。
(3 )afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) 方法,該方法也是需要當(dāng)前對應(yīng)的Interceptor 的preHandle 方法的返回值為true 時(shí)才會(huì)執(zhí)行。顧名思義,該方法將在整個(gè)請求結(jié)束之后,也就是在DispatcherServlet 渲染了對應(yīng)的視圖之后執(zhí)行。這個(gè)方法的主要作用是用于進(jìn)行資源清理工作的。
下面是一個(gè)簡單的代碼說明:

Java代碼
收藏代碼

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class SpringMVCInterceptor implements HandlerInterceptor {

/** 
 * preHandle方法是進(jìn)行處理器攔截用的,顧名思義,該方法將在Controller處理之前進(jìn)行調(diào)用,SpringMVC中的Interceptor攔截器是鏈?zhǔn)降模梢酝瑫r(shí)存在 
 * 多個(gè)Interceptor,然后SpringMVC會(huì)根據(jù)聲明的前后順序一個(gè)接一個(gè)的執(zhí)行,而且所有的Interceptor中的preHandle方法都會(huì)在 
 * Controller方法調(diào)用之前調(diào)用。SpringMVC的這種Interceptor鏈?zhǔn)浇Y(jié)構(gòu)也是可以進(jìn)行中斷的,這種中斷方式是令preHandle的返 
 * 回值為false,當(dāng)preHandle的返回值為false的時(shí)候整個(gè)請求就結(jié)束了。 
 */  
@Override  
public boolean preHandle(HttpServletRequest request,  
        HttpServletResponse response, Object handler) throws Exception {  
    // TODO Auto-generated method stub  
    return false;  
}  
  
/** 
 * 這個(gè)方法只會(huì)在當(dāng)前這個(gè)Interceptor的preHandle方法返回值為true的時(shí)候才會(huì)執(zhí)行。postHandle是進(jìn)行處理器攔截用的,它的執(zhí)行時(shí)間是在處理器進(jìn)行處理之 
 * 后,也就是在Controller的方法調(diào)用之后執(zhí)行,但是它會(huì)在DispatcherServlet進(jìn)行視圖的渲染之前執(zhí)行,也就是說在這個(gè)方法中你可以對ModelAndView進(jìn)行操 
 * 作。這個(gè)方法的鏈?zhǔn)浇Y(jié)構(gòu)跟正常訪問的方向是相反的,也就是說先聲明的Interceptor攔截器該方法反而會(huì)后調(diào)用,這跟Struts2里面的攔截器的執(zhí)行過程有點(diǎn)像, 
 * 只是Struts2里面的intercept方法中要手動(dòng)的調(diào)用ActionInvocation的invoke方法,Struts2中調(diào)用ActionInvocation的invoke方法就是調(diào)用下一個(gè)Interceptor 
 * 或者是調(diào)用action,然后要在Interceptor之前調(diào)用的內(nèi)容都寫在調(diào)用invoke之前,要在Interceptor之后調(diào)用的內(nèi)容都寫在調(diào)用invoke方法之后。 
 */  
@Override  
public void postHandle(HttpServletRequest request,  
        HttpServletResponse response, Object handler,  
        ModelAndView modelAndView) throws Exception {  
    // TODO Auto-generated method stub  
      
}  

/** 
 * 該方法也是需要當(dāng)前對應(yīng)的Interceptor的preHandle方法的返回值為true時(shí)才會(huì)執(zhí)行。該方法將在整個(gè)請求完成之后,也就是DispatcherServlet渲染了視圖執(zhí)行, 
 * 這個(gè)方法的主要作用是用于清理資源的,當(dāng)然這個(gè)方法也只能在當(dāng)前這個(gè)Interceptor的preHandle方法的返回值為true時(shí)才會(huì)執(zhí)行。 
 */  
@Override  
public void afterCompletion(HttpServletRequest request,  
        HttpServletResponse response, Object handler, Exception ex)  
throws Exception {  
    // TODO Auto-generated method stub  
      
}  

}

(二)實(shí)現(xiàn)WebRequestInterceptor 接口

WebRequestInterceptor 中也定義了三個(gè)方法,我們也是通過這三個(gè)方法來實(shí)現(xiàn)攔截的。這三個(gè)方法都傳遞了同一個(gè)參數(shù)WebRequest ,那么這個(gè)WebRequest 是什么呢?這個(gè)WebRequest 是Spring 定義的一個(gè)接口,它里面的方法定義都基本跟HttpServletRequest 一樣,在WebRequestInterceptor 中對WebRequest 進(jìn)行的所有操作都將同步到HttpServletRequest 中,然后在當(dāng)前請求中一直傳遞。
(1 )preHandle(WebRequest request) 方法。該方法將在請求處理之前進(jìn)行調(diào)用,也就是說會(huì)在Controller 方法調(diào)用之前被調(diào)用。這個(gè)方法跟HandlerInterceptor 中的preHandle 是不同的,主要區(qū)別在于該方法的返回值是void ,也就是沒有返回值,所以我們一般主要用它來進(jìn)行資源的準(zhǔn)備工作,比如我們在使用Hibernate 的時(shí)候可以在這個(gè)方法中準(zhǔn)備一個(gè)Hibernate 的Session 對象,然后利用WebRequest 的setAttribute(name, value, scope) 把它放到WebRequest 的屬性中。這里可以說說這個(gè)setAttribute 方法的第三個(gè)參數(shù)scope ,該參數(shù)是一個(gè)Integer 類型的。在WebRequest 的父層接口RequestAttributes 中對它定義了三個(gè)常量:
SCOPE_REQUEST :它的值是0 ,代表只有在request 中可以訪問。
SCOPE_SESSION :它的值是1 ,如果環(huán)境允許的話它代表的是一個(gè)局部的隔離的session,否則就代表普通的session,并且在該session范圍內(nèi)可以訪問。
SCOPE_GLOBAL_SESSION :它的值是2 ,如果環(huán)境允許的話,它代表的是一個(gè)全局共享的session,否則就代表普通的session,并且在該session 范圍內(nèi)可以訪問。
(2 )postHandle(WebRequest request, ModelMap model) 方法。該方法將在請求處理之后,也就是在Controller 方法調(diào)用之后被調(diào)用,但是會(huì)在視圖返回被渲染之前被調(diào)用,所以可以在這個(gè)方法里面通過改變數(shù)據(jù)模型ModelMap 來改變數(shù)據(jù)的展示。該方法有兩個(gè)參數(shù),WebRequest 對象是用于傳遞整個(gè)請求數(shù)據(jù)的,比如在preHandle 中準(zhǔn)備的數(shù)據(jù)都可以通過WebRequest 來傳遞和訪問;ModelMap 就是Controller 處理之后返回的Model 對象,我們可以通過改變它的屬性來改變返回的Model 模型。
(3 )afterCompletion(WebRequest request, Exception ex) 方法。該方法會(huì)在整個(gè)請求處理完成,也就是在視圖返回并被渲染之后執(zhí)行。所以在該方法中可以進(jìn)行資源的釋放操作。而WebRequest 參數(shù)就可以把我們在preHandle 中準(zhǔn)備的資源傳遞到這里進(jìn)行釋放。Exception 參數(shù)表示的是當(dāng)前請求的異常對象,如果在Controller中拋出的異常已經(jīng)被Spring 的異常處理器給處理了的話,那么這個(gè)異常對象就是是null 。

下面是一個(gè)簡單的代碼說明:

Java代碼
收藏代碼

import org.springframework.ui.ModelMap;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.WebRequestInterceptor;

public class AllInterceptor implements WebRequestInterceptor {

/** 
 * 在請求處理之前執(zhí)行,該方法主要是用于準(zhǔn)備資源數(shù)據(jù)的,然后可以把它們當(dāng)做請求屬性放到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);//這個(gè)是放到request范圍內(nèi)的,所以只能在當(dāng)前請求中的request中獲取到  
    request.setAttribute("session", "session", WebRequest.SCOPE_SESSION);//這個(gè)是放到session范圍內(nèi)的,如果環(huán)境允許的話它只能在局部的隔離的會(huì)話中訪問,否則就是在普通的當(dāng)前會(huì)話中可以訪問  
    request.setAttribute("globalSession", "globalSession", WebRequest.SCOPE_GLOBAL_SESSION);//如果環(huán)境允許的話,它能在全局共享的會(huì)話中訪問,否則就是在普通的當(dāng)前會(huì)話中訪問  
}  

/** 
 * 該方法將在Controller執(zhí)行之后,返回視圖之前執(zhí)行,ModelMap表示請求Controller處理之后返回的Model對象,所以可以在 
 * 這個(gè)方法中修改ModelMap的屬性,從而達(dá)到改變返回的模型的效果。 
 */  
@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");  
}  

/** 
 * 該方法將在整個(gè)請求完成之后,也就是說在視圖渲染之后進(jìn)行調(diào)用,主要用于進(jìn)行一些資源的釋放 
 */  
@Override  
public void afterCompletion(WebRequest request, Exception exception)  
throws Exception {  
    // TODO Auto-generated method stub  
    System.out.println(exception + "-=-=--=--=-=-=-=-=-=-=-=-==-=--=-=-=-=");  
}  

}

二、把定義的攔截器類加到SpringMVC的攔截體系中

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

Xml代碼
收藏代碼
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"  

      下面是我的聲明示例:

Xml代碼
收藏代碼

<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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

     這樣在SpringMVC的配置文件中就可以使用mvc標(biāo)簽了,mvc標(biāo)簽中有一個(gè)mvc:interceptors是用于聲明SpringMVC的攔截器的。

    (二)使用mvc:interceptors標(biāo)簽來聲明需要加入到SpringMVC攔截器鏈中的攔截器

Xml代碼 [圖片上傳中。。。(5)]

<mvc:interceptors>

<bean class="com.host.app.web.interceptor.AllInterceptor"/>
<mvc:interceptor>
<mvc:mapping path="/test/number.do"/>

<bean class="com.host.app.web.interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>

      由上面的示例可以看出可以利用mvc:interceptors標(biāo)簽聲明一系列的攔截器,然后它們就可以形成一個(gè)攔截器鏈,攔截器的執(zhí)行順序是按聲明的先后順序執(zhí)行的,先聲明的攔截器中的preHandle方法會(huì)先執(zhí)行,然而它的postHandle方法和afterCompletion方法卻會(huì)后執(zhí)行。
      在mvc:interceptors標(biāo)簽下聲明interceptor主要有兩種方式:
                (1)直接定義一個(gè)Interceptor實(shí)現(xiàn)類的bean對象。使用這種方式聲明的Interceptor攔截器將會(huì)對所有的請求進(jìn)行攔截。
                (2)使用mvc:interceptor標(biāo)簽進(jìn)行聲明。使用這種方式進(jìn)行聲明的Interceptor可以通過mvc:mapping子標(biāo)簽來定義需要進(jìn)行攔截的請求路徑。
      經(jīng)過上述兩步之后,定義的攔截器就會(huì)發(fā)生作用對特定的請求進(jìn)行攔截了。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 姓名: 李小娜 [嵌牛導(dǎo)讀]: SpringMVC 中的Interceptor 攔截器也是相當(dāng)重要和相當(dāng)有用的,...
    n184閱讀 3,204評論 0 4
  • SpringMVC中使用Interceptor攔截器 有兩種常用的方法實(shí)現(xiàn)SpringMVC攔截器: 1.一種是實(shí)...
    ll0292閱讀 1,016評論 0 4
  • 無論是前段時(shí)間大熱的國產(chǎn)劇《我的前半生》,還是經(jīng)典電影《穿Prada的女王》,為我們展現(xiàn)的職場女性,都是雷厲風(fēng)行、...
    DAREONE閱讀 1,317評論 0 0
  • 汽車限號多沒勁,有本事限性別,一三五男的出門,二四六女的上街,周日兩口子結(jié)伴而行。每天13億人出來6億,窩著6億,...
    古墓道人閱讀 83評論 0 0
  • 第四十三回 破局 “田哥、方哥……你們快起來。”易之將攤在地上的方、田二人叫起,“我想我有法子了。” “啥?”方南...
    沐杰閱讀 269評論 0 0