SpringMVC攔截器簡單使用
SpringMVC的處理器攔截器,類似於Servlet開發中的過濾器Filter,用於對處理器進行預處理和後處理。
(1)過濾器:
依賴於servlet容器。在實現上基於函式回撥,可以對幾乎所有請求進行過濾,但是缺點是一個過濾器例項只能在容器初始化時呼叫一次。使用過濾器的目的是用來做一些過濾操作,比如:在過濾器中修改字元編碼;在過濾器中修改HttpServletRequest的一些引數,包括:過濾低俗文字、危險字元等。
(2)攔截器:
依賴於web框架,在實現上基於Java的反射機制,屬於面向切面程式設計(AOP)的一種運用。由於攔截器是基於web框架的呼叫,因此可以使用Spring的依賴注入(DI)進行一些業務操作,同時一個攔截器例項在一個controller生命週期之內可以多次呼叫。
1、常見應用場景
1)日誌記錄:記錄請求資訊的日誌,以便進行資訊監控、資訊統計、計算PV(Page View)等。
2)許可權檢查:如登入檢測,進入處理器檢測是否登入,如果沒有直接返回到登入頁面;
3)效能監控:有時候系統在某段時間莫名其妙的慢,可以通過攔截器在進入處理器之前記錄開始時間,在處理完後記錄結束時間,從而得到該請求的處理時間(如果有反向代理,如apache可以自動記錄);
4)通用行為:讀取cookie得到使用者資訊並將使用者物件放入請求,從而方便後續流程使用,還有如提取Locale、Theme資訊等,只要是多個Controller中的處理方法都需要的,我們就可以使用攔截器實現。
5)OpenSessionInView:如Hibernate,在進入處理器開啟Session,在完成後關閉Session。
…………本質也是AOP(面向切面程式設計),也就是說符合橫切關注點的所有功能都可以放入攔截器實現。
2、SpringMVC提供的攔截器介面:HandlerInterceptor
public interface HandlerInterceptor { boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; void postHandle( HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception; void afterCompletion( HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception; }
攔截器一個有3個回撥方法,而一般的過濾器Filter才兩個:
preHandle:預處理回撥方法,實現處理器的預處理(如登入檢查),第三個引數為響應的處理器返回值:true表示繼續流程(如呼叫下一個攔截器或處理器);false表示流程中斷(如登入檢查失敗),不會繼續呼叫其他的攔截器或處理器,此時我們需要通過response來產生響應;
postHandle:後處理回撥方法,實現處理器的後處理(但在渲染檢視之前),此時我們可以通過modelAndView(模型和檢視物件)對模型資料進行處理或對檢視進行處理,modelAndView也可能為null。
afterCompletion:整個請求處理完畢回撥方法,即在檢視渲染完畢時回撥,如效能監控中我們可以在此記錄結束時間並輸出消耗時間,還可以進行一些資源清理,類似於try-catch-finally中的finally,但僅呼叫處理器執行鏈中preHandle返回true的攔截器才會執行afterCompletion。
3、攔截器介面卡:HandlerInterceptorAdapter
有時我們可能只需要實現三個回撥方法中的某一個,如果實現HandlerInterceptor介面的話,三個方法必須實現,此時spring提供了一個HandlerInterceptorAdapter介面卡(一種介面卡設計模式的實現),允許我們只實現需要的回撥方法。
public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
}
public void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
}
public void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
public void afterConcurrentHandlingStarted(
HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
}
}
二、 自定義攔截器例項
1) 自定義兩個攔截器(繼承攔截器介面卡:HandlerInterceptorAdapter):HandlerInterceptor1 和 HandlerInterceptor2
public class HandlerInterceptor1 extends HandlerInterceptorAdapter{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("--1--HandlerInterceptor1.preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("--1--HandlerInterceptor1.postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("--1--HandlerInterceptor1.afterCompletion");
}
}
2)在 springmvc.xml 配置檔案中配置攔截器:
(1)攔截所有Controller類裡的所有處理方法
<!-- 配置攔截器:-->
<mvc:interceptors>
<!-- 會攔截所有Controller類裡的所有處理方法 -->
<bean class="cn.jq.sshweb.web.HandlerInterceptor1"></bean>
<bean class="cn.jq.sshweb.web.HandlerInterceptor2"></bean>
</mvc:interceptors>
如果 HandlerInterceptor2 中 preHandle 方法返回 false , 在訪問:http://127.0.0.1:8080/sshweb/ ,檢視沒有渲染
(2)只攔截某個請求路徑的處理方法
<!-- 配置攔截器:-->
<mvc:interceptors>
<!-- 會攔截所有Controller類裡的所有處理方法 -->
<bean class="cn.jq.sshweb.web.HandlerInterceptor1"></bean>
<mvc:interceptor>
<!-- 只攔截該路徑 -->
<mvc:mapping path="/users"/>
<bean class="cn.jq.sshweb.web.HandlerInterceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
(3)攔截器深入配置:注意 /** (任意分層路徑下) ,/* (該任意單路徑下)
<!-- 配置攔截器:-->
<mvc:interceptors>
<!-- 會攔截所有Controller類裡的所有處理方法 -->
<bean class="cn.jq.sshweb.web.HandlerInterceptor1"></bean>
<mvc:interceptor>
<!-- 只攔截該路徑 -->
<mvc:mapping path="/users"/>
<bean class="cn.jq.sshweb.web.HandlerInterceptor2"></bean>
</mvc:interceptor>
<mvc:interceptor>
<!-- 攔截所有請求,排除攔截 /toAdd 請求 -->
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/toAdd"/>
<bean class="cn.jq.sshweb.web.HandlerInterceptor3"></bean>
</mvc:interceptor>
</mvc:interceptors>