当前位置: 首页 > news >正文

SpringBoot自定义拦截器以及多个拦截器执行顺序

一 springboot自定义拦截器

1.1 了解拦截器

springboot所有的拦截器都实现/继承自HandlerInterceptor接口。如果想要编写一个自定义拦截器,就需要实现/继承HandlerInterceptor接口或其子接口/实现类。下图所示为Spring MVC中拦截器的类图
在这里插入图片描述
HandlerInterceptor接口的源码如下,包含3个默认实现(Java 8)的方法——preHandle、postHandle和afterCompletion

public interface HandlerInterceptor {//处理器执行前被调用default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {return true;}//处理器执行后,视图渲染前被调用default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {}//视图渲染完成后被调用default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {}
}

先 自 定 义 一 个 最 简 单 、 纯 净 的 拦 截 器 , 也 就 是 直 接 实 现HandlerInterceptor 接 口 。 新 建 一 个 LogInterceptor 类 并 实 现HandlerInterceptor接口

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 LogInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {log.info("preHandle");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {log.info("postHandle");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {log.info("afterCompletion");}
}

在3个方法中分别添加了一条日志打印代码。新建一个WebConfigurer类并实现WebMvcConfigurer接口,用于注册自定义的拦截器:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebConfigurer implements WebMvcConfigurer {@Autowiredprivate LogInterceptor logInterceptor;
//    @Autowired
//    private TimeInterceptor timeInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(logInterceptor);
//      registry.addInterceptor(timeInterceptor);}
}

在HelloController类的hello方法中添加一条日志打印代码:

@slf4j
@RestController
public class HelloController {@GetMapping("/hello")public String hello() {log.info("hello");return "Hello Spring Boot";}
}

接下来启动工程,并访问http://localhost:8080/hello,会在控制台看到如下输出:
在这里插入图片描述
这代表我们自定义的拦截器成功了!

1.2 拦截器执行流程

从控制台的日志输出中,我们可以大概看出拦截器的执行流程。通过下图,我们可以更清晰地了解拦截器的执行流程。
在这里插入图片描述

  1. 执行preHandle方法。该方法会返回一个布尔值。如果为false,则结束本次请求;如果为true,则继续本次请求。
  2. 执行处理器逻辑,也就是Controller。
  3. 执行postHandle方法。
  4. 执行afterCompletion方法。

二 多个拦截器

在实际应用中,通常需要多个拦截器一起配合使用才能满足我们的需求。了解了单个拦截器的执行流程后,接下来看看多个拦截器组合起来是如何运转的:是执行完一个再执行下一个,还是嵌套执行,抑或是其他的方式呢?下面我们来一探究竟。

再创建一个拦截器 , 用来记录程序执行消耗的时间 , 创建一个TimeInterceptor类,同样实现HandlerInterceptor接口,代码如下:


import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.Duration;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;@Slf4j
//@Component
public class TimeInterceptor implements HandlerInterceptor {private final ThreadLocal<LocalTime> threadLocalStart = new ThreadLocal<>();private final ThreadLocal<LocalTime> threadLocalEnd = new ThreadLocal<>();private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss:SSS");// 记录开始时间@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {LocalTime startTime = LocalTime.now();threadLocalStart.set(startTime);log.info("开始时间:{}", startTime.format(formatter));return true;}// 记录结束时间@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {LocalTime endTime = LocalTime.now();threadLocalEnd.set(endTime);log.info("结束时间:{}", endTime.format(formatter));}// 计算接口执行时间@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {LocalTime startTime = threadLocalStart.get();LocalTime endTime = threadLocalEnd.get();log.info("接口执行时间:{} 毫秒", Duration.between(startTime, endTime).getNano() / 1000000);}
}

注册拦截器

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebConfigurer implements WebMvcConfigurer {@Autowiredprivate LogInterceptor logInterceptor;@Autowiredprivate TimeInterceptor timeInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(logInterceptor);registry.addInterceptor(timeInterceptor);}
}

接下来启动工程并再次访问hello接口,我们会看到控制台输出如下日志:
在这里插入图片描述

通过控制台的输出信息,我们可以看到多个拦截器的执行顺序有些类似于数据结构中的栈——先进后出。下面我们通过图来更加直观地理解一下这个逻辑。
在这里插入图片描述

http://www.xdnf.cn/news/127603.html

相关文章:

  • 前端算法Hot 100 _二分查找
  • HTB - BigBang靶机记录
  • C++学习:六个月从基础到就业——STL算法(三)—— 数值算法(上)
  • 深入理解表单---提交用户与网页交互的重要方式:GET 与 POST 的本质区别与应用实践
  • 【C++】入门基础【下】
  • 信息系统项目管理工程师备考计算类真题讲解八
  • rabbitmq安装项目集成
  • 智能清洁机器人中的实时操作系统应用研究
  • Android学习总结之扩展基础篇(一)
  • 动手试一试 Spring Boot默认缓存管理
  • 中央对齐模式1 2与更新中断
  • Apifox 4月更新|Apifox在线文档支持LLMs.txt、评论支持使用@提及成员、支持为团队配置「IP 允许访问名单」
  • 使用setGraphicsEffect重新设置阴影导致程序崩溃的问题
  • SAP SuccessFactors Recruiting and Onboarding The Comprehensive Guide
  • 【oql】spark thriftserver内存溢出,使用oql查询导致oom的sql
  • 覆盖纸(Overlay Paper):装饰材料领域的“隐形冠军”
  • 每日一练(4~24):互质的数【省模拟赛】
  • 【python】解释builtin.py函数为何全是pass
  • Kaamel白皮书:Model Context Protocol (MCP) 隐私安全最佳实践
  • AGP8+ fullMode 完全模式混淆闪退
  • MAC地址攻击和ARP攻击的原理及解决方法
  • nodejs导入文件模块和导入文件夹
  • 研0调研入门
  • 【Vue3 实战】插槽封装与懒加载
  • LJF-Framework 第14章 LjfSecurity适配SpringSecurity
  • springcloud-openfeign
  • 使用钉钉机器人推送系统内部的ERP停机维护公告
  • 微信小程序 tabbar底部导航栏
  • 传统的图像压缩技术(二)
  • mysql——索引事务和JDBC编程