# 拦截器

# 拦截器概念

image_2023-03-06-15-53-36

  • 拦截器 (Interceptor) 是一种动态拦截方法调用的机制,在 SpringMvc 中动态拦截控制器方法的执行

  • 作用:

    • 在指定的方法调用前后执行预先设定的代码
    • 阻止原始方法的执行

# 拦截器与过滤器区别

  • 归属不同:Filter 属于 Servlet 技术,Interceptor 属于 SpringMvc 技术

  • 拦截内容不同:Filter 对所有访问进行增强,Interceptor 仅针对 SpringMvc 的访问进行增强

# 入门案例

  1. 制作拦截器功能类
  • 生命拦截器的 bean, 并实现 HandlerInterceptor 接口 (注意:扫描加载 bean)
@SuppressWarnings("all")
@Component
public class ProjectInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandler ...");
//        改为 false 将终止原始操作的执行,如果终止了原始操作那么后面的方法也不会被执行
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandler ...");
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterHandler ...");
    }
}
  • 定义配置类,继承 WebMvcConfigurationSupport, 实现 addInterceptor 方法 (注意:扫描加载配置)
@SuppressWarnings("all")
// 配置 bean
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        ...
    }
}

addResourceHandlers 的详细介绍

SpringBoot 中,addResourceHandlers 方法用于配置静态资源的方式。通过该方法,你可以指定哪些路径下的静态资源应该被处理,以及如何处理它们。这些静态资源通常包括 CSS 文件,JavaScript 文件,图像文件等。

addResourceHandlers 方法详解

addResourceHandlers 方法定义在 WebMvcConfigurer 接口中,用于自定义 SpringMVC 的配置。你可以通过实现 WebMvcConfigurer 接口并覆盖 addResourceHandlers 方法来配置资源处理器,以下是一个示例,展示了如何配置静态资源处理:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // 将请求路径 /static/** 映射到类路径下的 /static/ 目录
        registry.addResourceHandler("/static/**")
                .addResourceLocations("classpath:/static/")
                .setCachePeriod(3600) // 设置缓存时间为 3600 秒
                .resourceChain(true); // 启用资源链优化
    }
}

关键配置选项

  1. addResourceHandler(String... pathPatterns)
    • 该方法用于指定应该拦截的 URL 路径模式。例如:/static/** 表示拦截所有以 /static/ 开头的请求
  2. addResourceLocations(String... resourceLocations)
    • 该方法用于指定静态资源的存储位置。可以是文件系统路径 (file:/path/to/resources/) 或类路径 (classpath:/static)
  3. setCachePeriod(int cachePeriod)
    • 设置缓存时间 (以秒为单位)。例如,3600 表示资源缓存时间为 1 小时
  4. resourceChain(boolean enabled)
    • 启用或禁用资源链优化。资源链优化可以提高静态资源的解析和处理效率

常见的资源处理配置

  1. 类路径资源

    • 如果静态资源存储在项目的类路径中(如 src/main/resources/static),可以使用 classpath: 前缀来指定资源位置

      registry.addResourceHandler("/resources/**")
              .addResourceLocations("classpath:/static/");
  2. 文件系统资源

    • 如果静态资源存储在文件系统中,可以使用 file: 前缀来指定资源位置

      registry.addResourceHandler("/files/**")
              .addResourceLocations("file:/opt/files/");
  3. 多路径映射

    • 可以将多个路径模式映射多个资源位置

      registry.addResourceHandler("/images/**")
              .addResourceLocations("classpath:/static/images/", "file:/opt/images/");

作用

  1. 静态资源处理
    • addResourceHandlers 方法允许你定义如何处理静态请求,使得这些请求可以被正确路由到相应的资源文件
  2. 缓存控制
    • 通过设置缓存时间,可以提高静态资源的加载速度,减少服务器的负载
  3. 资源链优化
    • 资源链优化可以提高静态资源的解析和处理效率

使用场景

  • web 应用

    • 在 web 应用中通常需要处理大量的静态资源,例如 CSS, JavaScript 和图像文件。通过配置 addResourceHandlers ,可以确保这些资源被正确处理并提供给客户端
  • API 服务

    • 虽然 API 服务主要提供数据接口,但有时也需要提供静态资源,例如 API 文档。此时也可以使用 addResourceHandlers 来配置静态资源的处理
  • 添加拦截器并设定拦截的访问路径,路径可以通过可变参数设置多个

@SuppressWarnings("all")
// 配置 bean
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
    @Autowired
    private ProjectInterceptor projectinterceptor;
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        ...
    }
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        // 先设置加哪个拦截器,在设置拦截哪个请求
        registry.addInterceptor(projectinterceptor).addPathPatterns("/books","/books/*");
    }
}
  • 使用标准接口 WebMvcConfigurer 简化开发 (注意:入侵式较强)
@SuppressWarnings("all")
@Configuration
@ComponentScan({"com.dkx.spring.controller"})
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer {
    @Autowired
    private ProjectInterceptor projectinterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(projectinterceptor).addPathPatterns("/books");
    }
}

image_2023-03-06-18-44-33

# 拦截器参数

# 前置处理

@SuppressWarnings("all")
@Component
public class ProjectInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandler ...");
//        改为 false 将终止原始操作的执行,如果终止了原始操作那么后面的方法也不会被执行
        return true;
    }
}
  • 参数

    • request: 请求对象
    • response: 响应对象
    • handler: 被调用的处理对象,本质上是一个方法对象,对反射技术中的 Method 对象进行了包装
  • 返回值

    • 返回值为 false, 被拦截的处理器将不执行
  • 可以这么认为,拿到了 Handle 对象就可以操作原始执行的方法了

# 后置处理

@Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandler ...");
    }
  • 参数
    • modelAndView: 如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息,并进行调整

# 完成后处理

@Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterHandler ...");
    }
  • 参数
    • ex: 如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理

# 拦截器执行顺序

  • 当配置多个拦截器时,形成拦截器链

  • 拦截器链的运行顺序参按照拦截器添加顺序为准

  • 当拦截器中出现对原始处理器的拦截,后面的拦截器均终止运行

  • 当拦截器运行中断,仅运行配置在前面的拦截器的 afterCompletion 操作

image_2023-03-06-19-37-35

  1. 拦截器链的运行顺序
  • preHandle: 与配置顺序相同,必定运行

  • postHandlr: 与配置顺序相反,可能不运行

  • afterCompletion: 与配置顺序相反,可能不运行