SpringBoot+AOP+Redis 防止重复请求提交

本文项目基于以下教程的代码版本: https://javaxbfs.blog.csdn.net/article/details/135224261

代码仓库: springboot一些案例的整合_1: springboot一些案例的整合

1、实现步骤

2.引入依赖

我们需要redis、aop的依赖。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.9.6</version>
</dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.6</version>
</dependency>

redis的访问参数,默认的就行,不需要特别配置。

3、定义拦截注解

我们最终希望的效果是,你想要哪个方法有防止重复提交的功能,直接加上@RepeatSubmit注解即可。 代码如下:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RepeatSubmit {/*** 加锁过期时间,默认是5秒* @return*/long lockTime() default 5L;
}

这段代码定义了一个Java注解(Annotation)叫做RepeatSubmit。注解是Java提供的一种元数据机制,它可以被用于为代码提供附加的信息,这些信息可以被编译器用于生成代码、生成文档、代码检查等。

下面是对这段代码的详细解释:

  • @Target(ElementType.METHOD): 这个注解指定RepeatSubmit只能被用于方法上。ElementType.METHOD表示这个注解只能用于方法。

  • @Retention(RetentionPolicy.RUNTIME): 这个注解指定了RepeatSubmit的保留策略是RUNTIME。这意味着在运行时,这个注解仍然可以被读取。

  • @Documented: 这个注解表明RepeatSubmit应当被Java文档生成器包含在生成文档中。

  • public @interface RepeatSubmit: 定义了一个名为RepeatSubmit的公共注解。

  • long lockTime() default 5L: 这是RepeatSubmit注解的一个元素,名为lockTime。这个元素返回一个长整型值,并且有一个默认值5秒(5L表示5秒)。

这个注解是为了防止方法的重复提交,并提供了一个默认的加锁过期时间为5秒。如果一个方法被这个注解标记,那么在特定的加锁过期时间内,这个方法只会被执行一次。

4、实现防止重复提交切面

关于Spring Aop切面,可以看我之前的文章。

NoRepeatSubmitAspect

package com.it.demo.aspect;import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.it.demo.annotation.RepeatSubmit;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
import java.util.concurrent.TimeUnit;@Component
@Slf4j
@Aspect
public class NoRepeatSubmitAspect {@Resourceprivate RedisTemplate redisTemplate;@Pointcut("@annotation(repeatSubmit)")public void pointCutNoRepeatSubmitAspect(RepeatSubmit repeatSubmit) {}@Around("pointCutNoRepeatSubmitAspect(repeatSubmit)")public Object around(ProceedingJoinPoint joinPoint,RepeatSubmit repeatSubmit) throws Throwable {String reqSignature = buildReqSignature(joinPoint);//加锁时间long lockTime = repeatSubmit.lockTime();Boolean res = redisTemplate.opsForValue().setIfAbsent(reqSignature, 1, lockTime, TimeUnit.SECONDS);if(!res){throw new RuntimeException("重复请求!");}return joinPoint.proceed();}/*** 构建请求签名* @param joinPoint* @return*/private String buildReqSignature(ProceedingJoinPoint joinPoint) {ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();if(Objects.isNull(requestAttributes)){throw new RuntimeException("请求参数异常!");}HttpServletRequest request = requestAttributes.getRequest();String remoteAddr =request.getRemoteAddr()  + ":" +  request.getRemoteHost();String method = request.getMethod();String requestURI = request.getRequestURI();StringBuffer sb = new StringBuffer();for (Object arg : joinPoint.getArgs()) {sb.append(arg);}//请求签名(MD5加密)return DigestUtil.md5Hex(StrUtil.format("{}-{}-{}-{}",remoteAddr,method,requestURI,sb));}
}

这段代码是一个切面(Aspect),用于处理重复提交的情况。以下是对代码中的主要部分的解释:

  1. 导入包及注解:代码首先导入了一些类,并使用了一些注解,例如 @Component, @Aspect, @Resource, @Slf4j 等。

  2. NoRepeatSubmitAspect 类:这是一个切面类,用于实现对重复提交的处理逻辑。

  3. 成员变量:代码中使用了 @Resource 注解注入了一个 RedisTemplate 对象,用于操作 Redis。

  4. 切入点:使用 @Pointcut 注解定义了一个切入点,这里使用了 @annotation(repeatSubmit) 表达式,表示会拦截所有标注了 @RepeatSubmit 注解的方法。

  5. Around 通知:使用 @Around 注解定义了一个环绕通知,在拦截的方法执行前后会执行这里定义的逻辑。

  6. around() 方法:在该方法中,首先调用了 buildReqSignature(joinPoint) 方法构建了请求的签名信息,然后根据 RepeatSubmit 注解中的配置,在 Redis 中设置了一个锁,以防止重复提交。如果设置锁失败,则抛出了一个运行时异常,表示重复请求,否则执行被拦截的方法。

  7. buildReqSignature() 方法:该方法用于构建请求的签名信息,首先获取了请求相关的信息,然后将这些信息进行拼接,并使用 MD5 加密生成请求签名。

这段代码是一个使用 AOP 实现的防止重复提交的切面,在方法执行前通过生成请求签名并利用 Redis 进行锁定的方式,来避免重复提交。

环绕通知实现逻辑如下图所示

构建 Redis 加锁需要使用的 key,加锁key由指定前缀 + MD5(请求签名)组成,对请求签名进行MD5,一方面减少Key的长度,另一方面保证签名信息中的敏感信息不可见,其实现逻辑如下图所示:

/*** 构建请求签名* @param joinPoint* @return*/
private String buildReqSignature(ProceedingJoinPoint joinPoint) {ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();if(Objects.isNull(requestAttributes)){throw new RuntimeException("请求参数异常!");}HttpServletRequest request = requestAttributes.getRequest();String remoteAddr =request.getRemoteAddr()  + ":" +  request.getRemoteHost();String method = request.getMethod();String requestURI = request.getRequestURI();StringBuffer sb = new StringBuffer();for (Object arg : joinPoint.getArgs()) {sb.append(arg);}//请求签名(MD5加密)return DigestUtil.md5Hex(StrUtil.format("{}-{}-{}-{}",remoteAddr,method,requestURI,sb));
}

5、 测试

查询方法加一个@RepeatSubmit

@GetMapping("/list")
@RepeatSubmit
public List<Device> list(){List<Device> list = deviceService.list();System.out.println(list);return deviceService.list();
}

访问localhost:8080/v1/device/list

五秒内再访问,报错:

{"code": 400,"msg": "重复请求!","data": null
}

验证通过。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/584086.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity C# Mp3 Mp4 音频 视频 合成

需求 将声音文件合并到视频中 限制 暂时只支持Windows使用 准备 下载ffmpeg.exe 解压后得到exe https://ffmpeg.org/download.html#releases 注意事项&#xff1a; 目录要在一起 代码 public void StartExe(){if (File.Exists(ffmpegExe)){ string mp4;string mp3;//…

深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第四节 参数传递对堆栈的影响 1

深入浅出图解C#堆与栈 C# Heaping VS Stacking 第四节 参数传递对堆栈的影响1 [深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第一节 理解堆与栈](https://mp.csdn.net/mdeditor/101021023)[深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第二节 栈基本工作原理](http…

将H5封装为App:实现跨平台移动应用开发的新趋势

H5技术指的是HTML5、CSS3和JavaScript等一系列前端技术的综合应用。它具有跨平台、开发成本低、开发周期短等优势&#xff0c;可以快速实现丰富的界面和交互效果。而原生应用开发受限于操作系统的差异&#xff0c;需要分别开发不同平台的应用&#xff0c;这就增加了开发成本和工…

2023年度总结(找到工作)

转眼2023年结束了&#xff0c;今天已经12月29日了。从2022年12月25日考研失败后&#xff0c;2023年就变成了找工作以及上班度日的时光了。针对2023年&#xff0c;我想对自己所说的是&#xff1a;终于找到工作了。作为一个普通的专升本&#xff0c;考研落榜生来说&#xff0c;能…

熊猫目标检测数据集VOC格式1200张

熊猫是中国的国宝&#xff0c;也是世界上最受人喜爱的动物之一。熊猫以其独特的外貌和与生俱来的文化象征意义而闻名于世。它们是一种大型的食草动物&#xff0c;主要分布在中国中部地区的竹林和高山地带。 熊猫的身形圆润笨拙&#xff0c;黑白分明&#xff0c;拥有圆润的脸庞…

C++进阶--多态

多态 一、多态的概念二、多态的定义及实现2.1 构成多态的两个硬性条件2.2 虚函数的重写2.2.1 协变(基类与派生类虚函数返回值类型不同)2.2.2 析构函数的重写(基类与派生类析构函数的名字不同) 2.3 final和override2.4 重载、覆盖&#xff08;重写&#xff09;、隐藏&#xff08…

基于Java图书借阅管理系统设计与实现(源码+部署文档)

博主介绍&#xff1a; ✌至今服务客户已经1000、专注于Java技术领域、项目定制、技术答疑、开发工具、毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精彩专栏 推荐订阅 &#x1f447;&#x1f3fb; 不然下次找不到 Java项目精品实…

英语中修饰头发的形容词顺序是怎么样的(加补充)

一、英语描述发型 :漂亮长短形状颜色头发。 例如她有一头美丽的黑色的直发。She has beautiful long straight black hair.二、多个形容词修饰同一名词时的顺序是固定的&#xff0c;其顺序为&#xff1a;①冠词、指示代词、不定代词、物主代词②序数词基数词③一般性描绘形容词…

小红书品牌曝光方式有哪些,小红书投放总结!

辛辛苦苦撰写了笔记&#xff0c;却没有人看。不懂平台的曝光策略&#xff0c;就无法获得预期的营销结果。今天就来分享下小红书品牌曝光方式有哪些&#xff0c;小红书投放总结&#xff01; 第一招&#xff0c;打造账号IP 在小红书平台进行传播&#xff0c;打造账号IP非常重要。…

Apache Doris (五十六): Doris Join类型 - 四种Join对比

🏡 个人主页:IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 🚩 私聊博主:加入大数据技术讨论群聊,获取更多大数据资料。 🔔 博主个人B栈地址:豹哥教你大数据的个人空间-豹哥教你大数据个人主页-哔哩哔哩视频 Doris 支持两种物理算子,一类是…

竞赛保研 基于情感分析的网络舆情热点分析系统

文章目录 0 前言1 课题背景2 数据处理3 文本情感分析3.1 情感分析-词库搭建3.2 文本情感分析实现3.3 建立情感倾向性分析模型 4 数据可视化工具4.1 django框架介绍4.2 ECharts 5 Django使用echarts进行可视化展示5.1 修改setting.py连接mysql数据库5.2 导入数据5.3 使用echarts…

2023 楚慧杯 --- Crypto wp

文章目录 初赛so large e 决赛JIGE 初赛 so large e 题目&#xff1a; from Crypto.Util.number import * from Crypto.PublicKey import RSA from flag import flag import randomm bytes_to_long(flag)p getPrime(512) q getPrime(512) n p*q e random.getrandbits(1…

全新研发体系助力产品落地 传音控股成科技出海代表

一直以来&#xff0c;手机都被认为是所有新技术的最佳应用载体&#xff0c;尤其是在数字化、智能化时代&#xff0c;技术创新能力决定着手机厂商的生存与发展。 作为全球新兴市场手机行业的中坚力量之一&#xff0c;传音控股始终坚持以技术创新为驱动&#xff0c;围绕用户需求…

最大后验概率法

在贝叶斯统计中&#xff0c;最大后验概率&#xff08;maximum a posteriori, MAP&#xff09;估计是对后验分布的模的估计。MAP可根据经验数据获得未观测量的点估计。它与最大似然&#xff08;ML&#xff09;估计方法密切相关&#xff0c;但采用了一个包含先验分布的增强优化目…

【数据结构】七、图

一、概念 图&#xff1a;记为G(V,E) 有向图&#xff1a;每条边都有方向 无向图&#xff1a;边无方向 完全图&#xff1a;每个顶点都与剩下的所有顶点相连 完全有向图有n(n-1)条边&#xff1b;完全无向图有n(n-1)/2条边 带权图&#xff1a;边上标有数值的图 连通图&#…

使用 pytest 相关特性重构 appium_helloworld

一、前置说明 在 pytest 基础讲解 章节,介绍了 pytest 的特性和基本用法,现在我们可以使用 pytest 的一些机制,来重构 appium_helloworld 。 appium_helloworld 链接: 编写第一个APP自动化脚本 appium_helloworld ,将脚本跑起来 代码目录结构: pytest.ini 设置: [pyt…

Goby 漏洞发布| QNAP NAS authLogin.cgi 命令执行漏洞(CVE-2017-6361)

漏洞名称&#xff1a;QNAP NAS authLogin.cgi 命令执行漏洞&#xff08;CVE-2017-6361&#xff09; English Name&#xff1a;QNAP NAS authLogin.cgi command execution vulnerability (CVE-2017-6361) CVSS core: 9.8 影响资产数&#xff1a; 2637547 漏洞描述&#xff1…

pd工具箱 Parallels Toolbox

Parallels Toolbox是一款适用于Mac和PC的强大工具箱软件&#xff0c;集成了多种实用的工具和功能&#xff0c;旨在帮助用户提高工作效率和生产力。它提供了文件管理、截图、音频视频处理、清理工具等众多工具&#xff0c;使用户能够方便快捷地完成各种常见任务。Parallels Tool…

“踩坑”经验分享:Swift语言落地实践

作者 | 路涛、艳红 导读 Swift 是一种适用于iOS/macOS应用开发、服务器端的编程语言。自2014年苹果发布 Swift 语言以来&#xff0c;Swift5 实现了 ABI 稳定性、Module 稳定性和Library Evolution&#xff0c;与Objective-C&#xff08;下文简称“OC”&#xff09;相比&#xf…

PLC电机正反转控制程序示例

一、对于三相电源线的电动机&#xff0c;反转只需要任意的交换两根电源线即可 二、例如接通KM1对应正转的话&#xff0c;则接通KM2则对应反转 三、电机正转按钮及其对应的地址 四、电机反转按钮及其对应的地址 五、电机停止按钮及其对应的地址 六、正转的接触器线圈 七、反转的…