tsx81428 发表于 2023-12-14 05:00:14

12、SpringMVC之拦截器

12.1、环境搭建

创建名为spring_mvc_interceptor的新module,过程参考9.1节和9.5节
12.1.1、页面请求示例

https://img2023.cnblogs.com/blog/2052479/202311/2052479-20231107165407618-229864532.png
<a th:target="_blank" href="https://www.cnblogs.com/@{/test/hello}">测试拦截器</a>12.1.2、控制器方法示例

https://img2023.cnblogs.com/blog/2052479/202311/2052479-20231107165616687-1570005521.png
    @RequestMapping("/test/hello")
    public String testHello(){
      return "success";
    }12.2、拦截器的入门示例

12.2.1、创建拦截器

https://img2023.cnblogs.com/blog/2052479/202311/2052479-20231107173122173-606692993.png
package online.liaojy.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* @author liaojy
* @date 2023/11/7 - 20:57
*/
// SpringMVC 中的拦截器要实现 HandlerInterceptor 接口
public class AAAInterceptor implements HandlerInterceptor {

    // preHandle()方法在控制器方法执行之前执行
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
      System.out.println("AAAInterceptor-->preHandle()");

      // 返回true表示不拦截,即执行控制器方法
      // 返回false表示拦截,即不再执行控制器方法
      return true;
    }

    // postHandle()方法在控制器方法执行之后执行
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
      System.out.println("AAAInterceptor-->postHandle()");
    }

    // afterCompletion()方法在渲染完视图之后执行
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
      System.out.println("AAAInterceptor-->afterCompletion()");
    }

}12.2.2、配置拦截器

与自定义的过滤器一样,自定义的拦截器也要配置后才能生效;
过滤器是服务器中的组件,所以配置到 web.xml 中;
拦截器是 springmvc 中的组件,因此要配置到 springmvc 的配置文件中。
https://img2023.cnblogs.com/blog/2052479/202311/2052479-20231107174747912-2127089876.png
    <mvc:interceptors>
      <bean ></bean>
    </mvc:interceptors>12.2.3、测试效果

https://img2023.cnblogs.com/blog/2052479/202311/2052479-20231107175039847-1440054239.png
https://img2023.cnblogs.com/blog/2052479/202311/2052479-20231107175059076-2109197155.png
因为在配置拦截器时,没有指定要拦截的路径,所以访问任何DispatcherServlet处理的资源时,拦截器都会执行。
https://img2023.cnblogs.com/blog/2052479/202311/2052479-20231107180410089-1323948772.png
https://img2023.cnblogs.com/blog/2052479/202311/2052479-20231107180434414-951844420.png
https://img2023.cnblogs.com/blog/2052479/202311/2052479-20231107180541981-594149792.png
12.3、拦截器的注解配置

除了使用 bean 标签通过全限定类名来配置拦截器,还可以通过 ref 标签引用已存在的 bean 组件来配置拦截器
12.3.1、将拦截器标识为bean组件

https://img2023.cnblogs.com/blog/2052479/202311/2052479-20231108111614742-1559248838.png
因为拦截器不属于持久层、业务层和控制层,所以应该用 @Component 注解将其标识为一个 bean 组件
@Component12.3.2、通过ref标签引用配置拦截器

https://img2023.cnblogs.com/blog/2052479/202311/2052479-20231108111712896-1021595332.png
    <mvc:interceptors>
      <bean ></bean>
    </mvc:interceptors>12.4、拦截器的进阶示例

通过上述的方式来配置拦截器,会对 DispatcherServlet 所处理的所有请求都进行拦截;
在实际情况中,可能只需要拦截部分请求,或排除部分请求的拦截。
12.4.1、精确的拦截配置

https://img2023.cnblogs.com/blog/2052479/202311/2052479-20231108114938161-1994464294.png
    <mvc:interceptors>
      <bean ></bean>
    </mvc:interceptors>    <mvc:interceptors>
      <bean ></bean>
    </mvc:interceptors>    <mvc:interceptors>
      <bean ></bean>
    </mvc:interceptors>    <mvc:interceptors>
      <bean ></bean>
    </mvc:interceptors>    <mvc:interceptors>
      <bean ></bean>
    </mvc:interceptors>    <mvc:interceptors>
      <bean ></bean>
    </mvc:interceptors>12.4.2、测试效果

https://img2023.cnblogs.com/blog/2052479/202311/2052479-20231108115754276-1761901482.png
https://img2023.cnblogs.com/blog/2052479/202311/2052479-20231108115908137-47683975.png
如上图所示,拦截了一级路径的请求
https://img2023.cnblogs.com/blog/2052479/202311/2052479-20231108120050903-1916396296.png
https://img2023.cnblogs.com/blog/2052479/202311/2052479-20231108120129577-568123798.png
https://img2023.cnblogs.com/blog/2052479/202311/2052479-20231108120154334-362161578.png
如上图所示,拦截了二级路径的请求
https://img2023.cnblogs.com/blog/2052479/202311/2052479-20231108165003989-234086442.png
https://img2023.cnblogs.com/blog/2052479/202311/2052479-20231109092203340-1852852298.png
如上图所示,没有拦截/abc的请求
注意:为实现演示效果,本例已在springmvc配置文件中设置了关于/abc请求的视图控制器
12.5、多个拦截器的执行顺序

12.5.1、创建另一个拦截器

https://img2023.cnblogs.com/blog/2052479/202311/2052479-20231109093252051-1256129594.png
package online.liaojy.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* @author liaojy
* @date 2023/11/9 - 7:27
*/
public class BBBInterceptor implements HandlerInterceptor {
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
      System.out.println("BBBInterceptor-->preHandle()");
      return true;
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
      System.out.println("BBBInterceptor-->postHandle()");
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
      System.out.println("BBBInterceptor-->afterCompletion()");
    }
}12.5.2、配置多个拦截器

https://img2023.cnblogs.com/blog/2052479/202311/2052479-20231109092622297-320536978.png
    <mvc:interceptors>
      <bean ></bean>
    </mvc:interceptors>      12.5.3、情况一


[*]如果每个拦截器的preHandle()都返回true
[*]此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关
[*]preHandle()会按照配置的顺序执行,而postHandle()和afterCompletion()会按照配置的反序执行
https://img2023.cnblogs.com/blog/2052479/202311/2052479-20231109095148228-358785546.png
https://img2023.cnblogs.com/blog/2052479/202311/2052479-20231109093509292-1137740476.png
注意:此时 AAAInterceptor 和 BBBInterceptor 拦截器的 preHandle() 方法返回值都是 true
12.5.4、情况二


[*]如果某个拦截器的preHandle()返回了false
[*]返回false的拦截器和它之前的拦截器的preHandle()都会执行
[*]所有postHandle()都不执行
[*]返回false的拦截器之前的拦截器的afterCompletion()会执行
https://img2023.cnblogs.com/blog/2052479/202311/2052479-20231109095054160-250797297.png
https://img2023.cnblogs.com/blog/2052479/202311/2052479-20231109093829311-771772134.png
注意:此时 AAAInterceptor 拦截器的 preHandle() 方法返回值为true,而 BBBInterceptor 拦截器的为 false
12.5.5、执行顺序流程图

https://img2023.cnblogs.com/blog/2052479/202311/2052479-20231109173436961-907228830.png
12.6、相关拓展

12.6.1、拦截器与过滤器的区别


[*]过滤器是 Tomcat 服务器中的对象,拦截器是 SpringMVC 框架中的对象;
[*]过滤器实现的是 Java 中的 Filter 接口,拦截器实现的是 SpringMVC 中的 HandleInterceptor 接口;
[*]过滤器配置在 web.xml 中,拦截器配置在 SpringMVC 配置文件中;
[*]过滤器在拦截器之前执行;
[*]过滤器是一个执行时间点;拦截器是三个执行时间点;
[*]过滤器除了对动态资源进行过滤之外,还可以对静态资源(HTML、CSS、JS、图片等)进行过滤;
[*]拦截器侧重对控制器方法进行拦截处理,如果一个请求不能被DispatcherServlet接收,那这个请求也不会被拦截器处理。
12.6.2、拦截器的应用场景


[*]权限校验:用户在访问某资源时,可以使用拦截器对用户请求进行拦截,
判断当前用户有没有登录,如果没有登录则强制回到登录页面进行登录。
[*]性能监控:如果想统计用户访问某个控制器方法的时间,可以使用拦截器对控制器方法进行前置拦截和后置拦截,
在前置拦截器里面记录用户访问资源的起始时间,在后置拦截器里面记录用户访问资源的结束时间,
两个时间之差就是当前用户访问控制器方法是总时长。
[*]日志记录:记录请求资源的日志信息,比如请求方式、请求参数、请求响应等,都可以通过拦截器来实现信息记录。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 12、SpringMVC之拦截器