目录
一、自定义拦截器类
首先创建如下项目:
在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方法