第二节 拦截器
1、概念
①拦截器和过滤器解决类似的问题
[1]生活中坐地铁的场景
[2]程序中
②拦截器 VS 过滤器
[1]相似点
[2]不同点
[3]选择
2、使用
①创建拦截器类
[1]实现接口
[2]继承类
②注册拦截器
[1]默认拦截全部请求
[2]配置拦截路径
(1)精确匹配
(2)模糊匹配:匹配单层路径
(3)模糊匹配:匹配多层路径
[3]配置不拦截路径
③多个拦截器执行顺序
④多个拦截器总体执行流程
3、拦截器的具体应用
① preHandle()方法
②postHandle()方法
③afterCompletion()方法

第二节 拦截器

1、概念

①拦截器和过滤器解决类似的问题

[1]生活中坐地铁的场景

为了提高乘车效率,在乘客进入站台前统一检票:
02 拦截器 - 图1

[2]程序中

在程序中,使用拦截器在请求到达具体 handler 方法前,统一执行检测。
02 拦截器 - 图2

②拦截器 VS 过滤器

[1]相似点

三要素相同

  • 拦住:必须先把请求拦住,才能执行后续操作
  • 过滤:拦截器或过滤器存在的意义就是对请求进行统一处理
  • 放行:对请求执行了必要操作后,放请求过去,让它访问原本想要访问的资源;也不能不放行,比如安全验证中没有登录。

[2]不同点

  • 工作平台不同
    • 过滤器工作在 Servlet 容器中
    • 拦截器工作在 SpringMVC 的基础上
  • 拦截的范围
    • 过滤器:能够拦截到的最大范围是整个 Web 应用
    • 拦截器:能够拦截到的最大范围是整个 SpringMVC 负责的请求(看DispatcherServlet的的设置是/还是*.action)
    • 02 拦截器 - 图3

  • IOC 容器支持
    • 过滤器:想得到 IOC 容器需要调用专门的工具方法,是间接的
    • 拦截器:它自己就在 IOC 容器中,所以可以直接从 IOC 容器中装配组件,也就是可以直接得到 IOC 容器的支持

[3]选择

功能需要如果用 SpringMVC 的拦截器能够实现,就不使用过滤器。

2、使用

①创建拦截器类

[1]实现接口

public class Process01Interceptor implements HandlerInterceptor {

  1. Logger logger = LoggerFactory.getLogger(this.getClass());
  2. // 在处理请求的目标 handler 方法前执行<br /> @Override<br /> public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  3. logger.debug("Process01Interceptor preHandle方法");
  4. // 返回true:放行<br /> // 返回false:不放行<br /> return true;<br /> }
  5. // 在目标 handler 方法之后,渲染视图之前<br /> @Override<br /> public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  6. logger.debug("Process01Interceptor postHandle方法");
  7. }
  8. // 渲染视图之后执行<br /> @Override<br /> public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  9. logger.debug("Process01Interceptor afterCompletion方法");
  10. }<br />}

单个拦截器执行顺序:

  • preHandle() 方法
  • 目标 handler 方法
  • postHandle() 方法
  • 渲染视图
  • afterCompletion() 方法

02 拦截器 - 图4

[2]继承类

在较低版本的 SpringMVC 中,实现 HandlerInterceptor 接口需要把所有抽象方法都实现。但是又不是每个方法都需要使用,导致代码比较繁琐。
此时可以通过继承 HandlerInterceptorAdapter 类同样可以创建拦截器类。HandlerInterceptorAdapter 类中已经给 HandlerInterceptor 接口提供了默认实现,我们继承后不需要把每个方法都实现,只需要把有用的方法重写即可。
在 SpringMVC 较高版本(例如:5.3版本以上)中,HandlerInterceptor 接口已经借助 JDK 1.8 新特性让每个抽象方法都给出了默认实现,所以 HandlerInterceptorAdapter 这个类被标记为过时。
@Deprecated
public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor {

}

②注册拦截器

[1]默认拦截全部请求

下配置的拦截器是全局拦截器,无需配置拦截路径,拦截经过DispatcherServlet的所有请求。




[2]配置拦截路径

下配置的拦截器是局部拦截器,需要配置拦截路径。

(1)精确匹配






(2)模糊匹配:匹配单层路径





(3)模糊匹配:匹配多层路径





[3]配置不拦截路径





<bean class="com.atguigu.mvc.interceptor.Process05Interceptor"/><br /></mvc:interceptor>

③多个拦截器执行顺序

按照配置的顺序执行,不管是全局拦截器,还是局部拦截器。

④多个拦截器总体执行流程

  • preHandle()方法:和配置的顺序一样
  • 目标handler方法
  • postHandle()方法:和配置的顺序相反
  • 渲染视图
  • afterCompletion()方法:和配置的顺序相反

    查看源码:org.springframework.web.servlet.HandlerExecutionChain
    02 拦截器 - 图5

02 拦截器 - 图6

02 拦截器 - 图7

3、拦截器的具体应用

① preHandle()方法

例如:解决中文乱码问题,安全验证(判断是否已经登录),页面跳转(系统维护中)等
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
log.debug(“—————HelloInterceptor preHandle—————“);
//return true:放行
//作用1:解决中文乱码问题
//request.setCharacterEncoding(“utf-8”);
//作用2:判断用户是否登录
//2.1 放行登录页面
if(request.getRequestURI().contains(“login.jsp”)){
return true;
}
//2.2 放行登录Controller
if(request.getRequestURI().contains(“login.action”)){
return true;
}
//2.3 如果没有登录,重定向到登录页面
Object user = request.getSession().getAttribute(“user”);
if(user==null){
response.sendRedirect(request.getContextPath()+”/login.jsp”);
return false;
}
//2.4 如果已经登录,放行
return true;
//作用3:页面跳转(网站维护中….)
//response.sendRedirect(request.getContextPath()+”/maintain.jsp”);
//return false;

}

②postHandle()方法

例如:网站升级测试时,跳转到新版测试页面;进行敏感字符替换等
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
log.debug(“—————HelloInterceptor postHandle—————“);

//作用1:网站升级时,再次修改跳转路径,跳转到测试的页面<br />    //modelAndView.setViewName("redirect:/index2.jsp");<br />    //作用2:敏感字符替换<br />    String obj = (String)modelAndView.getModel().get("error");<br />    if(obj.contains("zhangsan")){//枪支、黄色、反动<br />        obj = obj.replace("zhangsan","**");<br />        modelAndView.addObject("error",obj);<br />    }<br />}

③afterCompletion()方法

例如:完成资源关闭,异常处理等操作

上一节 回目录 下一节