说起 Spring MVC 框架的拦截器,就不得不提起原生 Servlet 中的过滤器,两者的功能性质是一样的,但底层实现机制会有差异性。拦截器用到了代理设计模式,是 Spring AOP 的具体实际应用。过滤器使用的是函数回调机制。
本节课程将和大家一起学习 Spring MVC 中的拦截器。通过本节课程,你将了解到拦截器的工作模式及基础原理。重点是要掌握拦截器的实现过程。
拦截器是什么?
拦截器就是一个功能模块,工作模式决定了其与众不同:
Spring MVC 中的拦截器和 Servlet 中的过滤器的生命周期、以及服务的目标有差异性。过滤器的生命周期由服务器维护,当请求包进入服务器或响应包即将离开服务器时,过滤器将起作用。
过滤器是在 DispatcherServlet 之前或之后工作,拦截器是请求经过 DispatcherServlet 后进行拦截。
拦截器属于 Spring MVC 组件,生命周期由 Spring 上下文容器对象维护。从细节上讲,拦截器可以在用户控制器之前、之后或视图渲染完成之后行使拦截工作。
拦截器可以解决很多实际问题:
除以上应用场景之外,你可以根据自己的业务需要灵活选择。
Spring MVC 内置有很多拦截器。这些拦截器提供的功能,基本上能够满足开发者完成常规开发。但是,需求总是瞬息变化的,开发者可以根据自己的业务需求自定义拦截器。
自定义拦截器之前,首先要了解 Spring MVC 提供的拦截器接口,自定义拦截器必须遵循此接口规范。
public interface HandlerInterceptor {
/** * 用户控制器之前拦截,实现用户控制器数据的预处理工作,第三个参数为响应的用户控制器 */
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
}
/** *对用户控制器处理后的数据再进一步处理 */
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
}
/** * 视图解析器对 View 渲染完成后对最后结果进行处理 */
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) throws Exception {
}
}
Spring MVC 提供有拦截器适配器,适配器对拦截器接口做了简单封装。
public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor{
//……
}
开发者可以通过实现接口或继承适配器这 2 种方式开发自己的拦截器。如自定义一个拦截器,监控控制器处理时间。
public class MyInterceptor extends HandlerInterceptorAdapter {
private long startTimer;
private long endTimer;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//调用控制器之前的时间
startTimer = System.currentTimeMillis();
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//控制器处理完成后的时间
endTimer = System.currentTimeMillis();
System.out.println(endTimer-startTimer);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//输出页面渲染完成后的时间
System.out.println("完成拦截器工作");
}
}
注解方式: 打开 WebConfig 文件,添加如下代码。
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
MyInterceptor myInterceptor = new MyInterceptor();
registry.addInterceptor(myInterceptor).addPathPatterns("/student/*");
}
Tips: 此拦截器仅对 /student/* 请求地址有效。
xml 方式:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="需要拦截的路径"/>
<bean class="自定义interceptor全路径名">
</mvc:interceptor>
</mvc:interceptors>
Tips:本课程以注解为主,XML 在这里只做简要介绍。
@RequestMapping("/student")
public class StudentAction {
@RequestMapping("/test")
public String interceptor() {
return "index";
}
}
所谓拦截器链,指多个拦截器一起协作工作,拦截器一起工作时,请注意拦截器中的各个方法之间的调用顺序。
前面拦截器的 preHandle 方法的返回值会影响后面的拦截器和控制器是否正常工作:
Tips : 如果第一个拦截器的 preHandle 方法返回 true,则会进入第二个拦截器。如果第二个拦截器的 preHandle 方法 返回 false,则直接进入第一个拦截器的 afterCompletion 方法。
本章节和大家讲解了 Spring MVC 的拦截器,需要大家掌握拦截的工作原理以及实现自定义拦截器。特别注意的是要理解多个拦截器在一起协作工作时方法之间是如何调用的。
0/1000