Spring Mvc中拦截器Interceptor用法解读

 更新时间:2025年03月25日 10:03:39   作者:透明果冻  
这篇文章主要介绍了Spring Mvc中拦截器Interceptor用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

一、概述

拦截器常用于在请求处理的不同阶段插入自定义逻辑。

Spring MVC的拦截器作用是在请求到达控制器之前或之后进行拦截,可以对请求和响应进行一些特定的处理。

如:

  • 登录验证:对于需要登录才能访问的网址,使用拦截器可以判断用户是否已登录,如果未登录则跳转到登录页面。
  • 权限校验:根据用户权限对部分网址进行访问控制,拒绝未经授权的用户访问。
  • 请求日志:记录请求信息,例如请求地址、请求参数、请求时间等,用于排查问题和性能优化。
  • 更改响应:可以对响应的内容进行修改,例如添加头信息、调整响应内容格式等。

二、拦截器和过滤器之间的区别

关于过滤器可以看我之前的文章过滤器Filter的介绍和使用

我们很容易发现拦截器和过滤器十分相似,他们都是对某一阶段的前后进行拦截,进行一些处理。那么他们之间有什么不同呢?

过滤器(Filter)是servlet中定义的,而拦截器(HandlerInterceptor)则是由Spring MVC框架提供

二者所作用的范围不同

  • 过滤器更注重在**请求和响应(即在Servlet之前)**的流程中进行处理,可以修改请求和响应的内容,例如设置编码和字符集、请求头、状态码等。
  • 拦截器则更加侧重于对控制器进行前置或后置处理,在请求到达控制器之前或之后进行特定的操作,例如打印日志、权限验证等。

三、自定义实现拦截器

Spring MVC 提供了 HandlerInterceptor 接口,开发者可以通过实现这个接口来创建自定义的拦截器。

其中定义了三个默认方法,用于对不同阶段进行拦截:

preHandle(HttpServletRequest request, HttpServletResponse response, Object handler):
  • 在控制器方法执行前调用。
  • 返回 true 表示继续执行后续的拦截器和控制器方法;返回 false 表示中断执行,不再调用后续的拦截器和控制器方法。
  • 可以用于权限验证、日志记录等。
postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView):
  • 在控制器方法执行后,但在视图渲染前调用。
  • 可以用于修改 ModelAndView 对象,添加额外的数据等。
afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex):
  • 在整个请求处理完成后调用,无论是否发生异常。
  • 可以用于资源清理、日志记录等。

创建自定义拦截器:

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

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

public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 在控制器方法执行前调用
        System.out.println("preHandle..." );
        //这里我们直接返回true
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 在控制器方法执行后,但在视图渲染前调用
        System.out.println("postHandle...");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 在整个请求处理完成后调用
        System.out.println("AfterCompletion");
    }
}

此时要想要该拦截器生效,我们还需在spring mvc配置文件中进行配置(默认对所有控制器进行拦截)

<mvc:interceptors>
    <mvc:interceptor>
        <!--设置要拦截的路径-->
        <mvc:mapping path="/**"/>
        <!--指定不进行拦截的路径-->
        <mvc:exclude-mapping path="/test"/>
        <!--配置自定义拦截器的类路径-->
        <bean class="com.example.MyInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

也可以通过在自定义 拦截器的类上加上@component注解,此时的配置文件为

<mvc:interceptors>
    <mvc:interceptor>
        <!--设置要拦截的路径-->
        <mvc:mapping path="/**"/>
        <!--指定不进行拦截的路径-->
        <mvc:exclude-mapping path="/test"/>
        <!--默认名字为类名首字母小写-->
        <ref bean="myInterceptor"></ref>
    </mvc:interceptor>
</mvc:interceptors>

四、多个拦截器的执行顺序

在 Spring MVC 中,多个拦截器可以组成一个拦截器链,按照注册(配置)顺序依次执行。

假设现在按顺序注册三个拦截器Interceptor1,Interceptor2,Interceptor3。

当所有的拦截器的preHandle方法都返回true时:

  • preHandle执行顺序:Interceptor1->Interceptor2->Interceptor3 (顺序执行)
  • postHandle执行顺序:Interceptor3->Interceptor2->Interceptor1 (逆序执行)
  • afterCompletion执行顺序:Interceptor3->Interceptor2->Interceptor1 (逆序执行)

当某一个拦截器的preHandle方法返回false时,这里假设为Interceptor3

  • preHandle执行顺序:Interceptor1->Interceptor2->Interceptor3 (顺序执行直到某一个拦截器返回false)
  • postHandle不执行,控制器方法也不执行
  • afterCompletion执行顺序:Interceptor2->Interceptor1 (返回false的拦截器之前的拦截器逆序执行)

为什么是这样的顺序呢?我们观察源码可以发现:

  • preHandle源码分析
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
   		 //interceptorList是一个ArrayList集合,按顺序存放了所有的拦截器	
    	//下标从0开始,从这里我们可以知道为什么是顺序执行的。
  		//this.interceptorIndex = i++,注意这个代码,如果返回false,则它的值则表示当前返回false的拦截器的下标
        for(int i = 0; i < this.interceptorList.size(); this.interceptorIndex = i++) {
            HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
            //如果返回false
            if (!interceptor.preHandle(request, response, this.handler)) {
                //执行AfterCompletion,这里我们就知道为什么不执行postHandle,而执行AfterCompletion了
                this.triggerAfterCompletion(request, response, (Exception)null);
                return false;
            }
        }

        return true;
    }
  • postHandle源码分析
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
    	//可以看到这里是从最后一个拦截器开始逆序遍历
        for(int i = this.interceptorList.size() - 1; i >= 0; --i) {
            HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
            interceptor.postHandle(request, response, this.handler, mv);
        }

    }
  • afterCompletion源码分析
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
    	//this.interceptorList.size() - 1表示当前返回false的拦截器的上一个的下标
    	//注意这里是--i
    	//这也就解释了为什么是返回false的拦截器之前的拦截器逆序执行
        for(int i = this.interceptorList.size() - 1; i >= 0; --i) {
            HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
            interceptor.postHandle(request, response, this.handler, mv);
        }

    }

总结

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

相关文章

  • BCryptPasswordEncoder加密与MD5加密的区别及说明

    BCryptPasswordEncoder加密与MD5加密的区别及说明

    这篇文章主要介绍了BCryptPasswordEncoder加密与MD5加密的区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • Java代码缺陷的自动化检测与跟踪的管理指南

    Java代码缺陷的自动化检测与跟踪的管理指南

    本文系统解析Java代码缺陷类型及危害,涵盖静态分析工具检测方法,动态监控技术(异常处理、性能指标),缺陷跟踪系统与CI/CD自动化集成方案,助力提升代码质量与安全防护,需要的朋友可以参考下
    2025-07-07
  • POST方法给@RequestBody传参数失败的解决及原因分析

    POST方法给@RequestBody传参数失败的解决及原因分析

    这篇文章主要介绍了POST方法给@RequestBody传参数失败的解决及原因分析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • SpringBoot使用Flyway进行数据库迁移的实现示例

    SpringBoot使用Flyway进行数据库迁移的实现示例

    Flyway是一个数据库迁移工具,它提供迁移历史和回滚的功能,本文主要介绍了如何使用Flyway来管理Spring Boot应用程序中的SQL数据库架构,感兴趣的可以了解一下
    2023-08-08
  • 浅谈java反射和自定义注解的综合应用实例

    浅谈java反射和自定义注解的综合应用实例

    本篇文章主要介绍了java反射和自定义注解的综合应用,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • Java简单高效实现分页功能

    Java简单高效实现分页功能

    这篇文章主要介绍了Java简单高效实现分页功能,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • SpringBoot整合Mail发送邮件功能

    SpringBoot整合Mail发送邮件功能

    我们在网站上注册账号的时候一般需要获取验证码,而这个验证码一般发送在你的手机号上还有的是发送在你的邮箱中,注册,账号密码…都需要用到验证,今天就演示一下如何用SpringBoot整合Mail发送邮箱
    2021-11-11
  • MyBatis验证多级缓存及 Cache Aside 模式的应用小结

    MyBatis验证多级缓存及 Cache Aside 模式的应用小结

    本文介绍了MyBatis的多级缓存机制,包括本地缓存和全局缓存,并通过Spock测试框架验证了多级缓存的实现,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2024-12-12
  • 基于jenkins构建结果企业微信提醒

    基于jenkins构建结果企业微信提醒

    这篇文章主要介绍了基于jenkins构建结果企业微信提醒,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • java8版本base64加密解密的实例

    java8版本base64加密解密的实例

    下面小编就为大家分享一篇java8版本base64加密解密的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2017-12-12

最新评论