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;

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

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

相关文章

cvc-complex-type.2.4.a: 发现了以元素 ‘base-extension‘ 开头的无效内容。应以 ‘{layoutlib}‘ 等等开头

不与世俗为伍。哪怕这是自己许给自己的诅咒。 —— 宫崎骏 《红猪》 最近&#xff0c;在使用最新版的AndroidStudio打开一个两年前的项目时候&#xff0c;报了一个如下的错误&#xff1a;【cvc-complex-type.2.4.a: 发现了以元素 ‘base-extension‘ 开头的无效内容】。应以 ‘…

从2023年世界机器人大会发现机器人新趋势

机器人零部件为何成2023年世界机器人大会关注热门&#xff1f; 在原先&#xff0c;机器人的三大核心零部件是控制系统中的控制器、驱动系统中的伺服电机和机械系统中的精密减速器。如今&#xff0c;机器人的主体框架结构已经落实&#xff0c;更多机器人已经开始深入到各类场景中…

论文阅读 FOCUS-AND-DETECT: A SMALL OBJECT DETECTION FRAMEWORK FOR AERIAL IMAGES

文章目录 FOCUS-AND-DETECT: A SMALL OBJECT DETECTION FRAMEWORK FOR AERIAL IMAGESABSTRACT1 Introduction2 Related Work3 Focus-and-Detect3.1 Overview3.2 Focus Stage3.2.1 Generating Ground-Truth Boxes of Focal Regions Using Gaussian Mixture Model 3.3 Detection …

横扫“盲区”、“看透”缺陷,维视智造推出短波红外相机

在可见光领域&#xff0c;工业相机的视觉应用已经十分成熟&#xff0c;但在日常的客户咨询中&#xff0c;我们也经常接到一些“超纲需求”——客户想要检测“白底上的白色缺陷”、“不透明包装内的透明物体有无”等&#xff0c;均属于可见光无法实现的检测&#xff0c;而市面上…

Ubuntu20.04安装软件报错:The following packages have unmet dependencies

Ubuntu20.04更换阿里云源后安装软件都会报错&#xff1a;The following packages have unmet dependencies 查看资料&#xff0c;大概是ubuntu本身的源比较版本较老&#xff0c;而阿里云的源比较新&#xff0c;因此版本不匹配造成依赖的库不匹配&#xff0c;所以只要将阿里云的…

基于 SVG 的图形交互方案实践

不知道从什么时候起&#xff0c;人们开始喜欢上数字大屏这种“花里胡哨”的东西&#xff0c;仿佛只要用上“科技蓝”这样神奇的色调&#xff0c;就可以让一家公司焕然一新&#xff0c;瞬间变得科技感满满。不管数字大屏的实际意义&#xff0c;是用来帮助企业监控和决策&#xf…

汽车制造业外发文件时 如何阻断泄密风险?

汽车制造业是我国国民经济发展的支柱产业之一&#xff0c;具有产业链长、关联度高、就业面广、消费拉动大等特性。汽车制造行业景气度与宏观经济、居民收入水平和固定资产投资密切相关。 汽车制造业产业链长&#xff0c;关联度高&#xff0c;汽车制造上游行业主要为钢铁、化工…

Docker搭建elasticsearch+kibana测试

最近需要做大数据画像&#xff0c;所以先简单搭建一个eskibana学习使用&#xff0c;记录一下搭建过程和遇到的问题以及解决办法 1.拉取es和kibana镜像 在拉取镜像之前先搜索一下 elasticsearch发现是存在elasticsearch镜像的&#xff0c;我一般习惯性拉取最新镜像&#xff0c…

CSS中的vertical-align属性

vertical-align 1.CSS属性 - vertical-align 2.深入理解vertical-align – line boxes This property affects the vertical positioning inside a line box of the boxes generated by an inline-levelelement. 官方文档的翻译&#xff1a;vertical-align会影响 行内块级元素…

如何将下载的安装包导入PyCharm

1. 下载安装包 这里以pyke为例。下载好之后解压缩&#xff0c;然后放入/Lib/site-packages/pyke-1.1.1 2. 打开PyCharm的终端进行安装 python setup.py install 3. 安装好之后导入即可使用 import pyke

2023年7月京东空气净化器行业品牌销售排行榜(京东运营数据分析)

随着科技发展&#xff0c;智能家具在日常生活中出现的频率越来越高&#xff0c;许多曾经不被关注的家电也出现在其中&#xff0c;包括近年来逐渐兴起的空气净化器。伴随人们对自身健康的重视度越来越高&#xff0c;作为能够杀灭空气污染物、有效提高空气清洁度的产品&#xff0…

龙迅LT7911UX TYPE-C/DP转MIPI/LVDS,内有HDCP

1. 描述 LT7911UX是一种高性能的Type-C/DP1.4a到MIPI或LVDS芯片。HDCP RX作为HDCP中继器的上游端&#xff0c;可以与其他芯片的HDCP TX协同工作&#xff0c;实现中继器的功能。 对于DP1.4a输入&#xff0c;LT7911UX可以配置为1/2/4车道。自适应均衡使其适用于长电缆应用&#…

bash: conda: command not found

问题描述&#xff1a; 在Pycharm上用SSH远程连接到服务器&#xff0c;打开Terminal准备查看用 conda 创建的虚拟环境时&#xff0c;却发现调用 conda 指令时出现以下报错&#xff1a; -bash: conda: command not found如果使用Xshell 利用端口号直接连接该 docker 容器&#…

人工智能技术

人工智能技术是什么&#xff1f; 人工智能技术&#xff08;Artificial Intelligence Technology&#xff0c;AI技术&#xff09;是一种模仿人类智能和思维方式的计算机技术&#xff0c;旨在使计算机能够执行需要人类智能才能完成的任务。这些任务包括理解自然语言、解决问题、…

【IMX6ULL驱动开发学习】10.Linux I2C驱动实战:AT24C02驱动设计流程

前情回顾&#xff1a;【IMX6ULL驱动开发学习】09.Linux之I2C框架简介和驱动程序模板_阿龙还在写代码的博客-CSDN博客 目录 一、修改设备树&#xff08;设备树用来指定引脚资源&#xff09; 二、编写驱动 2.1 i2c_drv_read 2.2 i2c_drv_write 2.3 完整驱动程序 三、上机测…

Python数据挖掘与机器学习

近年来&#xff0c;Python编程语言受到越来越多科研人员的喜爱&#xff0c;在多个编程语言排行榜中持续夺冠。同时&#xff0c;伴随着深度学习的快速发展&#xff0c;人工智能技术在各个领域中的应用越来越广泛。机器学习是人工智能的基础&#xff0c;因此&#xff0c;掌握常用…

Java虚拟机(JVM):堆溢出

一、概念 Java堆溢出&#xff08;Java Heap Overflow&#xff09;是指在Java程序中&#xff0c;当创建对象时&#xff0c;无法分配足够的内存空间来存储对象&#xff0c;导致堆内存溢出的情况。 Java堆是Java虚拟机中用于存储对象的一块内存区域。当程序创建对象时&#xff0c…

三维重建_体素重建_空间雕刻法/体素着色法

目录 1. 三角化和体素重建的区别 2. 空间雕刻法 空间雕刻法的一致性定义 空间雕刻法具体实现 基于八叉树的空间雕刻法具体实现​编辑 空间雕刻法效果展示 3. 体素着色法 体素着色法的缺点&#xff1a;不唯一性​编辑 体素着色法不唯一性解决措施​编辑 体素着色发实验环境与…

LVS DR模式搭建

目录 一、DR模式概述 一、与NET模式的区别 二、操作命令图 三、搭建流程 一、首先配置三台虚拟机并配置环境&#xff08;关闭防火墙&#xff0c;宽容模式&#xff09; 二、ping通百度 三、在115.3的&#xff08;lvs&#xff09;虚拟机上安装 ipvsadm 四、调整ARP参数 五…

一种IDEA疑难杂症的解决办法

解决办法 重启IDEA 针对于IDEA各种羡慕解析&#xff0c;运行时问题&#xff0c;但是无法通过搜索引擎得到答案的问题请试试此方法。 删除根目录下[.idea]文件夹后重启 此文件夹为idea首次导入项目时根据项目情况自动生成的配置文件。方便idea下次更快的解析项目。但是某些情…