springBoot防止重复提交
两种方法,
一种是后端实现,较复杂,要通过自定义注解和AOP以及Redis组合实现
另一种是前端实现,简单,只需通过js,设置过期时间,一定时间内,多次点击按钮只生效一次
后端实现
自定义注解+AOP+Redis
自定义注解
package com.wzw.config.anno;import java.lang.annotation.*;/*** 自定义注解防止表单重复提交*/
@Target(ElementType.METHOD) // 注解只能用于方法
@Retention(RetentionPolicy.RUNTIME) // 修饰注解的生命周期
@Documented
public @interface RepeatSubmit {/*** 防重复操作过期时间,默认1s*/long expireTime() default 1;
}
AOP
package com.wzw.config.aspect;import com.wzw.config.anno.RepeatSubmit;
import com.wzw.config.exception.CustomException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
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.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
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.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;/*** 防止重复提交切面*/
@Slf4j
@Component
@Aspect
public class RepeatSubmitAspect {@Autowiredprivate RedisTemplate redisTemplate;/*** 定义切点*/@Pointcut("@annotation(com.wzw.config.anno.RepeatSubmit)")public void repeatSubmit() {}@Around("repeatSubmit()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();// 获取防重复提交注解RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);// 获取token当做keyString token = request.getHeader("token");if (StringUtils.isBlank(token)) {throw new RuntimeException("token不存在,请登录!");}String url = request.getRequestURI();/*** 通过前缀 + url + token 来生成redis上的 key* 可以在加上用户id,小编这里没办法获取,大家可以在项目中加上*/String redisKey = "repeat_submit_key:".concat(url).concat(token);log.info("==========redisKey ====== {}",redisKey);if (!redisTemplate.hasKey(redisKey)) {redisTemplate.opsForValue().set(redisKey, redisKey, annotation.expireTime(), TimeUnit.SECONDS);try {//正常执行方法并返回return joinPoint.proceed();} catch (Throwable throwable) {redisTemplate.delete(redisKey);throw new Throwable(throwable);}} else {// 抛出异常throw new CustomException("请勿重复提交");}}
}
自定义异常类和全局异常处理
自定义异常类:CustomException
package com.wzw.config.exception;/*** 自定义异常*/
public class CustomException extends Exception {public CustomException() {super();}public CustomException(String message) {super(message);}
}
全局异常处理:CustomExceptionHandler
package com.wzw.config.exception;import com.wzw.base.pojo.Result;
import com.wzw.config.exception.CustomException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;@Slf4j
@RestControllerAdvice
public class CustomExceptionHandler {/*** 每当抛出CustomException异常,就会进入这里* @param e 自定义异常类* @return 返回值实体*/@ExceptionHandler(value = CustomException.class)@ResponseBodypublic Result handleCustomException(CustomException e){Result result=Result.init();result.setMsg(e.getMessage());result.setCode(0);return result;}}
响应实体:Result
package com.wzw.base.pojo;import lombok.Data;/*** 返回值响应实体*/
@Data
public class Result {private int code;private String msg;private Object data;public static Result init(){return new Result();}public static Result ok(){Result result=Result.init();result.code=1;return result;}public static Result ok(String msg){Result result=Result.ok();result.setMsg(msg);return result;}public static Result err(){Result result=Result.init();result.code=0;return result;}public static Result err(String msg){Result result=Result.err();result.setMsg(msg);return result;}
}
Redis
设置Redis配置数据源,然后创建 Redis配置类
package com.wzw.config.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory){RedisTemplate<Object, Object> template = new RedisTemplate<>();template.setConnectionFactory(connectionFactory);Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);// 使用StringRedisSerializer来序列化和反序列化redis的key值template.setKeySerializer(new StringRedisSerializer());template.setValueSerializer(serializer);// Hash的key也采用StringRedisSerializer的序列化方式template.setHashKeySerializer(new StringRedisSerializer());template.setHashValueSerializer(serializer);template.afterPropertiesSet();return template;}
}
使用
/*** 防止重复提交测试* @return 响应实体* @throws CustomException 自定义异常类*/@RequestMapping("/testCustomerException")@ResponseBody@RepeatSubmit(expireTime = 10) //不加expireTime,默认1s内,加参数可以重新设定防止重复提交的时间public Result testCustomerException() throws CustomException {Result result=Result.ok("请求成功");return result;}
可以看到第一次是请求成功,之后五秒都是提示请勿重复提交

前端实现
来源:https://blog.csdn.net/liangmengbk/article/details/127075604
/* 防止重复点击 */
let clickTimer = 0function clickThrottle() {var interval = 3000;//3秒钟之内重复点击只算一次点击let now = +new Date(); // 获取当前时间的时间戳let timer = clickTimer; // 记录触发事件的事件戳if (now - timer < interval) {// 如果当前时间 - 触发事件时的事件 < interVal,那么不符合条件,直接return false,// 不让当前事件继续执行下去return false;} else {// 反之,记录符合条件触发了事件的时间戳,并 return true,使事件继续往下执行clickTimer = now;return true;}
}
在需要的地方进行调用:
if(!clickThrottle()) return;
相关文章:
springBoot防止重复提交
两种方法, 一种是后端实现,较复杂,要通过自定义注解和AOP以及Redis组合实现 另一种是前端实现,简单,只需通过js,设置过期时间,一定时间内,多次点击按钮只生效一次 后端实现 自定义注…...
lvs-dr模式+keepalived
一,keepalived概述 Keepalived 是一个基于VRRP协议来实现的LVS服务高可用方案,可以解决静态路由出现的单点故障问题。 在一个LVS服务集群中通常有主服务器(MASTER)和备份服务器(BACKUP)两种角色的服务器&am…...
[C++]笔记-知识点总结
一.输入密码时候,隐藏密码 用函数getch(),头文件#include<conio.h>输入一个字符时候不会回显,getc会回显实现思路: 输入一个字符,由于不知道密码长度,所以设置为死循环,如果不是回车键,即将该字符添加到存放密码的数组里,顺便打印一个星号,如果输入的为回车键,由于getch…...
1.RabbitMQ介绍
一、MQ是什么?为什么使用它 MQ(Message Queue,简称MQ)被称为消息队列。 是一种用于在应用程序之间传递消息的通信方式。它是一种异步通信模式,允许不同的应用程序、服务或组件之间通过将消息放入队列中来进行通信。这…...
软考高级系统架构设计师系列论文七十三:论中间件在SIM卡应用开发中的作用
软考高级系统架构设计师系列论文七十三:论中间件在SIM卡应用开发中的作用 一、中间件相关知识点二、摘要三、正文四、总结一、中间件相关知识点 软考高级系统架构设计师:构件与中间件技术二、摘要 我曾于近期参与过一个基于SIM卡应用的开发项目,并在项目中担任系统分析的工作…...
【Java架构-包管理工具】-Maven进阶(二)
本文摘要 Maven作为Java后端使用频率非常高的一款依赖管理工具,在此咱们由浅入深,分三篇文章(Maven基础、Maven进阶、私服搭建)来深入学习Maven,此篇为开篇主要介绍Maven进阶知识,包含坐标、依赖、仓库、生…...
『C语言入门』分支和循环语句
文章目录 引言一、什么是语句?1.1表达式语句1.2赋值语句1.3函数调用语句1.4复合语句1.5空语句1.6控制语句 二、分支语句2.1 if语句2.1.1基本语法2.1.2使用else语句2.1.3嵌套if语句2.1.4多层if-else语句 2.2 switch语句2.2.1基本语法2.2.2示例2.2.3穿透 三、循环语句…...
【给自己挖个坑】三维视频重建(NSR技术)-KIRI Engine
文章目录 以下是我和AI的对话通过手机拍摄物体的视频,再根据视频生成三维模型,这个可实现吗我想开发类似上面的手机应用程序,如何开发呢 看了以上回答,还是洗洗睡吧NSR技术的实现原理是什么呢有案例吗我是名Java工程师,…...
Chrome历史版本下载和Selenium驱动版本下载
Python自动化必备: Selenium驱动版本下载 http://chromedriver.storage.googleapis.com/index.html Chrome浏览器历史版本下载 https://www.slimjet.com/chrome/google-chrome-old-version.php...
联合注入步骤
使用场景: 有回显,可以看到某些字段的回显信息 像下面的有具体的回显信息 一、判断注入位点 在原始的id(参数)的输入后面添加额外的条件 如果and 11 有结果,and10没有结果输出, 就说明我们添加的额外条件…...
后端项目开发:整合redis缓存
因为各种场合比如门户和后台,需要不同的redis配置,我们在common包配置通用的reids配置。 1.新建service目录,建立RedisService服务接口,同时编写工具类实现该接口。 public interface RedisService {/*** 保存属性*/void set(Str…...
美国访问学者签证好办吗?
近年来,随着国际交流与合作的不断深入,许多人对于美国访问学者签证的办理情况产生了浓厚的兴趣。那么,美国访问学者签证到底好办吗?让知识人网小编带您一起了解一下。 首先,美国作为世界上的科研、教育和创新中心之一&…...
Linux之基础IO文件系统讲解
基础IO文件系统讲解 回顾C语言读写文件读文件操作写文件操作输出信息到显示器的方法stdin & stdout & stderr总结 系统文件IOIO接口介绍文件描述符fd文件描述符的分配规则C标准库文件操作函数简易模拟实现重定向dup2 系统调用在minishell中添加重定向功能 FILE文件系统…...
Django主要特点
Django 是一个开源的 Python Web 开发框架,它提供了一系列的工具和功能,帮助开发人员快速、高效地构建 Web 应用程序。 以下是 Django 的一些主要特点: 1. 强大的 ORM(对象关系映射): Django 提供了一个…...
element-ui中的el-table合并单元格
描述: 在写项目的时候有时候会经常遇到把行和列合并起来的情况,因为有些数据是重复渲染的,不合并行列会使表格看起来非常的混乱,如下: 而我们想要的数据是下面这种情况,将重复的行进行合并,使表…...
自组织地图 (SOM) — 介绍、解释和实现
自组织地图 (SOM) — 介绍、解释和实现 一、说明 什么是SOM(self orgnize map)自组织地图,是GNN类似的图神经网络的概念。因为神经网络实质上可以解释为二部图的权重,因此无论GNN还是SOM都有共同的神经网络…...
Arduino程序设计(四)按键消抖+按键计数
按键消抖按键计数 前言一、按键消抖二、按键计数1、示例代码2、按键计数实验 参考资料 前言 本文主要介绍两种按键控制LED实验:第一种是采用软件消抖的方法检测按键按下的效果;第二种是根据按键按下次数,四个LED灯呈现不同的流水灯效果。 一…...
Module not found: Error: Can‘t resolve ‘vue-pdf‘ in ‘xxx‘
使用命令npm run serve时vue项目报错: Module not found: Error: Cant resolve vue-pdf in xxx 解决方案: 运行命令: npm install vue-pdf --save --legacy-peer-deps 即可解决。 再次顺利执行npm run serve...
ELK之LogStash介绍及安装配置
一、logstash简介 集中、转换和存储数据 Logstash 是免费且开放的服务器端数据处理管道,能够从多个来源采集数据,转换数据,然后将数据发送到您最喜欢的“存储库”中。 Logstash 能够动态地采集、转换和传输数据,不受格式或复杂度的…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...
Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...
【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
