当前位置: 首页 > 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接口,我们会看到控制台输出如下日志:
在这里插入图片描述

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

相关文章:

  • 安卓adb shell串口基础指令
  • 【金仓数据库征文】加速数字化转型:金仓数据库在金融与能源领域强势崛起
  • 修改el-select背景颜色
  • 第9章 多模态大语言模型
  • vue element使用el-table时,切换tab,table表格列项发生错位问题
  • mysql快速在不同库中执行相同的sql
  • 金融机构典型欺诈场景
  • 【element plus】解决报错error:ResizeObserver loop limit exceeded的问题
  • JBoltAI 赋能金融文档:基于 RAG 的基金招募说明书视觉增强方案
  • 致远oa部署
  • 在Vue3中,如何在父组件中使用v-model与子组件进行双向绑定?
  • 【计算机视觉】CV实战项目 - 基于YOLOv5与DeepSORT的智能交通监控系统:原理、实战与优化
  • 【C++】内存管理:内存划分、动态内存管理(new、delete用法)
  • 【KWDB 创作者计划】_嵌入式硬件篇---寄存器与存储器截断与溢出
  • 关于边缘计算盒子的外部接口保护
  • Python torchvision.transforms 下常用图像处理方法
  • 计算机网络学习笔记
  • 【含文档+PPT+源码】基于SpringBoot的开放实验管理平台设计与实现
  • 高防IP是如何防护DDoS攻击和CC攻击的
  • C语言教程(十四):C 语言指针详解
  • 北朝时期的甲胄
  • 富力地产:广州富力空港假日酒店第一次拍卖流拍,起拍价约2.77亿元
  • 我国将组织实施梦舟飞船零高度逃逸、揽月着陆器综合着陆起飞验证等试验
  • 旁白丨无罪后领到国家补偿,一位退休教师卸下了“包袱”
  • 神舟二十号任务完成最后一次全区合练,发射场做好发射前各项准备
  • 田野调查|“心青年”的日常秩序与归属之地