1.攔截器概述
1.1 什麼是攔截器?
Spring MVC中的攔截器(Interceptor)類似于Servlet中的過濾器(Filter),它主要用于攔截使用者請求并作相應的處理。例如通過攔截器可以進行權限驗證、記錄請求資訊的日志、判斷使用者是否登入等。
要使用Spring MVC中的攔截器,就需要對攔截器類進行定義和配置。通常攔截器類可以通過兩種方式來定義。
1.通過實作HandlerInterceptor接口,或繼承HandlerInterceptor接口的實作類(如HandlerInterceptorAdapter)來定義。
2.通過實作WebRequestInterceptor接口,或繼承WebRequestInterceptor接口的實作類來定義。
以實作HandlerInterceptor接口方式為例,自定義攔截器類的代碼如下:
public class CustomInterceptor implements HandlerInterceptor{
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler)throws Exception {
return false;
}
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 {
}
}
上述代碼中,自定義攔截器實作了HandlerInterceptor接口,并實作了接口中的三個方法:
-
preHandle() 方法:該方法會在控制器方法前執行,其傳回值表示是否中斷後續操作。當其傳回值為true時,表示繼續向下執行;
當其傳回值為false時,會中斷後續的所有操作(包括調用下一個攔截器和控制器類中的方法執行等)。
- postHandle()方法:該方法會在控制器方法調用之後,且解析視圖之前執行。可以通過此方法對請求域中的模型和視圖做出進一步的修改。
- afterCompletion()方法:該方法會在整個請求完成,即視圖渲染結束之後執行。可以通過此方法實作一些資源清理、記錄日志資訊等工作。
1.2 攔截器的配置
開發攔截器就像開發servlet或者filter一樣,都需要在配置檔案進行配置,配置代碼如下:
<!--配置攔截器-->
<mvc:interceptors>
<!--<bean class="com.ma.interceptor.CustomeInterceptor" />-->
<!--攔截器1-->
<mvc:interceptor>
<!--配置攔截器的作用路徑-->
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path=""/>
<!--定義在<mvc:interceptor>下面的表示比對指定路徑的請求才進行攔截-->
<bean class="com.ma.interceptor.Intercptor1"/>
</mvc:interceptor>
<!--攔截器2-->
<mvc:interceptor>
<mvc:mapping path="/hello"/>
<bean class="com.ma.interceptor.Interceptor2"/>
</mvc:interceptor>
上面的代碼中,<mvc:interceptors>元素用于配置一組攔截器,基子元素<bean>中定義的是全局攔截器,它會攔截所有的請求;而<mvc:interceptor>元素中定義的是指定路徑的攔截器,它會對指定路徑下的請求生效。<mvc:interceptor>元素的子元素<mvc:mapping>用于配置攔截器作用的路徑,該路徑在其屬性path 中定義。如上述代碼中 path 的屬性值“/**” 表示攔截所有路徑,“/hello” 表示攔截所有以 “/hello” 結尾的路徑。如果在請求路徑中包含不需要攔截的内容,還可以通過<mvc:exclude-mapping>元素進行配置。
注意:<mvc:interceptor>中的子元素必須按照上述代碼中的配置順序進行編寫,即<mvc:mapping> <mvc:exclude-mapping> <bean>,否則檔案會報錯。
2. 攔截器的執行流程
2.1 單個攔截器的執行流程
在運作程式時,攔截器的執行是有一定順序的,該順序與配置檔案中所定義的攔截器的順序相關。
單個攔截器,在程式中的執行流程如下圖所示:
1.程式先執行preHandle()方法,如果該方法的傳回值為true,則程式會繼續向下執行處理器中的方法,否則将不再向下執行。
2.在業務處理器(即控制器Controller類)處理完請求後,會執行postHandle()方法,然後會通過DispatcherServlet向用戶端傳回響應。
3.在DispatcherServlet處理完請求後,才會執行afterCompletion()方法。
測試案例:
通過一個測試程式來驗證它的執行流程。
建立一個web項目,準備好SpringMVC程式運作所需要的JAR包,在web.xml中配置前端過慮器和初始化加載資訊。
建立一個測試controller,代碼如下:
/**
* @author mz
* @version V1.0
* @Description: 攔截器測試
*/
@Controller
public class HelloController {
@RequestMapping("/hello")
public String Hello() {
System.out.println("Hello!");
return "success";
}
}
然後,建立一個攔截器,實作HandlerInterceptor接口,并實作其中的方法。
/**
* @author mz
* @version V1.0
* @Description: 實作了HandlerInterceptor接口的自定義攔截器類
*/
public class CustomeInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o)
throws Exception {
System.out.println("CustomInterceptor....preHandle");
//對浏覽器的請求進行放行處理
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView)
throws Exception {
System.out.println("CustomInterceptor....postHandle");
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e)
throws Exception {
System.out.println("CustomInterceptor....afterCompletion");
}
}
在配置檔案中配置攔截器。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!--定義元件掃描器,指定需要掃描的包-->
<context:component-scan base-package="com.ma.controller"/>
<!-- 配置視圖解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--配置攔截器-->
<mvc:interceptors>
<bean class="com.ma.interceptor.CustomeInterceptor" />
</beans>
把項目釋出到tomcat中,運作測試:
2.2 多個攔截器的執行流程
多個攔截器(假設有兩個攔截器Interceptor1和Interceptor2,并且在配置檔案中, Interceptor1攔截器配置在前),在程式中的執行流程如下圖所示:
從圖可以看出,當有多個攔截器同時工作時,它們的preHandle()方法會按照配置檔案中攔截器的配置順序執行,而它們的postHandle()方法和afterCompletion()方法則會按照配置順序的反序執行。
測試案例:
建立兩個攔截器:
/**
* @author mz
* @version V1.0
* @Description: 第一個攔截器
*/
public class Intercptor1 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.println("Interceptor1....preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("Interceptor1....postHandle");
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("Interceptor1....afterCompletion");
}
/**
* @author mz
* @version V1.0
* @Description: 第二個攔截器
*/
public class Interceptor2 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.println("Interceptor2....preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("Interceptor2....postHandle");
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("Interceptor2....afterCompletion");
}
}
添加配置資訊:
<!--攔截器1-->
<mvc:interceptor>
<!--配置攔截器的作用路徑-->
<mvc:mapping path="/**"/>
<!--定義在<mvc:interceptor>下面的表示比對指定路徑的請求才進行攔截-->
<bean class="com.ma.interceptor.Intercptor1"/>
</mvc:interceptor>
<!--攔截器2-->
<mvc:interceptor>
<mvc:mapping path="/hello"/>
<bean class="com.ma.interceptor.Interceptor2"/>
</mvc:interceptor>
測試運作:
從結果可以看出,執行的順序和圖檔中是一樣的。
如果第一個攔截器return true; 而第二個攔截器 return false;結果如下:
小結
首先學習如何在Spring MVC項目中定義和配置攔截器,然後了解單個攔截器和多個攔截器的執行流程。