詳解SpringMVC中使用Interceptor攔截器

姓名: 李小娜

[嵌牛導讀]: ? SpringMVC 中的Interceptor 攔截器也是相當重要和相當有用的洋丐,它的主要作用是攔截用戶的請求并進行相應的處理吊圾。比如通過它來進行權限驗證,或者是來判斷用戶是否登陸挂绰,或者是像12306 那樣子判斷當前時間是否是購票時間屎篱。

[嵌牛鼻子]:定義Interceptor實現(xiàn)類 ??把定義的攔截器類加到SpringMVC的攔截體系中 ??

[嵌牛提問]:定義的攔截器就會發(fā)生作用對特定的請求進行攔截的步驟?

[嵌牛正文] :?一葵蒂、定義Interceptor實現(xiàn)類

SpringMVC 中的Interceptor 攔截請求是通過HandlerInterceptor 來實現(xiàn)的交播。在SpringMVC 中定義一個Interceptor 非常簡單,主要有兩種方式践付,第一種方式是要定義的Interceptor類要實現(xiàn)了Spring 的HandlerInterceptor 接口秦士,或者是這個類繼承實現(xiàn)了HandlerInterceptor 接口的類,比如Spring 已經提供的實現(xiàn)了HandlerInterceptor 接口的抽象類HandlerInterceptorAdapter 永高;第二種方式是實現(xiàn)Spring的WebRequestInterceptor接口隧土,或者是繼承實現(xiàn)了WebRequestInterceptor的類。

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

HandlerInterceptor 接口中定義了三個方法命爬,我們就是通過這三個方法來對用戶的請求進行攔截處理的曹傀。

(1 )preHandle (HttpServletRequest request, HttpServletResponse response,

Object handle) 方法,顧名思義饲宛,該方法將在請求處理之前進行調用皆愉。SpringMVC 中的Interceptor

是鏈式的調用的,在一個應用中或者說是在一個請求中可以同時存在多個Interceptor 艇抠。每個Interceptor

的調用會依據它的聲明順序依次執(zhí)行幕庐,而且最先執(zhí)行的都是Interceptor 中的preHandle

方法,所以可以在這個方法中進行一些前置初始化操作或者是對當前請求的一個預處理练链,也可以在這個方法中進行一些判斷來決定請求是否要繼續(xù)進行下去翔脱。

該方法的返回值是布爾值Boolean 類型的,當它返回為false 時媒鼓,表示請求結束届吁,后續(xù)的Interceptor 和Controller 都不會再執(zhí)行;當返回值為true 時就會繼續(xù)調用下一個Interceptor 的preHandle 方法绿鸣,如果已經是最后一個Interceptor 的時候就會是調用當前請求的Controller 方法疚沐。

(2 )postHandle (HttpServletRequest request, HttpServletResponse response,

Object handle, ModelAndView modelAndView) 方法,由preHandle

方法的解釋我們知道這個方法包括后面要說到的afterCompletion 方法都只能是在當前所屬的Interceptor 的preHandle

方法的返回值為true 時才能被調用潮模。

postHandle 方法亮蛔,顧名思義就是在當前請求進行處理之后,也就是Controller 方法調用之后執(zhí)行擎厢,但是它會在DispatcherServlet 進行視圖返回渲染之前被調用究流,所以我們可以在這個方法中對Controller 處理之后的ModelAndView 對象進行操作辣吃。postHandle 方法被調用的方向跟preHandle 是相反的,也就是說先聲明的Interceptor 的postHandle 方法反而會后執(zhí)行芬探,這和Struts2 里面的Interceptor 的執(zhí)行過程有點類型神得。Struts2 里面的Interceptor 的執(zhí)行過程也是鏈式的,只是在Struts2 里面需要手動調用ActionInvocation 的invoke 方法來觸發(fā)對下一個Interceptor 或者是Action 的調用偷仿,然后每一個Interceptor 中在invoke 方法調用之前的內容都是按照聲明順序執(zhí)行的哩簿,而invoke 方法之后的內容就是反向的。

(3 )afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) 方法酝静,該方法也是需要當前對應的Interceptor 的preHandle 方法的返回值為true 時才會執(zhí)行节榜。顧名思義,該方法將在整個請求結束之后别智,也就是在DispatcherServlet 渲染了對應的視圖之后執(zhí)行宗苍。這個方法的主要作用是用于進行資源清理工作的。

下面是一個簡單的代碼說明:

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

importorg.springframework.web.servlet.HandlerInterceptor;

importorg.springframework.web.servlet.ModelAndView;

publicclassSpringMVCInterceptorimplementsHandlerInterceptor {

/**

* preHandle方法是進行處理器攔截用的亿遂,顧名思義浓若,該方法將在Controller處理之前進行調用,SpringMVC中的Interceptor攔截器是鏈式的蛇数,可以同時存在

* 多個Interceptor挪钓,然后SpringMVC會根據聲明的前后順序一個接一個的執(zhí)行,而且所有的Interceptor中的preHandle方法都會在

* Controller方法調用之前調用耳舅。SpringMVC的這種Interceptor鏈式結構也是可以進行中斷的碌上,這種中斷方式是令preHandle的返

* 回值為false,當preHandle的返回值為false的時候整個請求就結束了浦徊。

*/

@Override

publicbooleanpreHandle(HttpServletRequest request,

HttpServletResponse response, Object handler)throwsException {

// TODO Auto-generated method stub

returnfalse;

}

/**

* 這個方法只會在當前這個Interceptor的preHandle方法返回值為true的時候才會執(zhí)行馏予。postHandle是進行處理器攔截用的,它的執(zhí)行時間是在處理器進行處理之

* 后盔性,也就是在Controller的方法調用之后執(zhí)行霞丧,但是它會在DispatcherServlet進行視圖的渲染之前執(zhí)行,也就是說在這個方法中你可以對ModelAndView進行操

* 作冕香。這個方法的鏈式結構跟正常訪問的方向是相反的蛹尝,也就是說先聲明的Interceptor攔截器該方法反而會后調用,這跟Struts2里面的攔截器的執(zhí)行過程有點像悉尾,

* 只是Struts2里面的intercept方法中要手動的調用ActionInvocation的invoke方法突那,Struts2中調用ActionInvocation的invoke方法就是調用下一個Interceptor

* 或者是調用action,然后要在Interceptor之前調用的內容都寫在調用invoke之前构眯,要在Interceptor之后調用的內容都寫在調用invoke方法之后愕难。

*/

@Override

publicvoidpostHandle(HttpServletRequest request,

HttpServletResponse response, Object handler,

ModelAndView modelAndView)throwsException {

// TODO Auto-generated method stub

}

/**

* 該方法也是需要當前對應的Interceptor的preHandle方法的返回值為true時才會執(zhí)行。該方法將在整個請求完成之后,也就是DispatcherServlet渲染了視圖執(zhí)行猫缭,

* 這個方法的主要作用是用于清理資源的葱弟,當然這個方法也只能在當前這個Interceptor的preHandle方法的返回值為true時才會執(zhí)行。

*/

@Override

publicvoidafterCompletion(HttpServletRequest request,

HttpServletResponse response, Object handler, Exception ex)

throwsException {

// TODO Auto-generated method stub

}

}

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

WebRequestInterceptor 中也定義了三個方法饵骨,我們也是通過這三個方法來實現(xiàn)攔截的翘悉。這三個方法都傳遞了同一個參數WebRequest ,那么這個WebRequest 是什么呢居触?這個WebRequest 是Spring 定義的一個接口,它里面的方法定義都基本跟HttpServletRequest 一樣老赤,在WebRequestInterceptor 中對WebRequest 進行的所有操作都將同步到HttpServletRequest 中轮洋,然后在當前請求中一直傳遞。

(1 )preHandle(WebRequest request) 方法抬旺。該方法將在請求處理之前進行調用弊予,也就是說會在Controller 方法調用之前被調用。這個方法跟HandlerInterceptor 中的preHandle 是不同的开财,主要區(qū)別在于該方法的返回值是void 汉柒,也就是沒有返回值,所以我們一般主要用它來進行資源的準備工作责鳍,比如我們在使用Hibernate 的時候可以在這個方法中準備一個Hibernate 的Session 對象碾褂,然后利用WebRequest 的setAttribute(name, value, scope) 把它放到WebRequest 的屬性中。這里可以說說這個setAttribute 方法的第三個參數scope 历葛,該參數是一個Integer 類型的正塌。在WebRequest 的父層接口RequestAttributes 中對它定義了三個常量:

SCOPE_REQUEST :它的值是0 ,代表只有在request 中可以訪問恤溶。

SCOPE_SESSION :它的值是1 乓诽,如果環(huán)境允許的話它代表的是一個局部的隔離的session,否則就代表普通的session咒程,并且在該session范圍內可以訪問鸠天。

SCOPE_GLOBAL_SESSION :它的值是2 ,如果環(huán)境允許的話帐姻,它代表的是一個全局共享的session稠集,否則就代表普通的session,并且在該session 范圍內可以訪問卖宠。

(2 )postHandle(WebRequest request, ModelMap model) 方法巍杈。該方法將在請求處理之后,也就是在Controller 方法調用之后被調用扛伍,但是會在視圖返回被渲染之前被調用筷畦,所以可以在這個方法里面通過改變數據模型ModelMap 來改變數據的展示。該方法有兩個參數,WebRequest 對象是用于傳遞整個請求數據的鳖宾,比如在preHandle 中準備的數據都可以通過WebRequest 來傳遞和訪問吼砂;ModelMap 就是Controller 處理之后返回的Model 對象,我們可以通過改變它的屬性來改變返回的Model 模型鼎文。

(3 )afterCompletion(WebRequest request, Exception ex) 方法渔肩。該方法會在整個請求處理完成,也就是在視圖返回并被渲染之后執(zhí)行拇惋。所以在該方法中可以進行資源的釋放操作周偎。而WebRequest 參數就可以把我們在preHandle 中準備的資源傳遞到這里進行釋放。Exception 參數表示的是當前請求的異常對象撑帖,如果在Controller 中拋出的異常已經被Spring 的異常處理器給處理了的話蓉坎,那么這個異常對象就是是null 。

下面是一個簡單的代碼說明:


importorg.springframework.ui.ModelMap;

importorg.springframework.web.context.request.WebRequest;

importorg.springframework.web.context.request.WebRequestInterceptor;

publicclassAllInterceptorimplementsWebRequestInterceptor {

/**

* 在請求處理之前執(zhí)行胡嘿,該方法主要是用于準備資源數據的蛉艾,然后可以把它們當做請求屬性放到WebRequest中

*/

@Override

publicvoidpreHandle(WebRequest request)throwsException {

// 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范圍內的衷敌,如果環(huán)境允許的話它只能在局部的隔離的會話中訪問勿侯,否則就是在普通的當前會話中可以訪問

request.setAttribute("globalSession","globalSession", WebRequest.SCOPE_GLOBAL_SESSION);//如果環(huán)境允許的話,它能在全局共享的會話中訪問缴罗,否則就是在普通的當前會話中訪問

}

/**

* 該方法將在Controller執(zhí)行之后助琐,返回視圖之前執(zhí)行,ModelMap表示請求Controller處理之后返回的Model對象瞒爬,所以可以在

* 這個方法中修改ModelMap的屬性弓柱,從而達到改變返回的模型的效果。

*/

@Override

publicvoidpostHandle(WebRequest request, ModelMap map)throwsException {

// TODO Auto-generated method stub

for(String key:map.keySet())

System.out.println(key +"-------------------------");;

map.put("name3","value3");

map.put("name1","name1");

}

/**

* 該方法將在整個請求完成之后侧但,也就是說在視圖渲染之后進行調用矢空,主要用于進行一些資源的釋放

*/

@Override

publicvoidafterCompletion(WebRequest request, Exception exception)

throwsException {

// TODO Auto-generated method stub

System.out.println(exception +"-=-=--=--=-=-=-=-=-=-=-=-==-=--=-=-=-=");

}

}

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

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

這樣在SpringMVC的配置文件中就可以使用mvc標簽了禀横,mvc標簽中有一個mvc:interceptors是用于聲明SpringMVC的攔截器的屁药。

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

可以看出可以利用mvc:interceptors標簽聲明一系列的攔截器,然后它們就可以形成一個攔截器鏈柏锄,攔截器的執(zhí)行順序是按聲明的先后順序執(zhí)行的酿箭,先聲明的攔截器中的preHandle方法會先執(zhí)行,然而它的postHandle方法和afterCompletion方法卻會后執(zhí)行趾娃。

在mvc:interceptors標簽下聲明interceptor主要有兩種方式:

(1)直接定義一個Interceptor實現(xiàn)類的bean對象缭嫡。使用這種方式聲明的Interceptor攔截器將會對所有的請求進行攔截。

(2)使用mvc:interceptor標簽進行聲明抬闷。使用這種方式進行聲明的Interceptor可以通過mvc:mapping子標簽來定義需要進行攔截的請求路徑妇蛀。

經過上述兩步之后耕突,定義的攔截器就會發(fā)生作用對特定的請求進行攔截了。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末评架,一起剝皮案震驚了整個濱河市眷茁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌纵诞,老刑警劉巖上祈,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異浙芙,居然都是意外死亡登刺,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門茁裙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來塘砸,“玉大人,你說我怎么就攤上這事晤锥。” “怎么了廊宪?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵矾瘾,是天一觀的道長。 經常有香客問我箭启,道長壕翩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任傅寡,我火速辦了婚禮放妈,結果婚禮上,老公的妹妹穿的比我還像新娘荐操。我一直安慰自己芜抒,他們只是感情好,可當我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布托启。 她就那樣靜靜地躺著宅倒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪屯耸。 梳的紋絲不亂的頭發(fā)上拐迁,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天,我揣著相機與錄音疗绣,去河邊找鬼线召。 笑死,一個胖子當著我的面吹牛多矮,可吹牛的內容都是我干的缓淹。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼割卖!你這毒婦竟也來了前酿?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤鹏溯,失蹤者是張志新(化名)和其女友劉穎罢维,沒想到半個月后,有當地人在樹林里發(fā)現(xiàn)了一具尸體丙挽,經...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡肺孵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了颜阐。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片平窘。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖凳怨,靈堂內的尸體忽然破棺而出瑰艘,到底是詐尸還是另有隱情,我是刑警寧澤肤舞,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布紫新,位于F島的核電站,受9級特大地震影響李剖,放射性物質發(fā)生泄漏芒率。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一篙顺、第九天 我趴在偏房一處隱蔽的房頂上張望偶芍。 院中可真熱鬧,春花似錦德玫、人聲如沸匪蟀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽萄窜。三九已至,卻和暖如春撒桨,著一層夾襖步出監(jiān)牢的瞬間查刻,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工凤类, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留穗泵,地道東北人。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓谜疤,卻偏偏與公主長得像佃延,于是被迫代替她去往敵國和親现诀。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,500評論 2 359

推薦閱讀更多精彩內容