javascript
框架:SpringMVC中Interceptor拦截器的两种实现
Spring中使用Interceptor攔截器
? ? ? ??SpringMVC 中的Interceptor?攔截器也是相當重要和相當有用的,它的主要作用是攔截用戶的請求并進行相應的處理。比如通過它來進行權限驗證,或者是來判斷用戶是否登陸,或者是像12306?那樣子判斷當前時間是否是購票時間。
??一、定義Interceptor實現類
?SpringMVC?中的Interceptor?攔截請求是通過HandlerInterceptor?來實現的。在SpringMVC?中定義一個Interceptor?非常簡單,主要有兩種方式,
第一種方式是要定義的Interceptor類要實現了Spring?的HandlerInterceptor?接口,或者是這個類繼承實現了HandlerInterceptor?接口的類,比如Spring?已經提供的實現了HandlerInterceptor?接口的抽象類HandlerInterceptorAdapter?;
第二種方式是實現Spring的WebRequestInterceptor接口,或者是繼承實現了WebRequestInterceptor的類。
(一)實現HandlerInterceptor接口
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?渲染了對應的視圖之后執行。這個方法的主要作用是用于進行資源清理工作的。
下面是一個簡單的代碼說明:
import javax.servlet.http.HttpServletRequest;?
import javax.servlet.http.HttpServletResponse;?
importorg.springframework.web.servlet.HandlerInterceptor;?
importorg.springframework.web.servlet.ModelAndView;?
?
public class SpringMVCInterceptor implements HandlerInterceptor {?
?
?
??? /**
???? * preHandle方法是進行處理器攔截用的,顧名思義,該方法將在Controller處理之前進行調用,SpringMVC中的Interceptor攔截器是鏈式的,可以同時存在
???? * 多個Interceptor,然后SpringMVC會根據聲明的前后順序一個接一個的執行,而且所有的Interceptor中的preHandle方法都會在
???? * Controller方法調用之前調用。SpringMVC的這種Interceptor鏈式結構也是可以進行中斷的,這種中斷方式是令preHandle的返回值為false,當preHandle的返回值為false的時候整個請求就結束了。
???? */?
??? @Override?
??? publicboolean preHandle(HttpServletRequest request,?
??????????? HttpServletResponse response,Object handler) throws Exception {?
??????? // TODO Auto-generated method stub?
??????? return false;?
??? }?
?????
??? /**
???? * 這個方法只會在當前這個Interceptor的preHandle方法返回值為true的時候才會執行。postHandle是進行處理器攔截用的,它的執行時間是在處理器進行處理之
???? * 后,也就是在Controller的方法調用之后執行,但是它會在DispatcherServlet進行視圖的渲染之前執行,也就是說在這個方法中你可以對ModelAndView進行操
???? * 作。這個方法的鏈式結構跟正常訪問的方向是相反的,也就是說先聲明的Interceptor攔截器該方法反而會后調用,這跟Struts2里面的攔截器的執行過程有點像,
???? * 只是Struts2里面的intercept方法中要手動的調用ActionInvocation的invoke方法,Struts2中調用ActionInvocation的invoke方法就是調用下一個Interceptor
???? * 或者是調用action,然后要在Interceptor之前調用的內容都寫在調用invoke之前,要在Interceptor之后調用的內容都寫在調用invoke方法之后。
???? */?
??? @Override?
??? publicvoid postHandle(HttpServletRequest request,?
??????????? HttpServletResponse response,Object handler,?
??????????? ModelAndView modelAndView) throws Exception {?
??????? // TODO Auto-generated method stub?
?????????
??? }?
?
??? /**
???? * afterCompletion,該方法也是需要當前對應的Interceptor的preHandle方法的返回值為true時才會執行。該方法將在整個請求完成之后,也就是DispatcherServlet渲染了視圖執行,
???? * 這個方法的主要作用是用于清理資源的,當然這個方法也只能在當前這個Interceptor的preHandle方法的返回值為true時才會執行。
???? */?
??? @Override?
??? public void afterCompletion(HttpServletRequestrequest,?
??????????? HttpServletResponse response,Object handler, Exception ex)?
??? throws Exception {?
??????? // TODO Auto-generated method stub?
?????????
??? }?
?????
}
多個攔截器的執行順序:
?
使用場景舉例:
1)解決請求亂碼問題
2)權限鑒定(是否登陸)
(二)實現WebRequestInterceptor?接口
?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;?
importorg.springframework.web.context.request.WebRequest;?
importorg.springframework.web.context.request.WebRequestInterceptor;?
?
publicclass AllInterceptor implementsWebRequestInterceptor {?
?????
??? /**
???? * 在請求處理之前執行,該方法主要是用于準備資源數據的,然后可以把它們當做請求屬性放到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?
??? publicvoid afterCompletion(WebRequest request,Exception exception)?
??? throws Exception {?
??????? // TODO Auto-generated method stub?
??????? System.out.println(exception +"-=-=--=--=-=-=-=-=-=-=-=-==-=--=-=-=-=");?
??? }?
?????
}?
?
二、把定義的攔截器類加到SpringMVC的攔截體系中
? 1.在SpringMVC的配置文件中加上支持MVC的schema
?下面是我的聲明示例
?
<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標簽了,mvc標簽中有一個mvc:interceptors是用于聲明SpringMVC的攔截器的。
??(二)使用mvc:interceptors標簽來聲明需要加入到SpringMVC攔截器鏈中的攔截器
?
<mvc:interceptors>?
??? <!-- 使用bean定義一個Interceptor,直接定義在mvc:interceptors根下面的Interceptor將攔截所有的請求-->?
??? <bean class="com.host.app.web.interceptor.AllInterceptor"/>? ?//攔截所有的請求
??? <mvc:interceptor>?
??????? <mvc:mapping path="/test/number.do"/>? ?//對特定的請求才進行攔截
??????? <!-- 定義在mvc:interceptor下面的表示是對特定的請求才進行攔截的 -->?
??????? <bean class="com.host.app.web.interceptor.LoginInterceptor"/>?
??? </mvc:interceptor>?
</mvc:interceptors>?
?
? ?由上面的示例可以看出可以利用mvc:interceptors標簽聲明一系列的攔截器,然后它們就可以形成一個攔截器鏈,攔截器的執行順序是按聲明的先后順序執行的,先聲明的攔截器中的preHandle方法會先執行,然而它的postHandle方法和afterCompletion方法卻會后執行。
????????? 在mvc:interceptors標簽下聲明interceptor主要有兩種方式:
?????????(1)直接定義一個Interceptor實現類的bean對象。使用這種方式聲明的Interceptor攔截器將會對所有的請求進行攔截。
?????????(2)使用mvc:interceptor標簽進行聲明。使用這種方式進行聲明的Interceptor可以通過mvc:mapping子標簽來定義需要進行攔截的請求路徑。
?????????經過上述兩步之后,定義的攔截器就會發生作用對特定的請求進行攔截了
?
總結
以上是生活随笔為你收集整理的框架:SpringMVC中Interceptor拦截器的两种实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 框架:Spring Aop、拦截器、过滤
- 下一篇: 框架:SpringMVC的工作原理