SpringBoot表单防止重复提交
哪些因素会引起重复提交?
开发的项目中可能会出现下面这些情况:
前端下单按钮重复点击导致订单创建多次
网速等原因造成页面卡顿,用户重复刷新提交请求
黑客或恶意用户使用postman等http工具重复恶意提交表单
重复提交会带来哪些问题?
重复提交带来的问题
会导致表单重复提交,造成数据重复或者错乱
核心接口的请求增加,消耗服务器负载,严重甚至会造成服务器宕机
订单的防重复提交你能想到几种方案?
核心接口需要做防重提交,你应该可以想到以下几种方案:
方式一:前端JS控制点击次数,屏蔽点击按钮无法点击 前端可以被绕过,前端有限制,后端也需要有限制
方式二:数据库或者其他存储增加唯一索引约束 需要想出满足业务需求的唯一索引约束,比如注册的手机号唯一。但是有些业务是没有唯一性限制的,且重复提交也会导致数据错乱,比如你在电商平台可以买一部手机,也可以买两部手机
方式三:服务端token令牌方式 下单前先获取令牌-存储redis,下单时一并把token提交并检验和删除-lua脚本
分布式情况下,采用Lua脚本进行操作(保障原子性)
其中方式三 是大家采用的最多的,那有没更加优雅的方式呢?
假如系统中不止一个地方,需要用到这种防重复提交,每一次都要写这种lua脚本,代码耦合性太强,这种又不属于业务逻辑,所以不推荐耦合进service中,可读性较低。
本文采用自定义注解+AOP的方式,优雅的实现防止重复提交功能。
1、注解
/*** 表单防止重复提交自定义注解*/
@Documented
@Target(ElementType.METHOD) //可以用在方法上
@Retention(RetentionPolicy.RUNTIME) //保留到虚拟机上,可通过反射获取
public @interface RepeatSubmit {/*** 加锁过期时间,默认是5秒* @return*/int lockTime() default 5;}
注解解析:
@Documented 将此注解包含在 javadoc 中
@Inherited 是否允许子类继承父类中的注解
@interface 用来声明一个注解,可以通过default来声明参数的默认值
自定义注解时,自动继承了java.lang.annotation.Annotation接口,可以通过反射可以获取自定义注解
@Retention 表示在什么级别保存该注解信息
- RetentionPolicy.SOURCE 保留到源码上
- RetentionPolicy.CLASS 保留到字节码上
- RetentionPolicy.RUNTIME 保留到虚拟机运行时(最多,可通过反射获取)
@Target 表示该注解用于什么地方
ElementType.CONSTRUCTOR 用在构造器
ElementType.FIELD 用于描述域-属性上
ElementType.METHOD 用在方法上
ElementType.TYPE 用在类或接口上
ElementType.PACKAGE 用于描述包
2、aop
/*** 表单防止重复提交切面*/
@Aspect
@Component
@Slf4j
public class RepeatSubmitAspect {private Lock lock = new ReentrantLock();@Resourceprivate RedisCache redisCache;/*** 定义 @Pointcut注解表达式, 通过特定的规则来筛选连接点, 就是Pointcut,选中那几个你想要的方法* 在程序中主要体现为书写切入点表达式(通过通配、正则表达式)过滤出特定的一组 JointPoint连接点* 方式一:@annotation:当执行的方法上拥有指定的注解时生效*/@Pointcut("@annotation(repeatSubmit)")public void pointCutNoRepeatSubmit(RepeatSubmit repeatSubmit) {}/*** 环绕通知, 围绕着方法执行* @param joinPoint* @param repeatSubmit* @Around 可以用来在调用一个具体方法前和调用后来完成一些具体的任务。* 用@Pointcut和@Around联合注解也可以*/@Around("pointCutNoRepeatSubmit(repeatSubmit)")public Object around(ProceedingJoinPoint joinPoint, RepeatSubmit repeatSubmit) throws Throwable {// 获取用户的token验证,这里项目用的是 header 里的 Authorization 参数HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();String requestToken = request.getHeader("Authorization");log.info("请求的token->{}", requestToken);boolean res = true;//从redis中获取tokenObject token = redisCache.getCacheObject("submit:token"+requestToken);if(token == null){//设置token并且设置有效期redisCache.setCacheObject("submit:token"+requestToken,requestToken,repeatSubmit.lockTime(), TimeUnit.SECONDS);res = false;}//用于记录成功或者失败log.info("环绕通知中");log.info("默认加锁时间->{}秒", repeatSubmit.lockTime());Object obj = "";try {if (lock.tryLock(repeatSubmit.lockTime(), TimeUnit.SECONDS)) { //设置尝试获取锁得时间//防重提交if (res) {log.error("请求重复提交");log.info("环绕通知中");throw new ServiceException("请勿重复提交");}log.info("环绕通知执行前");obj = joinPoint.proceed();log.info("环绕通知执行后");}} catch (InterruptedException e) {throw new RuntimeException(e);} finally {lock.unlock(); //释放锁}return obj;}
}
3、使用
/*** 同步菜谱* @param data* @return*/@RepeatSubmit@PostMapping("/addRecipe")public AjaxResult addRecipe(@RequestBody String data){recipeService.addRecipe(data);return AjaxResult.success();}
相关文章:
SpringBoot表单防止重复提交
哪些因素会引起重复提交? 开发的项目中可能会出现下面这些情况: 前端下单按钮重复点击导致订单创建多次 网速等原因造成页面卡顿,用户重复刷新提交请求 黑客或恶意用户使用postman等http工具重复恶意提交表单 重复提交会带来哪些问题&…...
java面向对象.day17(什么是面向对象)
先认识:面向过程思想,面向对象思想 面向过程思想(具体) 步骤清晰简单,第一步做什么,第二步做什么.... 面对过程适合处理一些较为简单的问题 面向对象思想(抽象) 物以类聚&#x…...
mysql处理并发简单示例
处理并发的基本思路是使用锁来控制对共享资源的访问。在MySQL中,可以使用事务和行级锁来处理并发。 具体处理方式如下: 创建一个用于存储并发任务的MySQL表,该表包含一个自增的ID字段和任务名称字段。设置一个最大并发数量,用来…...

顺序表——功能实现
✨✨欢迎👍👍点赞☕️☕️收藏✍✍评论 个人主页:秋邱博客 所属栏目:C语言 (感谢您的光临,您的光临蓬荜生辉) 目录 1.0 前言 2.0 线性表 2.1 顺序表 2.2 顺序表的分类 2.3 顺序表功能的实现…...
达梦导出工具dexp
基础环境 操作系统:Red Hat Enterprise Linux Server release 7.9 (Maipo) 数据库版本:DM Database Server 64 V8 架构:单实例dexp 逻辑导出 dexp 工具可以对本地或者远程数据库进行数据库级、用户级、模式级和表级的逻辑备份。备份的内容非…...

Ubuntu 22.04安装新硬盘并启动时自动挂载
方法一 要在Ubuntu 22.04系统中安装一个新硬盘、对其进行格式化并实现启动时自动挂载,需要按以下步骤操作: 1. 安装硬盘 - 确保你的硬盘正确连接到计算机上(涉及硬件安装)。 2. 发现新硬盘 - 在系统启动后,打开终端…...
Mybatis中sqlSession.getMapper背后的原理
在通过MyBatis操作数据库之前我们一定先通过Session对象获取指定Mappper接口的代理对象。如下代码所示: public class UserMapper{Select(value"SELECT * FROM user")public List<User> findAll(); }public static void main(String [] args){Conf…...
[环境配置]conda 64位安装32位python
进入32模式 set CONDA_FORCE_32BIT1创建环境 conda create --name yourEnv python3.8退出32模式 set CONDA_FORCE_32BIT0ok...

某虚假交友APP(信息窃取)逆向分析
应用初探 在群里水群的时候 群u发了一个交友APP 于是拿来分析一下 可以看到应用打开后又一个登录的界面 需要用户输入手机号与验证码进行登录 #在线云沙箱分析 将APK放入某安信云沙箱中分析 提示应用请求了过多的敏感权限 逆向分析 直接拖入Jadx分析 好在程序没有加固 也没…...

基于FPGA的按键消抖
按键工作原理 当KEY1按下时,整条电路就会导通,这个时候KEY1就是低电平; 当KEY1松开时,整条电路就会断开,这个时候KEY1就是高定平; 我们可以通过判断KEY1的高低电平来判断按键是否被按下。 为什么按键消…...

1.网络编程-网络协议
目录 网络编程是什么 网络编程三要素 OSI七层网络模型 TCP/IP五层模型 SSL/TLS 是哪层协议 网络编程是什么 网络编程是计算机科学中的一个重要领域,它涉及到编写能够在网络环境中进行通信的程序。网络编程的核心目标是使不同的设备能够通过网络交换信息&#…...

代码+视频,手动绘制logistic回归预测模型校准曲线(Calibration curve)(2)
校准曲线图表示的是预测值和实际值的差距,作为预测模型的重要部分,目前很多函数能绘制校准曲线。 一般分为两种,一种是通过Hosmer-Lemeshow检验,把P值分为10等分,求出每等分的预测值和实际值的差距 另外一种是calibrat…...
金融数据_Scikit-Learn决策树(DecisionTreeClassifier)实例
金融数据_Scikit-Learn决策树(DecisionTreeClassifier)实例 逻辑回归: 逻辑回归常被用于二分类问题, 比如涨跌预测。你可以将涨跌标记为类别, 然后使用逻辑回归进行训练。 决策树和随机森林: 决策树和随机森林是用于分类问题的强大模型。它们能够处理非线性关系, 并且对于特征…...
bash的login shell与non-login shell,以及各自的初始化过程
识别login shell与non-login shell login shell 可能是以-开头的 [almalinuxVM-AlmaLinux8-tmpl-wanlinwang ~]$ echo $0 -bash # "-" is the first character. Therefore, this is a login shell.或者以--login启动的bash [almalinuxVM-AlmaLinux8-tmpl-wanlinw…...

为什么苹果 Mac 电脑需要使用清理软件?
尽管 Apple Mac 电脑因其卓越的性能、简洁高效的 macOS 操作系统及独特的美学设计备受全球用户青睐,但任何电子设备在长期使用后都难以避免面临系统资源日渐累积的问题。其中一个重要维护需求在于,随着使用时间的增长,Mac电脑可能会由于系统垃…...

33. UE5 RPG使用增强输入激活GameplayAbility(三)
在前面的文章,我们实现了使用GameplayTag和InputAction的对应绑定的数据,并且添加到了增强输入映射的上下文中,实现了通过按键打印对应的GameplayTag,这只是我们基础需要制作的。目的主要是为了实现在GameplayAblity上面设置对应的…...
speech to text 库FastASR交叉编译arm target的配置
FastASR是一个比较方便的SPEECH TO TEXT的AI库。开源。下面介绍下其在交叉编译到ARM target时候的交叉编译的cmake配置: cmake_minimum_required(VERSION 3.10)project(FastASR)SET(CMAKE_C_COMPILER "/home/xxx/buildroot/output/platform_name/host/bin/aar…...

WPS快速将插入Excle数据插入Word
前置条件: 一张有标题、数据的excle表格word中的表格与excle表格标题对应或包含电脑已经安装WPS软件 第一步、根据word模板设计excle模板,标头对应 第二步、word上面选【引用】--【邮件】,选打开数据源,找到excle文件,…...
Springboot 集成Rabbitmq之延时队列
1.首先确保已经引入了Spring AMQP和RabbitMQ的相关依赖: <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId> </dependency> 2. 创建一个普通队列并设置TTL&#x…...
【云开发笔记NO.22】运用云原生产品打造技术中台
一、云原生产品与技术中台的结合点 云原生产品以其容器化、微服务化、自动化等特性,为技术中台的建设提供了强大的技术支持。容器化技术使得应用可以更容易地进行部署和管理,提高了应用的可移植性和弹性。微服务架构则让应用更加模块化,便于…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...

【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...

C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...

如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

Razor编程中@Html的方法使用大全
文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

PHP 8.5 即将发布:管道操作符、强力调试
前不久,PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5!作为 PHP 语言的又一次重要迭代,PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是,借助强大的本地开发环境 ServBay&am…...