SpringMVC攔截器的使用

SpringMVC 中的Interceptor 攔截器也是相當(dāng)重要和相當(dāng)有用的,它的主要作用是攔截用戶的請求并進(jìn)行相應(yīng)的處理。比如通過它來進(jìn)行權(quán)限驗(yàn)證,或者是來判斷用戶是否登陸,或者是像12306 那樣子判斷當(dāng)前時間是否是購票時間。
一、springMVC攔截器的實(shí)現(xiàn)方式
springMVC攔截器的實(shí)現(xiàn)一般有兩種方式:
第一種方式是要定義的Interceptor類要實(shí)現(xiàn)了Spring的HandlerInterceptor 接口。
第二種方式是繼承實(shí)現(xiàn)了HandlerInterceptor接口的類,比如Spring已經(jīng)提供的實(shí)現(xiàn)了HandlerInterceptor接口的抽象類HandlerInterceptorAdapter。
1.實(shí)現(xiàn)HandlerInterceptor 接口
HandlerInterceptor 接口中定義了三個方法,我們就是通過這三個方法來對用戶的請求進(jìn)行攔截處理的。
(1)preHandle (HttpServletRequest request, HttpServletResponse response, Object handle) 方法,這個方法將在請求處理之前進(jìn)行調(diào)用。
SpringMVC 中的Interceptor 是鏈?zhǔn)秸{(diào)用的,在一個應(yīng)用中或者說是在一個請求中可以同時存在多個Interceptor 。每個Interceptor 的調(diào)用會依據(jù)它的聲明順序依次執(zhí)行,而且最先執(zhí)行的都是Interceptor 中的preHandle 方法,所以可以在這個方法中進(jìn)行一些前置初始化操作或者是對當(dāng)前請求的一個預(yù)處理,也可以在這個方法中進(jìn)行一些判斷來決定請求是否要繼續(xù)進(jìn)行下去。
?(2)postHandle (HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView) 方法,由preHandle 方法的解釋我們知道這個方法包括后面要說到的afterCompletion 方法都只能是在當(dāng)前所屬的Interceptor 的preHandle 方法的返回值為true 時才能被調(diào)用。
postHandle 方法,顧名思義就是在當(dāng)前請求進(jìn)行處理之后,也就是Controller 方法調(diào)用之后執(zhí)行,但是它會在DispatcherServlet 進(jìn)行視圖返回渲染之前被調(diào)用,所以我們可以在這個方法中對Controller 處理之后的ModelAndView 對象進(jìn)行操作。
postHandle 方法被調(diào)用的方向跟preHandle 是相反的,也就是說先聲明的Interceptor 的postHandle 方法反而會后執(zhí)行,這和Struts2 里面的Interceptor 的執(zhí)行過程有點(diǎn)類型。
(3)afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) 方法,這個方法也是需要當(dāng)前對應(yīng)的Interceptor 的preHandle 方法的返回值為true 時才會執(zhí)行,用于進(jìn)行資源清理工作。afterCompletion方法將在整個請求結(jié)束之后,也就是在DispatcherServlet 渲染了對應(yīng)的視圖之后執(zhí)行。
多個攔截器的調(diào)用順序:

下面是一個簡單的代碼說明:
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)降?,可以同時存在
??????* 多個Interceptor,然后SpringMVC會根據(jù)聲明的前后順序一個接一個的執(zhí)行,而且所有的Interceptor中的preHandle方法都會在
??????* Controller方法調(diào)用之前調(diào)用。SpringMVC的這種Interceptor鏈?zhǔn)浇Y(jié)構(gòu)也是可以進(jìn)行中斷的,這種中斷方式是令preHandle的返
??????* 回值為false,當(dāng)preHandle的返回值為false的時候整個請求就結(jié)束了。
??????*/
????@Override
????public?boolean?preHandle(HttpServletRequest request,
????????????HttpServletResponse response, Object handler)?throws?Exception {
????????// TODO Auto-generated method stub
????????return?false;
????}
????
????/**
?????* 這個方法只會在當(dāng)前這個Interceptor的preHandle方法返回值為true的時候才會執(zhí)行。postHandle是進(jìn)行處理器攔截用的,它的執(zhí)行時間是在處理器進(jìn)行處理之
??????* 后,也就是在Controller的方法調(diào)用之后執(zhí)行,但是它會在DispatcherServlet進(jìn)行視圖的渲染之前執(zhí)行,也就是說在這個方法中你可以對ModelAndView進(jìn)行操
??????* 作。這個方法的鏈?zhǔn)浇Y(jié)構(gòu)跟正常訪問的方向是相反的,也就是說先聲明的Interceptor攔截器該方法反而會后調(diào)用,這跟Struts2里面的攔截器的執(zhí)行過程有點(diǎn)像,
??????* 只是Struts2里面的intercept方法中要手動的調(diào)用ActionInvocation的invoke方法,Struts2中調(diào)用ActionInvocation的invoke方法就是調(diào)用下一個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時才會執(zhí)行。該方法將在整個請求完成之后,也就是DispatcherServlet渲染了視圖執(zhí)行,
??????* 這個方法的主要作用是用于清理資源的,當(dāng)然這個方法也只能在當(dāng)前這個Interceptor的preHandle方法的返回值為true時才會執(zhí)行。
??????*/
????@Override
????public?void?afterCompletion(HttpServletRequest request,
????????????HttpServletResponse response, Object handler, Exception ex)
????throws?Exception {
????????// TODO Auto-generated method stub
????????
????}
????
}2.繼承HandlerInterceptorAdapter類
有時候我們可能只需要實(shí)現(xiàn)三個回調(diào)方法中的某一個,如果實(shí)現(xiàn)HandlerInterceptor接口的話,三個方法必須實(shí)現(xiàn),不管你需不需要,此時spring提供了一個HandlerInterceptorAdapter適配器(一種適配器設(shè)計(jì)模式的實(shí)現(xiàn)),允許我們只實(shí)現(xiàn)需要的回調(diào)方法(注:一般項(xiàng)目中使用比較多的是這種方式)。
HandlerInterceptorAdapter適配器是Spring MVC為了方便我們使用HandlerInterceptor而對HandlerInterceptor 的默認(rèn)實(shí)現(xiàn),里面的3個方法沒有做任何處理,在preHandle方法直接返回true,這樣我們繼承HandlerInterceptorAdapter后只需要實(shí)現(xiàn)3個方法中我們需要的方法即可,而不像繼承HandlerInterceptor一樣不管是否需要3個方法都要實(shí)現(xiàn)。
import?javax.servlet.http.HttpServletRequest;
import?javax.servlet.http.HttpServletResponse;
import?org.slf4j.Logger;
import?org.slf4j.LoggerFactory;
import?org.springframework.web.servlet.ModelAndView;
import?org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
public?class?CommonInterceptor??extends?HandlerInterceptorAdapter{
????
????private?final?Logger log = LoggerFactory.getLogger(CommonInterceptor.class);
????/**
?????* 在業(yè)務(wù)處理器處理請求之前被調(diào)用
??????* 如果返回false,從當(dāng)前的攔截器往回執(zhí)行所有攔截器的afterCompletion(),再退出攔截器鏈。
??????* 如果返回true,執(zhí)行下一個攔截器,直到所有的攔截器都執(zhí)行完畢,再執(zhí)行被攔截的Controller。
??????* 然后進(jìn)入攔截器鏈,從最后一個攔截器往回執(zhí)行所有的postHandle()
?????* 接著再從最后一個攔截器往回執(zhí)行所有的afterCompletion()
?????*/??
????@Override??
????public?boolean?preHandle(HttpServletRequest request,
????????????HttpServletResponse response, Object handler)?throws?Exception {
????????????
????????log.info("==============執(zhí)行順序: 1、preHandle================");
????}
????
????/**
?????* 在業(yè)務(wù)處理器處理請求執(zhí)行完成后,生成視圖之前執(zhí)行的動作
??????* 可在modelAndView中加入數(shù)據(jù),比如當(dāng)前時間
??????*/
????@Override??
????public?void?postHandle(HttpServletRequest request,
????????????HttpServletResponse response, Object handler,
????????????ModelAndView modelAndView)?throws?Exception {
????????????
????????log.info("==============執(zhí)行順序: 2、postHandle================");
????????if(modelAndView != null){ //加入當(dāng)前時間
????????????modelAndView.addObject("haha", "測試postHandle");
????????}
????}
????
????/**
?????* 在DispatcherServlet完全處理完請求后被調(diào)用,可用于清理資源等
??????* 當(dāng)有攔截器拋出異常時,會從當(dāng)前攔截器往回執(zhí)行所有的攔截器的afterCompletion()
?????*/??
????@Override??
????public?void?afterCompletion(HttpServletRequest request,
????????????HttpServletResponse response, Object handler, Exception ex)??
????????????throws?Exception {
????????
????????log.info("==============執(zhí)行順序: 3、afterCompletion================");
????}
}二、把定義的攔截器類加入到SpringMVC的攔截體系中
1.在SpringMVC的配置文件中加上支持MVC的schema
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"2.使用mvc:interceptors標(biāo)簽來聲明需要加入到SpringMVC攔截器鏈中的攔截器
????<mvc:interceptors>?
??????
????????<mvc:interceptor>
????????????<mvc:mapping?path="/test/number.do"/>?
??????????????
????????????<bean?id="commonInterceptor"?class="org.shop.interceptor.CommonInterceptor">bean>
????????mvc:interceptor>?
????
mvc:interceptors>由上面的示例可以看出可以利用mvc:interceptors標(biāo)簽聲明一系列的攔截器,然后它們就可以形成一個攔截器鏈,攔截器的執(zhí)行順序是按聲明的先后順序執(zhí)行的,先聲明的攔截器中的preHandle方法會先執(zhí)行,然而它的postHandle方法和afterCompletion方法卻會后執(zhí)行。
?在mvc:interceptors標(biāo)簽下聲明interceptor主要有兩種方式:
(1)直接定義一個Interceptor實(shí)現(xiàn)類的bean對象。使用這種方式聲明的Interceptor攔截器將會對所有的請求進(jìn)行攔截。
(2)使用mvc:interceptor標(biāo)簽進(jìn)行聲明。使用這種方式進(jìn)行聲明的Interceptor可以通過mvc:mapping子標(biāo)簽來定義需要進(jìn)行攔截的請求路徑。
經(jīng)過上述兩步之后,定義的攔截器就會發(fā)生作用對特定的請求進(jìn)行攔截了。
注:使用mvc:exclude-mapping 可以排除攔截的地址
<mvc:interceptors>
????<mvc:interceptor>
?????????
????????<mvc:mapping?path="/**"?/>
????????
????????<mvc:exclude-mapping?path="/js/**"?/>
????????<mvc:exclude-mapping?path="/css/**"?/>
????????<mvc:exclude-mapping?path="/image/**"?/>
????????
????????<bean?id="commonInterceptor"?class="org.shop.interceptor.CommonInterceptor">bean>?
????mvc:interceptor>
mvc:interceptors>原文鏈接:cnblogs.com/xiaoxi/p/6256812.html
