拦截器(interceptor)的作用
Spring MVC 的拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。
将拦截器按一定的顺序联结成一条链,这条链称为拦截器链(Interceptor Chain)。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。拦截器也是 AOP 思想的具体实现。
拦截器和过滤器区别
拦截器快速入门
自定义拦截器很简单,只有如下三步:
① 创建拦截器类实现HandlerInterceptor接口
② 配置拦截器
③ 测试拦截器的拦截效果
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Controller public class TargetController {
@RequestMapping("/target") public ModelAndView show(){ System.out.println("目标资源执行......"); ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("name","gaojie.cc"); modelAndView.setViewName("index"); return modelAndView; }
}
|
1 2 3 4 5
| <html> <body> <h2>Hello World! ${name}</h2> </body> </html>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| spring-mvc.xml
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/"/> <property name="suffix" value=".jsp"/> </bean>
<mvc:default-servlet-handler/>
<context:component-scan base-package="cc.gaojie.controller"/>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| web.xml
<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:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>DispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
|
1. 创建拦截器类实现HandlerInterceptor接口
HandlerInterceptor 接口中没有需要我们修饰的方法,是因为在接口内部所有的抽象方法都用 default 关键字修饰了。但方法体都是空的,因此需要我们手动覆盖。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class MyInterceptor1 implements HandlerInterceptor {
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle……"); return false; }
@Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle……"); }
@Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion……"); } }
|
2. 配置拦截器
1 2 3 4 5 6 7 8 9 10
| spring-mvc.xml
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="cc.gaojie.interceptor.MyInterceptor1"/> </mvc:interceptor> </mvc:interceptors>
|
3. 测试拦截器的拦截效果
可以发现,除了preHandle() 方法外,其他方法都没执行。这是因为 preHandle() 方法默认返回 false,后面的两个方法都不能再执行。
4. 修改拦实现截器类
修改拦实现截器类 MyInterceptor1,重新配置将 preHandle() 方法返回值修改为 true:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class MyInterceptor1 implements HandlerInterceptor {
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle……"); return true; }
@Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle……"); }
@Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion……"); } }
|
可以看到,当 preHandle() 方法返回值为 true 时,postHandle()、afterCompletion() 方法和目标资源都执行了。
拦截器方法解析
preHandle()
当 preHandle() 方法返回 true 时放行目标资源,返回 false 时不放行。我们可以借助方法形参中的 request 进行转发、response 进行重定向。在方法内部转向其他资源,避开目标资源。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle……"); String param = request.getParameter("param"); if ("yes".equals(param)){ return true; } else { request.getRequestDispatcher("/error.jsp").forward(request,response); return false; }
}
|
postHandle()
除 request、response 之外,可以借助方法形参中 modelAndView ,获取到封装好的模型和视图数据,进行修改。
1 2 3 4 5
| @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { modelAndView.addObject("name","SpringMVC"); System.out.println("postHandle……"); }
|
afterCompletion()
借助参数中的 ex,对封装后的异常进行处理。使用比较少。
多拦截器操作
新增拦截器类 MyInterceptor2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class MyInterceptor2 implements HandlerInterceptor {
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle2222……"); return true; }
@Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { System.out.println("postHandle2222……"); }
@Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { System.out.println("afterCompletion2222……"); }
}
|
配置拦截器
1 2 3 4 5 6 7 8 9 10 11 12 13
| <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="cc.gaojie.interceptor.MyInterceptor1"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="cc.gaojie.interceptor.MyInterceptor2"/> </mvc:interceptor> </mvc:interceptors>
|
测试拦截器的拦截效果
可以看到,先配置的拦截器先执行。