SpringMVC 中的 Interceptor 攔截器是非常重要和相當有用的,它的主要作用是攔截指定的用戶請求,并進行相應的預處理與后處理。其攔截的時間點在“處理器映射器根據用戶提交的請求映射出了所要執行的處理器類,并且也找到了要執行該處理器類的處理器適配器,在處理器適配器執行處理器之前”。當然,在處理器映射器映射出所要執行的處理器類時,已經將攔截器與處理器組合為了一個處理器執行鏈,并返回給了中央調度器。
項目:interceptor。
自定義攔截器
自定義攔截器,需要實現 HandlerInterceptor 接口。而該接口中含有三個方法:
● preHandle(request, response, Object handler):
該方法在處理器方法執行之前執行。其返回值為 boolean,若為 true,則緊接著會執行處理器方法,且會將 afterCompletion()方法放入到一個專門的方法棧中等待執行。
● postHandle(request, response, Object handler, modelAndView):
該方法在處理器方法執行之后執行。處理器方法若最終未被執行,則該方法不會執行。
由于該方法是在處理器方法執行完后執行,且該方法參數中包含 ModelAndView,所以該方法可以修改處理器方法的處理結果數據,且可以修改跳轉方向。
● afterCompletion(request, response, Object handler, Exception ex):
當 preHandle()方法返回 true 時,會將該方法放到專門的方法棧中,等到對請求進行響應的所有工作完成之后才執行該方法。即該方法是在中央調度器渲染(數據填充)了響應頁面之后執行的,此時對 ModelAndView 再操作也對響應無濟于事。
攔截器中方法與處理器方法的執行順序如下圖:
換一種一表現方式,也可以這樣理解:
1、注冊攔截器
用于指定當前所注冊的攔截器可以攔截的請求路徑,而/**表示攔截所 有請求。
2、修改 index 頁面
3、修改處理器
4、修改 show 頁面
5、控制臺輸出結果
項目:interceptor2。在項目 interceptor 基礎上修改。
1、再定義一個攔截器
2、多個攔截器的注冊與執行
3、控制臺執行結果
當有多個攔截器時,形成攔截器鏈。攔截器鏈的執行順序,與其注冊順序一致。需要再次強調一點的是,當某一個攔截器的 preHandle()方法返回 true 并被執行到時,會向一個專門的方法棧中放入該攔截器的 afterCompletion()方法。
多個攔截器中方法與處理器方法的執行順序如下圖:
將處理器執行鏈返回給中央控制器
從圖中可以看出,只要有一個 preHandle()方法返回 false,則上部的執行鏈將被斷開, 其后續的處理器方法與 postHandle()方法將無法執行。但,無論執行鏈執行情況怎樣,只要方法棧中有方法,即執行鏈中只要有 preHandle()方法返回 true,就會執行方法棧中的afterCompletion()方法。最終都會給出響應。
換一種一表現方式,也可以這樣理解:
4、 閱讀源碼
查看中央調度器 DispatcherServlet 的 doDispatch()方法源碼:在執行處理器方法之前, 會執行處理器執行鏈對象 mappedHandler 的 applyPreHandle()方法。然后執行 Handler,最后 執行處理器執行鏈對象的 applyPostHandle()方法。
applyPreHandle()方法用于執行處理器執行鏈中的所有攔截器的 preHandle()方法。
applyPreHandle()方法的返回結果取決于執行鏈中的每一個攔截器的 preHandle()方法。只要 有一個 preHandle()方法返回 false,則其就會返回 false。然后就執行了 return;即結束了 doDispatch()方法,即該請求的處理結束。
對于處理器執行鏈的 applyPostHandle()方法,其是循環倒序執行所有攔截器的 postHandle()方法的。
那么 afterCompletion()方法是什么時候執行的呢?
在剛才的處理器執行鏈的 applyPreHandle()方法中看到,若存在任一個攔截器的 preHandle()方法返回 false,則會調用執行處理器執行鏈的 triggerAfterCompletion()方法,即 會觸發所有 afterCompletion()方法的執行。
在 doDispatch()方法中也存在一個 catch(){}語句,表示若發生異常,則會調用執行 triggerAfterCompletion()方法。
但在正常情況下,即所有的 preHandle()方法返回均為 true,且 doDispatch()方法沒有異 常發生的情況下,afterCompletion()方法是在視圖解析器后執行的。
查看中央調度器 DispatcherServlet 的 processDispatchResult()方法源碼可知,在對視圖渲 染過后,會調用執行處理器執行鏈的 triggerAfterCompletion() 方法,即執行所有的 afterCompletion()方法。
打 開 處 理 器執 行 鏈的 triggerAfterCompletion() 方法 , 可 以 看到 , 其對攔 截 器 的 afterCompletion()方法的執行,也是循環倒序執行的。
只有經過登錄的用戶方可訪問處理器,否則,將返回“無權訪問”提示。
本例的登錄,由一個 JSP 頁面完成。即在該頁面里將用戶信息放入 session 中。也就是說,只要訪問過該頁面,就說明登錄了。沒訪問過,則為未登錄用戶。
項目:interceptor_permission。在項目 interceptor1 基礎上修改。
1、修改 index 頁面
2、定義 Controller
3、定義 welcome 頁面
4、定義權限攔截器
當 preHandle()方法返回 false 時,需要使用 request 或 response 對請求進行響應。
5、定義 fail 頁面
6、注冊權限攔截器
7、定義 login 頁面
8、定義 logout 頁面
9、項目測試
Step1:在地址欄先直接提交 system.do 請求
Step2:訪問 login.jsp,進行用戶登錄
Step3:再次提交 system.do 請求
Step4:訪問 logout.jsp,進行用戶退出
Step5:三次提交 system.do 請求