Spring MVC拦截器的快速应用代码示例

 更新时间:2026年09月04日 10:31:30   作者:zhaojiakang99  
拦截器是Spring MVC中的一个重要概念,主要用于在请求处理之前、之后或异常抛出时执行特定的操作,这篇文章主要介绍了Spring MVC拦截器快速应用的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

基础

拦截器的生效位置

为什么preHandle是主流?(核心原因)

以后面的案例的「token 校验」为例,就能明白为什么大家优先用 preHandle

1. 「提前拦截」= 减少无效消耗(最核心)

如果 token 无效 / 不存在,preHandle 返回 false,请求会直接被拦截,不会进入控制器、不会调用 Service/DAO、不会操作数据库—— 相当于 “把坏人挡在门外”,而不是 “让坏人进屋里再赶出去”。

  • 比如:用户拿失效的 token 访问 /api/user/infopreHandle 直接返回 401,控制器的 getUserInfo() 方法根本不会执行,节省了服务器资源;
  • 如果用 postHandle:控制器方法已经执行完(比如查了数据库、查了用户信息),再发现 token 无效,此时只能修改响应,但数据库查询、业务逻辑执行的资源已经消耗了,完全没必要。

2.preHandle是唯一能「阻断请求」的方法

postHandleafterCompletion 都是 void 返回值,哪怕发现 token 无效,也无法阻止请求流程(因为控制器已经执行了),只能做一些 “补救”(比如修改响应体),但核心业务逻辑已经执行,失去了拦截的意义。而 preHandleboolean 返回值是 “生死开关”,这是实现「权限控制、token 校验、请求限流」等核心拦截逻辑的关键。

3. 符合 “拦截器” 的设计初衷

拦截器(Interceptor)的核心目的是「在请求处理前做校验 / 过滤,避免无效请求消耗资源」,而不是 “请求处理后做善后”——preHandle 完美契合这个初衷,而另外两个方法只是补充。

postHandle和afterCompletion什么时候用?

不是说这两个方法没用,而是它们的场景很特定,只适合「后置处理」,比如:

1.postHandle适用场景

  • 统一修改响应数据(比如给所有接口返回值加统一的包装格式:{code:200, data:..., msg:"success"});
  • 修改视图渲染参数(比如给所有页面添加全局的用户信息);
  • 记录控制器执行耗时(结合 preHandle 记录的开始时间,计算耗时)。

2.afterCompletion适用场景

  • 资源清理(比如关闭请求中打开的流、释放临时文件);
  • 全局异常记录(通过方法参数 Exception ex 捕获整个请求流程的异常,记录日志);
  • 最终的请求日志汇总(比如记录请求的最终状态、响应码)。

拦截器的使用步骤

1.1 创建拦截器

  • 第1步:工程目录下创建拦截器 base.interceptors.MyInterCeptor(命名随意)

public class MyInterceptor implements HandlerInterceptor {
    /**
     * 1.执行handler之前调用的拦截方法;
     * 2.可以进行编码格式设置、登录保护、权限处理等。
     * @param request 请求对象
     * @param response 响应对象
     * @param handler handler是我们要调用的方法对象
     * @return true放行,false拦截
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("1.preHandle执行");
        return true;
    }

    /**
     * 1.当handler方法执行完成后,触发的方法,没有拦截机制了。
     * 2.此方法只有 preHandle中 return true时才会触发
     * 3.对结果进行处理,比如敏感词检查。
     * @param request 请求
     * @param response 响应
     * @param handler handler方法
     * @param modelAndView 返回的视图和模型数据
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("2.postHandle执行");
    }

    /**
     * 整体处理完毕,调用此方法
     * @param request 请求
     * @param response 响应
     * @param handler handler方法
     * @param ex 异常对象
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("3.afterCompletion执行");
    }
}
  • 第2步:注册拦截器,工程目录下创建 config.MvcConfig(命名随意)

    • 第1:实现WebMvcConfigurer,它是SpringMVC的标准化配置类,提供拦截器的注入

    • 第2:重写注入方法:addInterceptors

    • 第3:注册拦截器:registry.addInterceptor()

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //1.拦截所有请求
        registry.addInterceptor(new MyInterceptor())
                .addPathPatterns("/**");
    }
}

1.2 注册拦截器

SpringMVC 的配置类中,通过实现 WebMvcConfigurer 接口并重写 addInterceptors 方法进行拦截器的注册。

  • 第1步:创建配置类,并实现 WebMvcConfigurer

  • 第2步:注册拦截器,重写 addInterceptors

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //1.拦截所有请求 
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/v1/**");
    }
}

1.2.1 拦截器配置方案

1.拦截全部请求

registry.addInterceptor(new MyInterceptor()) .addPathPatterns("/**");

2.拦截指定请求

示例: 拦截所有 /v1/user/ 开头的请求,使用 /v1/user/**

registry.addInterceptor(new MyInterceptor()) .addPathPatterns("/v1/user/**");

3.排除指定请求

示例: 拦截所有的 /v1/user/ 开头的请求, 但是不包含登录请求 /v1/user/login

registry
.addInterceptor(new MyInterceptor()) 
.addPathPatterns("/v1/user/**")
.excludePathPatterns("/v1/user/login");

实战

限定访问时间拦截器

要求: 项目工程中,限定所有请求只能在每天的: 06:00 - 22:59 之间进行访问;

  • 第1步:创建拦截器的类并实现拦截器功能;

public class TimeAccessInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, 
HttpServletResponse response, Object handler) throws Exception {
        System.out.println("进入访问时间限定拦截器");
        LocalTime now = LocalTime.now();//JDK中的时间对象
        int hour = now.getHour();//获取当前时间对应小时
        if (hour<6 || hour>22){
            throw new RuntimeException("请在06:00~22:00之间进行访问");
        }
        return true;
    }
}
  • 第2步:注册拦截器并添加拦截策略;

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new TimeAccessInterceptor())
                .addPathPatterns("/v1/user/**");
    }
}
  • 第3步:重启工程测

权限校验拦截器

由后端进⾏⽤⼾⾝份验证,若不存在token或失效,则失败返回

采⽤拦截器来完成校验token的合法性

第1步:创建拦截器的类并实现拦截器功能;

@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response, Object handler) throws Exception {
        //从 header 中获取 token
        String jwtToken = request.getHeader("user_token");
        log.info("获取路径:{}", request.getRequestURI());
        log.info("从header中获取token:{}", jwtToken);
        //验证用户 token
        Claims claims = JWTUtil.parseJWT(jwtToken);
        if (null == claims){
            response.setStatus(401);
            return false;
        }
        log.info("令牌验证通过, 放行");
        return true;
    }
}

第2步:注册拦截器并添加拦截策略;

@Configuration
public class AppConfig implements WebMvcConfigurer {

    @Autowired
    private LoginInterceptor loginInterceptor;

    private final List<String> excludes = Arrays.asList(
            "/**/*.html",
            "/css/**",
            "/js/**",
            "/pic/**",
            "/*.jpg",
            "/favicon.ico",
            "/**/login",
            "/register",
            "/verification-code/send",
            "/winning-records/show"
    );

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns(excludes);
    }
}

限流功能拦截器[扩展]

    因为系统处理能力有限,所以现在要对接口访问进行限流,实现方案是编写一个拦截器,对请求进行拦截和计算,要求: 单个IP限制在每分钟访问网站不能超过3次,超过3次则认为该客户端存在攻击风险,具体代码如下:

    • 前提: 获取客户端的IP地址 request.getRemoteAddr();

    • 计数的HashMap:

        {"192.168.1.11": 2, "192.168.1.12": 1, "192.168.1.13": 3}

      • 记录时间的HashMap:

          {"192.168.1.11": "2025-08-11 10:00:00", "192.168.1.12": "2025-08-11 11:00:00", "192.168.1.13": "2025-08-11 09:00:00"}

        • 情况1: 该IP第一次访问网站;

        • 情况2: 该IP之前访问过,但是距离本次访问的时间已经超过了60秒;

        • 情况3: 该IP在1分钟之内访问过;

        • 获取到客户端的IP地址: request.getRemoteAddr();

        • 存储计数的HashMap: {"192.168.1.11": 2, "192.168.1.12": 3, "192.168.1.13": 1}

        • 存储最后一次访问时间的HashMap: {"192.168.1.11": "2025-07-11 00:00:00", "192.168.1.12":"2025-07-10:00:00:00", "192.168.1.13": "2020-01-01 00:00:00"}

        • 第1步: 编写拦截器

          package cn.tedu._03vehicle.base.interceptors;
          
          import org.springframework.web.servlet.HandlerInterceptor;
          
          import jakarta.servlet.http.HttpServletRequest;
          import jakarta.servlet.http.HttpServletResponse;
          import java.time.LocalDateTime;
          import java.util.concurrent.ConcurrentHashMap;
          
          public class RateLimitInterceptor implements HandlerInterceptor {
          
              private static final int MAX_REQUESTS_PER_MINUTE = 3;
              private static final long WINDOW_SIZE_SECONDS = 60;
          
              // {"192.168.1.11": 1, "192.168.1.12": 1, "192.168.1.13": 2}
              private final ConcurrentHashMap<String, Integer> clientCounts = new ConcurrentHashMap<>();
              // {"192.168.1.11": "2024-01-01 14:00:00", "192.168.1.12": "2024-01-01 14:30:30", ...}
              private final ConcurrentHashMap<String, LocalDateTime> lastResetTimes = new ConcurrentHashMap<>();
          
              @Override
              public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
                  //获取客户端的IP地址
                  String clientId = request.getRemoteAddr();
          
                  // 尝试获取上次重置时间
                  LocalDateTime lastResetTime = lastResetTimes.get(clientId);
                  // 如果上次重置时间不存在或已过期,则重置计数器和时间
                  if (lastResetTime == null || LocalDateTime.now().isAfter(lastResetTime.plusSeconds(WINDOW_SIZE_SECONDS))) {
                      clientCounts.put(clientId, 0);
                      lastResetTimes.put(clientId, LocalDateTime.now());
                  }
          
                  // 增加请求次数
                  Integer count = clientCounts.get(clientId);
                  count = count + 1;
                  clientCounts.put(clientId, count);
          
                  // 检查是否超过限制
                  if (count > MAX_REQUESTS_PER_MINUTE) {
                      throw new RuntimeException("访问太频繁了");
                  }
          
                  return true;
              }
          }
          • 第2步: 配置拦截器

          @Configuration
          public class InterceptorConfig implements WebMvcConfigurer {
              @Override
              public void addInterceptors(InterceptorRegistry registry) {
                  registry.addInterceptor(new RateLimitInterceptor())
                                     .addPathPatterns("/v1/user/**");
              }
          }
          • 第3步: 重启工程测试

          总结 

          到此这篇关于Spring MVC拦截器的快速应用的文章就介绍到这了,更多相关Spring MVC拦截器应用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

          相关文章

          • JDK的下载、安装与部署图文教程

            JDK的下载、安装与部署图文教程

            这篇文章主要为大家详细介绍了JDK的下载、安装与部署图文教程,感兴趣的小伙伴们可以参考一下
            2016-06-06
          • Java设计模式编程中的责任链模式使用示例

            Java设计模式编程中的责任链模式使用示例

            这篇文章主要介绍了Java设计模式编程中的责任链模式使用示例,责任链模式可以避免很多请求的发送者和接收者之间的耦合关系,需要的朋友可以参考下
            2016-05-05
          • 教你使用springboot配置多数据源

            教你使用springboot配置多数据源

            发现有很多小伙伴还不会用springboot配置多数据源,今天特地给大家整理了本篇文章,文中有非常详细的图文介绍及代码示例,对正在学习java的小伙伴很有帮助,需要的朋友可以参考下
            2021-05-05
          • Java实现简易计算器(逆波兰表达式)

            Java实现简易计算器(逆波兰表达式)

            这篇文章主要为大家详细介绍了Java实现简易计算器,逆波兰表达式,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
            2022-07-07
          • Spring AOP中的JDK和CGLib动态代理哪个效率更高?

            Spring AOP中的JDK和CGLib动态代理哪个效率更高?

            今天小编就为大家分享一篇关于Spring AOP中的JDK和CGLib动态代理哪个效率更高?,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
            2019-03-03
          • Java如何向指定文件操作一段内容(增加,删除均可使用本方法)

            Java如何向指定文件操作一段内容(增加,删除均可使用本方法)

            这篇文章主要介绍了Java如何向指定文件操作一段内容(增加,删除均可使用本方法),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
            2023-12-12
          • Java StringTokenizer分隔符拆分字符串

            Java StringTokenizer分隔符拆分字符串

            Java中的StringTokenizer类用于将一个字符串分解成标记,本文主要介绍了Java StringTokenizer分隔符拆分字符串,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
            2023-08-08
          • Java并发编程进阶之线程控制篇

            Java并发编程进阶之线程控制篇

            在使用Java实际编程中,多线程可以说是无所不在,凡是需要并发执行的都可以用到它,一个应用程序中不用多线程将会是很糟糕的事情,所以掌握线程以及它的控制操作是非常重要的。通过本篇文章来今天带大家一文掌握线程控制操作,感谢您的观看
            2022-07-07
          • Java中Arraylist动态扩容方法详解

            Java中Arraylist动态扩容方法详解

            ArrayList的列表对象实质上是存储在一个引用型数组里的,下面这篇文章主要给大家介绍了关于Java中Arraylist动态扩容方法的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面跟着小编来一起学习学习吧。
            2017-08-08
          • Spring Boot+MyBatis-Flex之数据库连接信息加密实战指南

            Spring Boot+MyBatis-Flex之数据库连接信息加密实战指南

            在Spring Boot中使用MyBatis时,为了保护数据库连接信息不被泄露,通常需要对数据库连接信息进行加密,这可以防止敏感信息出现在代码库中或配置文件中,从而增强应用的安全性,以下是一个详细的步骤指南,介绍如何在Spring Boot项目中实现数据库连接信息加密
            2026-08-08

          最新评论