攔截器,顧名思義就是用來攔截的。
那什么是攔截,又為什么要攔截。對於Spring MVC來說,攔截器主要的工作對象就是用戶的請求,攔截下來之后,我們可以在攔截的各個階段悉心呵護【為所欲為】。常見的比如可以做權限驗證,登錄系統后,系統獲取到你的請求然后分析下你的用戶權限,是Administrator還是User還是Guest。
主要相關類和方法
HandlerExecutionChain
該類主要由handler和handler interceptors組成
HandlerMapping類通過getHandler方法會調用到該類
HandlerInterceptor
Spring MVC中對於一個請求可以添加多個攔截器,而這個攔截器集合中會鏈式調用這些攔截器。每個攔截器會執行固定順序的方法,而這些方法就定義在HandlerInterceptor類中。
這是攔截器的一個基礎接口,里面有三個方法
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
使用時機:在處理請求之前
應用場景:可以在該方法中放入一些初始化的操作,比如權限驗證,日志管理等
注意:該方法的返回值是boolean類型,若返回值為true,則繼續調用后面的攔截器和目標方法,若返回為false,則不會調用后面的攔截器和目標方法,表示請求結束
void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception;
使用時機:在調用目標方法之后,渲染視圖之前被調用。具體來說,是在調用了Controller中定義的方法之后,但在DispatcherServlet 處理視圖返回渲染結果之前被調用。
應用場景:根據使用的時機就可以知道,該方法可以對Controller處理之后ModelAndView進行操作
注意:當有多個interceptor的時候,對於preHandler的調用順序和postHandler的調用順序是恰恰想法的。
舉例來說,現在有一個FirstInterceptor和一個SecondInterceptor,單獨調用FirstInterceptor的三個方法的順序為:
FirstInterceptor.preHandle->HandlerAdapter.handle->FirstInterceptor.postHanle->DispatcherServlet.render->FirstInterceptor.afterCompletion。
對於兩個interceptor的調用順序大致如下:
可以總結出preHandler是先進先執行,而postHandler是先進后執行
void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception;
使用時機:渲染視圖之后
應用場景:釋放資源
具體應用
新建攔截器類FirstInterceptor
該類需實現HandlerInterceptor接口
package com.jackie.springmvc.interceptors; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; public class FirstInterceptor implements HandlerInterceptor{ @Override public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception { System.out.println("Interceptor:afterCompletion"); } @Override public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception { System.out.println("Interceptor:postHandle"); } @Override public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception { System.out.println("Interceptor:preHandle"); return true; } }
在三個方法中分別打印當前方法信息,通過執行,看這些方法是否執行以及執行的順序。
配置springmvc.xml
<mvc:interceptors> <bean class="com.jackie.springmvc.interceptors.FirstInterceptor"></bean> </mvc:interceptors>
最后啟動tomcat服務,得到控制台輸出結果為:
Interceptor:preHandle
Interceptor:postHandle
Interceptor:afterCompletion
機智的你,可能會萌生一個想法,對於定義的這個FirstInterceptor,我並不想在任何場景下都要使用它,能不能再指定的場景下執行相應的攔截器,或者指定的場景下不執行呢,答案是肯定的!
首先我們還是要新建另外一個攔截器SecondInterceptor
package com.jackie.springmvc.interceptors; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; public class SecondInterceptor implements HandlerInterceptor{ @Override public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception { System.out.println("SecondInterceptor:afterCompletion"); } @Override public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception { System.out.println("SecondInterceptor:postHandle"); } @Override public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception { System.out.println("SecondInterceptor:preHandle"); return true; } }
同時在springmvc.xml中添加
<mvc:interceptors> <bean class="com.jackie.springmvc.interceptors.FirstInterceptor"></bean> <!-- 配置攔截器(不)作用的路徑 --> <mvc:interceptor> <mvc:mapping path="/emps"/> <bean class="com.jackie.springmvc.interceptors.SecondInterceptor"></bean> </mvc:interceptor> </mvc:interceptors>
這樣我們在/emps下才能使SecondInterceptor有效,其他路徑的請求就不會觸發這個攔截器,效果如下:
至此,我們明白了:
- 什么是攔截器
- 攔截器的作用
- 如何使用攔截器
如果您覺得閱讀本文對您有幫助,請點一下“推薦”按鈕,您的“推薦”將是我最大的寫作動力!如果您想持續關注我的文章,請掃描二維碼,關注JackieZheng的微信公眾號,我會將我的文章推送給您,並和您一起分享我日常閱讀過的優質文章。
友情贊助
如果你覺得博主的文章對你那么一點小幫助,恰巧你又有想打賞博主的小沖動,那么事不宜遲,趕緊掃一掃,小額地贊助下,攢個奶粉錢,也是讓博主有動力繼續努力,寫出更好的文章^^。
1. 支付寶 2. 微信