SpringMVC拦截器之HandlerInterceptor接口解读

 更新时间:2026年06月08日 14:32:45   作者:JiaHao汤  
这段描述概括了HandlerInterceptor接口的核心概念,包括preHandle、postHandle和afterCompletion三个方法的功能及其在SpringMVC中的配置与执行顺序,同时提供了多个拦截器的实现和执行顺序的示例

HandlerInterceptor

HandlerInterceptor 接口中定义了以下三个方法。

preHandle:在控制器执行之前调用。

  • 可以在这个方法中进行一些预处理操作,比如身份验证、权限检查等。
  • 如果返回值为 true,则继续执行后续的拦截器链或进入控制器方法;如果返回值为 false,则中断请求处理流程,不执行后续的拦截器链和控制器方法。

postHandle:在控制器执行之后、视图渲染之前调用。

  • 可以在这个方法中进行一些后处理操作,比如修改数据模型、添加额外的数据等。
  • 该方法中可以对 ModelAndView 对象进行修改。

afterCompletion:在视图渲染完成之后调用。

  • 可以在这个方法中进行一些资源清理的操作,比如释放资源、记录日志等。
  • 可以获取到 Exception 对象,用于记录异常信息。

单个拦截器的实现

以下是实现单个拦截器的步骤。

定义拦截器

通过实现 HandlerInterceptor 接口定义一个拦截器:

package test;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

@Slf4j
@Component
public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 预处理逻辑,如权限检查
        log.info("preHandle方法执行");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 后处理逻辑,可以修改数据模型
        log.info("postHandle方法执行");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 资源清理逻辑,比如释放资源或记录日志
        log.info("afterCompletion方法执行");
    }

}

配置拦截器

在 Spring MVC 中,需要声明实现 WebMvcConfigurer 接口的配置类,并在配置类中配置拦截器才能使拦截器生效。

以下是一个示例,将拦截器配置为拦截所有请求(/**)。

package test;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.annotation.Resource;

@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {

    @Resource
    private MyInterceptor myInterceptor;

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

}

测试拦截器

定义一个控制器,用于测试拦截器是否生效。

package test;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Slf4j
public class MyController {

    @GetMapping("/test")
    public String test() {
        log.info("控制器方法执行");
        return "OK";
    }
    
}

通过 HTTP 请求方式访问控制器方法,控制台输出的结果为:

多个拦截器的实现

定义拦截器

定义多个拦截器,如下例中定义 3 个拦截器。

第一个拦截器:

package test;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

@Slf4j
@Component
public class MyInterceptor1 implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 预处理逻辑,如权限检查
        log.info("【我的拦截器1】preHandle方法执行");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 后处理逻辑,可以修改数据模型
        log.info("【我的拦截器1】postHandle方法执行");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 资源清理逻辑,比如释放资源或记录日志
        log.info("【我的拦截器1】afterCompletion方法执行");
    }

}

第二个拦截器:

package test;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

@Slf4j
@Component
public class MyInterceptor2 implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 预处理逻辑,如权限检查
        log.info("【我的拦截器2】preHandle方法执行");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 后处理逻辑,可以修改数据模型
        log.info("【我的拦截器2】postHandle方法执行");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 资源清理逻辑,比如释放资源或记录日志
        log.info("【我的拦截器2】afterCompletion方法执行");
    }

}

第三个拦截器:

package test;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

@Slf4j
@Component
public class MyInterceptor3 implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 预处理逻辑,如权限检查
        log.info("【我的拦截器3】preHandle方法执行");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 后处理逻辑,可以修改数据模型
        log.info("【我的拦截器3】postHandle方法执行");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 资源清理逻辑,比如释放资源或记录日志
        log.info("【我的拦截器3】afterCompletion方法执行");
    }

}

配置拦截器

为上述 3 个拦截器进行配置,指定每个拦截器拦截指定的路径。

package test;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.annotation.Resource;

@Configuration
public class MyMultipleInterceptorConfig implements WebMvcConfigurer {

    @Resource
    private MyInterceptor1 myInterceptor1;

    @Resource
    private MyInterceptor2 myInterceptor2;

    @Resource
    private MyInterceptor3 myInterceptor3;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(myInterceptor1)
                .addPathPatterns("/test1");
        registry.addInterceptor(myInterceptor2)
                .addPathPatterns("/test2");
        registry.addInterceptor(myInterceptor3)
                .addPathPatterns("/test3");
    }

}

测试拦截器

在控制器中为上述的路径增加映射。

package test;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Slf4j
public class MyMultipleInterceptorTestController {

    @GetMapping("/test1")
    public String test1() {
        log.info("控制器test1方法执行");
        return "OK";
    }

    @GetMapping("/test2")
    public String test2() {
        log.info("控制器test2方法执行");
        return "OK";
    }

    @GetMapping("/test3")
    public String test3() {
        log.info("控制器test3方法执行");
        return "OK";
    }

}

通过 HTTP 请求方式访问映射路径为 /test2 的控制器方法,控制台输出的结果为:

说明访问指定路径(/test2)时,只会生效指定的拦截器(MyInterceptor2)。

多个拦截器的执行顺序

如果配置了多个拦截器,它们之间的执行顺序是什么样的?

修改上例拦截器配置,指定将多个拦截器拦截同一个路径:

package test;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.annotation.Resource;

@Configuration
public class MyMultipleInterceptorConfig implements WebMvcConfigurer {

    @Resource
    private MyInterceptor1 myInterceptor1;

    @Resource
    private MyInterceptor2 myInterceptor2;

    @Resource
    private MyInterceptor3 myInterceptor3;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(myInterceptor1)
                .addPathPatterns("/test2");
        registry.addInterceptor(myInterceptor2)
                .addPathPatterns("/test2");
        registry.addInterceptor(myInterceptor3)
                .addPathPatterns("/test2");
    }

}

输出的结果为:

说明在定义多个拦截器拦截同一个路径时,拦截器的 preHandle 方法是按照拦截器的定义顺序执行,而 postHandleafterCompletion 方法则是按照拦截器的定义顺序倒序执行。

某个拦截器拒绝放行的情况

如果请求被某个拦截器拦截,即在某个拦截器中被拒绝放行,那么会出现什么情况?

继续对上例中的 MyInterceptor2 拦截器进行修改,将 preHandle 方法的返回值修改为 false,使请求在 MyInterceptor3 中被拦截。

package test;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

@Slf4j
@Component
public class MyInterceptor2 implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 预处理逻辑,如权限检查
        log.info("【我的拦截器2】preHandle方法执行");
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 后处理逻辑,可以修改数据模型
        log.info("【我的拦截器2】postHandle方法执行");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 资源清理逻辑,比如释放资源或记录日志
        log.info("【我的拦截器2】afterCompletion方法执行");
    }

}

通过 HTTP 请求访问 /test2,输出的结果为:

上述结果说明在定义了多个拦截器的情况下:

  • 请求被任何一个拦截器拦截,目标控制器方法都不会执行;
  • 对于拦截请求的拦截器之前的拦截器,它们的 preHandle 方法将会执行,afterCompletion 方法也会执行;
  • 对于拦截请求的拦截器,它自身的 preHandle 方法将会执行,但是 afterCompletion 方法不会执行;
  • 对于拦截请求的拦截器之后的拦截器,所有的方法都不会执行;
  • 对于所有的拦截器,它们的 postHandle 方法都不会执行。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java中静态类型检查是如何进行的实例思路详解

    Java中静态类型检查是如何进行的实例思路详解

    这篇文章主要介绍了Java中静态类型检查是如何进行的实例思路详解的相关资料,需要的朋友可以参考下
    2016-05-05
  • 详解如何熟练使用java函数式接口

    详解如何熟练使用java函数式接口

    最近刚好有空给大家整理下JDK8的特性,这个在实际开发中的作用也是越来越重了,本文重点讲解下函数式接口内容,需要的朋友可以参考下
    2021-06-06
  • JVM常用垃圾收集器及GC算法解读

    JVM常用垃圾收集器及GC算法解读

    这篇文章主要介绍了JVM常用垃圾收集器及GC算法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-04-04
  • SpringAop @Around执行两次的原因及解决

    SpringAop @Around执行两次的原因及解决

    这篇文章主要介绍了SpringAop @Around执行两次的原因及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • 一文讲解如何优雅的调试jar包

    一文讲解如何优雅的调试jar包

    在现实开发过程中,现场环境永远比开发环境复杂,下面这篇文章主要给大家介绍了关于如何优雅的调试jar包的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2022-03-03
  • SpringBoot+websocket实现消息对话功能

    SpringBoot+websocket实现消息对话功能

    WebSocket是一种在Web应用程序中实现实时双向通信的技术,它可以用于在线游戏、在线聊天、推送通知、实时监控等,并且比传统的轮询技术更加高效和可靠,本文就给大家介绍基于SpringBoot+websocket实现消息对话功能,感兴趣的小伙伴可以自己动手试一试
    2023-09-09
  • java数据结构ArrayList详解

    java数据结构ArrayList详解

    本文详细讲解了java数据结构ArrayList的用法,文中通过示例代码介绍的非常详细。对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-12-12
  • java面向对象:API(接口)与集合(ArrayList)

    java面向对象:API(接口)与集合(ArrayList)

    这篇文章主要介绍了Java语言面向对象的API与集合,还是十分不错的,这里给大家分享下,需要的朋友可以参考,希望能够给你带来帮助
    2021-08-08
  • Java顺序表实现的扑克牌小游戏(附详细代码)

    Java顺序表实现的扑克牌小游戏(附详细代码)

    在扑克牌游戏中,我们有时需要判断一手牌是否是一个顺子,也就是判断5张牌是否连续,这篇文章主要介绍了Java顺序表实现的扑克牌小游戏的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-10-10
  • 手把手教你如何获取微信用户openid

    手把手教你如何获取微信用户openid

    众所周知小程序的openid相当重要,它是用户的唯一标识id,牵扯的支付,登录,授权等,下面这篇文章主要给大家介绍了关于如何获取微信用户openid的相关资料,需要的朋友可以参考下
    2023-02-02

最新评论