目錄
一、自定義攔截器類
首先創建如下項目:
在web.xml中配置DispatchServlet:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>springsun</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:application.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
在Controller容器中創建攔截/userinfo/toView.do請求的Handler方法:
package club.affengkuang.userinfo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class UserInfoController {
@RequestMapping("/userinfo/toView.do")
public String toView() {
System.out.println("toView......");
return "to";
}
}
接下來自定義攔截器:
創建AccessInterceptor類,實現HandlerInterceptor接口,並重寫接口中的三個抽象方法preHandle、postHandle、afterCompletion,攔截器便自定義完成:
package club.affengkuang.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
//創建一個HandlerInterceptor接口實現類
public class AccessInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
System.out.println("preHandle......");
return true;
}
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
throws Exception {
System.out.println("postHandle......");
}
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
System.out.println("afterCompletion......");
}
}
二、配置攔截器
在application中配置15到17行mvc:interceptors標籤內配置剛纔自定義好的AccessInterceptor類:
<?xml version="1.0" encoding="UTF-8"?>
<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:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<context:component-scan base-package="club.affengkuang"></context:component-scan>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/WEB-INF/view/" p:suffix=".jsp"></bean>
<mvc:interceptors>
<bean class="club.affengkuang.interceptor.AccessInterceptor"></bean>
</mvc:interceptors>
</beans>
測試:
三、執行順序
在請求處理過程中,攔截器中三個方法的執行順序如下:
1.preHandle
preHandle方法在目標方法(Handler方法)執行前執行,一般用於校驗,以下是底層代碼分析:
請求處理執行過程見博客:SpringMVC中servlet請求處理過程
當使用debug方式,執行到DispatchServlet類中doDispatch方法時:
第962行:進入applyPreHandle方法
進入applyPreHandle後:
第129行:創建一個上轉型對象數組,將所有攔截器對象賦值到父類接口的數組變量中,其中[1]中便是我們自定義的Accessinterceptor類對象
第131行:遍歷interceptors中每個元素
第133行:此處使用多態,表層調用的是接口中preHandle方法,實則調用的是上轉型對象重寫的preHandle方法,也就是我們實現的preHandle方法;
注意:在preHandle方法中返回值爲Boolean類型
①假設該方法返回false時,該行if語句爲true,執行if代碼塊
第135行:applyPreHandle方法返回false
上面的doDispatch方法中也直接結束執行,所以執行結果中只有preHandle方法被執行了:
②假設該方法返回true時,該行if語句爲true,執行第140行語句,返回true:
回到doDispatch方法:
第967行:handle方法處理servlet中請求
2.postHandle
接着上面的源碼分析:
進入第974行代碼中的applyPostHandle方法:執行原理與preHandle方法相同,只不過在第151行執行的是在AccessInterceptor類中實現的postHandle方法:
3.afterCompletion
隨後執行到第984行,進入processDispatchResult方法:
然後執行到processDispatchResult方法中:
第1027行:如果此時沒發生異常,exception爲null,則不執行此代碼;
第1059行:執行triggerAfterCompletion方法;
執行原理與前面兩個方法原理相同,此處169行執行的是在AccessInterceptor類中實現的afterCompletion方法