位置: IT常识 - 正文

SpringBoot之用拦截器避免重复请求(springboot怎么配置拦截器)

编辑:rootadmin
开发中可能会经常遇到短时间内由于用户的重复点击导致几秒之内重复的请求,可能就是在这几秒之内由于各种问题,比如网络,事务的隔离性等等问题导致了数据的重复等问题,因此在日常开发中必须规避这类的重复请求操作,今天就用拦截器简单的处理一下这个问题。 ... 拦截器什么是拦截器

推荐整理分享SpringBoot之用拦截器避免重复请求(springboot怎么配置拦截器),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:springboot nio,springboot @lazy,springbootdao,springboot -d,springboot curd,springboot @lazy,springboot ci,springboot怎么用,内容如对您有帮助,希望把文章链接给更多的朋友!

Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。

如何自定义拦截器

自定义一个拦截器非常简单,只需要实现HandlerInterceptor这个接口即可,这个接口有三个可实现的方法

preHandle()方法:该方法会在控制器方法前执行,其返回值表示是否知道如何写一个接口。中断后续操作。当其返回值为true时,表示继续向下执行;当其返回值为false时,会中断后续的所有操作(包括调用下一个拦截器和控制器类中的方法执行等)。

postHandle()方法:该方法会在控制器方法调用之后,且解析视图之前执行。可以通过此方法对请求域中的模型和视图做出进一步的修改。

afterCompletion()方法:该方法会在整个请求完成,即视图渲染结束之后执行。可以通过此方法实现一些资源清理、记录日志信息等工作。

如何让拦截器在Spring Boot中生效

想要在Spring Boot生效其实很简单,只需要定义一个配置类,实现WebMvcConfigurer这个接口,并且实现其中的addInterceptors()方法即可,代码如下:

@Configurationpublic class WebConfig implements WebMvcConfigurer { @Autowired private XXX xxx; @Override public void addInterceptors(InterceptorRegistry registry) { // 不拦截的uri final String[] commonExclude = {}}; registry.addInterceptor(xxx).excludePathPatterns(commonExclude); }}用拦截器规避重复请求需求SpringBoot之用拦截器避免重复请求(springboot怎么配置拦截器)

开发中可能会经常遇到短时间内由于用户的重复点击导致几秒之内重复的请求,可能就是在这几秒之内由于各种问题,比如网络,事务的隔离性等等问题导致了数据的重复等问题,因此在日常开发中必须规避这类的重复请求操作,今天就用拦截器简单的处理一下这个问题。

思路

在接口执行之前先对指定接口(比如标注某个注解的接口)进行判断,如果在指定的时间内(比如5秒)已经请求过一次了,则返回重复提交的信息给调用者。

根据什么判断这个接口已经请求了?

根据项目的架构可能判断的条件也是不同的,比如IP地址,用户唯一标识、请求参数、请求URI等等其中的某一个或者多个的组合。

这个具体的信息存放在哪?

由于是短时间内甚至是瞬间并且要保证定时失效,肯定不能存在事务性数据库中了,因此常用的几种数据库中只有Redis比较合适了。

实现Docker启动一个Redisdocker pull redis:7.0.4docker run -itd \--name redis \-p 6379:6379 \redis:7.0.4创建一个Spring Boot项目

使用idea的Spring Initializr来创建一个Spring Boot项目,如下图:

添加依赖

pom.xml文件如下

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.5</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>springboot_06</artifactId> <version>0.0.1-SNAPSHOT</version> <name>springboot_06</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!--spring redis配置--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <!-- 1.5的版本默认采用的连接池技术是jedis 2.0以上版本默认连接池是lettuce, 在这里采用jedis,所以需要排除lettuce的jar --> <exclusions> <exclusion> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </exclusion> <exclusion> <groupId>io.lettuce</groupId> <artifactId>lettuce-core</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>配置Redis

application.properties

spring.redis.host=127.0.0.1spring.redis.database=1spring.redis.port=6379定义一个注解package com.example.springboot_06.intercept;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target({ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface RepeatSubmit { /** * 默认失效时间5秒 * * @return */ long seconds() default 5;}创建一个拦截器package com.example.springboot_06.intercept;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.core.annotation.AnnotationUtils;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.stereotype.Component;import org.springframework.web.method.HandlerMethod;import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.util.Objects;import java.util.concurrent.TimeUnit;/** * 重复请求的拦截器 * * @Component:该注解将其注入到IOC容器中 */@Slf4j@Componentpublic class RepeatSubmitInterceptor implements HandlerInterceptor { /** * Redis的API */ @Autowired private StringRedisTemplate stringRedisTemplate; /** * preHandler方法,在controller方法之前执行 * <p> * 判断条件仅仅是用了uri,实际开发中根据实际情况组合一个唯一识别的条件。 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (handler instanceof HandlerMethod) { // 只拦截标注了@RepeatSubmit该注解 HandlerMethod method = (HandlerMethod) handler; // 标注在方法上的@RepeatSubmit RepeatSubmit repeatSubmitByMethod = AnnotationUtils.findAnnotation(method.getMethod(), RepeatSubmit.class); // 标注在controler类上的@RepeatSubmit RepeatSubmit repeatSubmitByCls = AnnotationUtils.findAnnotation(method.getMethod().getDeclaringClass(), RepeatSubmit.class); // 没有限制重复提交,直接跳过 if (Objects.isNull(repeatSubmitByMethod) && Objects.isNull(repeatSubmitByCls)) { log.info("isNull"); return true; } // todo: 组合判断条件,这里仅仅是演示,实际项目中根据架构组合条件 //请求的URI String uri = request.getRequestURI(); //存在即返回false,不存在即返回true Boolean ifAbsent = stringRedisTemplate.opsForValue().setIfAbsent(uri, "", Objects.nonNull(repeatSubmitByMethod) ? repeatSubmitByMethod.seconds() : repeatSubmitByCls.seconds(), TimeUnit.SECONDS); //如果存在,表示已经请求过了,直接抛出异常,由全局异常进行处理返回指定信息 if (ifAbsent != null && !ifAbsent) { String msg = String.format("url:[%s]重复请求", uri); log.warn(msg); // throw new RepeatSubmitException(msg); throw new Exception(msg); } } return true; }}配置拦截器package com.example.springboot_06.config;import com.example.springboot_06.intercept.RepeatSubmitInterceptor;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;@Configurationpublic class WebConfig implements WebMvcConfigurer { @Autowired private RepeatSubmitInterceptor repeatSubmitInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { // 不拦截的uri final String[] commonExclude = {"/error", "/files/**"}; registry.addInterceptor(repeatSubmitInterceptor).excludePathPatterns(commonExclude); }}写个测试Controllerpackage com.example.springboot_06.controller;import com.example.springboot_06.intercept.RepeatSubmit;import lombok.extern.slf4j.Slf4j;import org.springframework.http.ResponseEntity;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/** * 标注了@RepeatSubmit注解,全部的接口都需要拦截 * */@Slf4j@RestController@RequestMapping("/user")@RepeatSubmitpublic class UserController { @RequestMapping("/save") public ResponseEntity save() { log.info("/user/save"); return ResponseEntity.ok("save success"); }}测试

本文链接地址:https://www.jiuchutong.com/zhishi/310704.html 转载请保留说明!

上一篇:php判断数组元素不为空格的方法(php判断数据类型)

下一篇:织梦数据库类$dsql使用方法(安装织梦数据库连接不上)

  • 传统企业怎样突围互联网壁垒(传统企业如何链改)

    传统企业怎样突围互联网壁垒(传统企业如何链改)

  • 酷狗vip怎么退订自动续费(酷狗vip怎么退订自动续费安卓)

    酷狗vip怎么退订自动续费(酷狗vip怎么退订自动续费安卓)

  • 网易云怎么下架自己作品(网易云怎么下架唱片收藏)

    网易云怎么下架自己作品(网易云怎么下架唱片收藏)

  • 抖音怎么设置让别人保存本地(抖音怎么设置让别人看不到我在线)

    抖音怎么设置让别人保存本地(抖音怎么设置让别人看不到我在线)

  • 台式机怎么用单孔耳麦(台式电脑单主机什么意思)

    台式机怎么用单孔耳麦(台式电脑单主机什么意思)

  • 惠普m30w用非原装硒鼓可以吗(惠普m30w质量好吗)

    惠普m30w用非原装硒鼓可以吗(惠普m30w质量好吗)

  • etc激活后显示card

    etc激活后显示card

  • 什么是操作系统

    什么是操作系统

  • 苹果numlock键在哪(苹果键盘numberlock在哪)

    苹果numlock键在哪(苹果键盘numberlock在哪)

  • word段后间距怎么设置6磅(word段后间距0.3厘米怎么设置)

    word段后间距怎么设置6磅(word段后间距0.3厘米怎么设置)

  • 蓝牙耳机有一只不亮(蓝牙耳机有一只找不到了怎么办)

    蓝牙耳机有一只不亮(蓝牙耳机有一只找不到了怎么办)

  • 盒马鲜生可以用微信支付吗(盒马鲜生可以用支付宝支付吗)

    盒马鲜生可以用微信支付吗(盒马鲜生可以用支付宝支付吗)

  • 抖音收到的礼物在哪(抖音收到的礼物在哪里提现)

    抖音收到的礼物在哪(抖音收到的礼物在哪里提现)

  • 摄像头未检测到存储卡(摄像头未检测到sd卡什么意思)

    摄像头未检测到存储卡(摄像头未检测到sd卡什么意思)

  • nex手机充不进去电是怎么回事(nex手机充不进电)

    nex手机充不进去电是怎么回事(nex手机充不进电)

  • 蓝牙耳机充电仓一直闪红灯(蓝牙耳机充电仓和耳机可以一起充吗)

    蓝牙耳机充电仓一直闪红灯(蓝牙耳机充电仓和耳机可以一起充吗)

  • 电脑可以下载抖音app吗(电脑可以下载抖音视频吗)

    电脑可以下载抖音app吗(电脑可以下载抖音视频吗)

  • wps电子表格删除空白行(wps 表格删除)

    wps电子表格删除空白行(wps 表格删除)

  • 手环手表怎么调时间(手环手表怎么调秒数)

    手环手表怎么调时间(手环手表怎么调秒数)

  • 8g和6g运存相差多少(8g运存跟6g运存有什么区别?)

    8g和6g运存相差多少(8g运存跟6g运存有什么区别?)

  • 公积金app开发有什么功能(公积金小程序是哪个)

    公积金app开发有什么功能(公积金小程序是哪个)

  • 京东闪购是什么(京东闪购真的便宜吗)

    京东闪购是什么(京东闪购真的便宜吗)

  • 如何拍摄城市宣传片(城市宣传片拍摄策划案案例)

    如何拍摄城市宣传片(城市宣传片拍摄策划案案例)

  • Win11任务管理器在哪? Widows11打开任务管理器的技巧(win11任务管理器在哪里打开)

    Win11任务管理器在哪? Widows11打开任务管理器的技巧(win11任务管理器在哪里打开)

  • TCN(Temporal Convolutional Network,时间卷积网络)

    TCN(Temporal Convolutional Network,时间卷积网络)

  • 前端开发常用哪些工具软件?(前端开发常用技术)

    前端开发常用哪些工具软件?(前端开发常用技术)

  • python socket的连接步骤(python sockets)

    python socket的连接步骤(python sockets)

  • 金税盘的会计科目
  • 境外培训费计入关税完税价格
  • 研发设备定义
  • 银行应发贷款和实际收到的贷款为什么不一致
  • 小规模企业每月能开多少专票
  • 个人往对公账户上存款怎么存
  • 房产税应由哪方交纳
  • 应收票据贴现的含义
  • 生产经营行业
  • 跨区经营如何预缴税款
  • 收到科技局的补贴短信
  • 查定征收方式适用于什么
  • 企业未能实施个人所得税代扣代缴是否会罚款呢?
  • 企业收取客户利润违法吗
  • 固定资产清理属于
  • 没有收到发票的支出可以做成本吗
  • 个人申请税务局开技术服务发票如何收费
  • 税号里的字母是什么
  • 企业所得税看哪里
  • 交通卡定额发票购买
  • 什么发票 既可以抵扣又可以退税
  • 房地产中介公司排名
  • 百旺开票系统升级后如何恢复
  • 增值税专用发票查询系统官方网站
  • 苹果14如何强制关机重启
  • 微软雅黑字体一般用在哪里
  • 如何更改中英文切换
  • u盘装机大师怎么用
  • window10发现威胁怎么办
  • 外籍人员个税免征吗
  • 电脑卡住了按什么键回到桌面
  • 公司年终奖怎么缴税
  • 何为租赁合同
  • vue的安装命令
  • php打包网站并在哪里打开
  • 运动目标检测算法
  • 跨区域涉税事项报告表在哪里打印
  • 孕妇钙片什么时候吃最好吸收? 已解决
  • markdown语法是什么意思
  • redissessiondao
  • 史上伟大电影
  • 购入支票号码和使用支票号码是什么
  • 新会计准则分录大全
  • 转让不动产为什么能差额
  • 一条sql在mysql中经过怎样的过程
  • mysql 字符集
  • 帝国cms吧
  • 个人收到承兑汇票
  • sql server 2008中的权限分为三类
  • 投资性房地产转换计入其他综合收益
  • 住宿费专票可以抵扣进项税吗税率多少
  • 住房公积金的账户状态是封存是什么意思
  • 资产减值损失如何计提
  • 非流动资产基金借贷方表示
  • 售后租回会计处理分录
  • 电子记账凭证需要划线吗
  • 发票找不到了怎么操作
  • 根据企业会计准则第11号规定,下列关于等待期
  • 清空mysql数据库
  • 在window中
  • centos安装后配置
  • xp硬盘安装win7系统教程
  • 怎么清理win7
  • 在Linux系统中安装虚拟window
  • linux一块网卡绑定多个ip
  • 在windowsxp中设置控制计算机硬件设备
  • linux系统命令包含在哪个目录中
  • 在linux中使用什么可以执行shell脚本
  • 宽带连接找不到设备是怎么回事
  • win10预览文件怎么显示内容
  • linux开发android好处
  • es6展开符
  • jquery的css样式
  • python ar
  • [置顶]游戏名:chivalry2
  • python黑魔法手册
  • windows ipython
  • 12366纳税服务热线存在的问题
  • 2021年吉林省城乡居民基础养老金是多少
  • 南京税务服务热线
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设