spring防止重复点击,两种注解实现(AOP)

第一种:@EasyLock

简介

为了简化可复用注解,自己实现的注解,代码简单随拿随用

使用方式

1.创建一个注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EasyLock {long waitTime() default 1;long leaseTime() default 3;
}

 2. 创建一个AOP切面类(异常可以自定义,这里我用的Cicada)

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.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.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;
import vip.lspace.agent.common.annotation.EasyLock;
import vip.lspace.agent.common.exception.LockException;import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;@Component
@Aspect
@Slf4j
public class LockAop {@Resourceprivate LockException lockException;@ResourceRedissonClient redissonClient;private static final String redisLockKeyParamName = "redisLockKey";@Pointcut("@annotation(vip.lspace.agent.common.annotation.EasyLock)")public void lockPointcut() {}@Around("lockPointcut()")public Object doAround(ProceedingJoinPoint proceedingJoinPoint) {log.info("EasyLock locking");MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();EasyLock easyLock = methodSignature.getMethod().getAnnotation(EasyLock.class);Object[] args = proceedingJoinPoint.getArgs();String[] parameterNames = methodSignature.getParameterNames();String redisLockKey = "";for (int i = 0; i < parameterNames.length; i++) {if (parameterNames[i].equals(redisLockKeyParamName)) {redisLockKey = (String) args[i];}}if (StringUtils.isBlank(redisLockKey)) {throw lockException.lockKeyNotExist();}RLock lock = redissonClient.getLock(redisLockKey);try {if (!lock.tryLock(easyLock.waitTime(), easyLock.leaseTime(), TimeUnit.SECONDS)) {throw lockException.getLockTimeOut(redisLockKey);}return proceedingJoinPoint.proceed();} catch (Throwable e) {throw new RuntimeException(e);} finally {if (lock.isLocked() && lock.isHeldByCurrentThread()) {lock.unlock();log.info("当前线程{},释放锁:{}", Thread.currentThread().getId(), redisLockKey);}}}
@CicadaBean(namespace = "lock")
public interface LockException {@ExceptionInfo(errCode = 13001, errMessage = "没找到分布式锁key")CicadaException lockKeyNotExist();@ExceptionInfo(errCode = 13002, errMessage = "超时未获取到锁: %s")CicadaException getLockTimeOut(String key);
}

3.使用方式

 注意点:

必须包含名为redisLockKey的参数,作为redis的key

@Override@EasyLock(waitTime = 1,leaseTime = 3)@Transactional(rollbackFor = Exception.class)public void concurrentTest(String redisLockKey) {PaymentBillBacktrack paymentBillBacktrack = paymentBillBacktrackService.getById(1L);String refundRequestNo = paymentBillBacktrack.getMerchantRefundRequestNo();paymentBillBacktrack.setMerchantRefundRequestNo(String.valueOf(Integer.parseInt(refundRequestNo) + 1));paymentBillBacktrackService.updateById(paymentBillBacktrack);}

第二种:@NiceLock

简介

大佬提供的公共组件,引包后可直接使用,使用简单,细节代码可看nicelock: nicelock:一个注解,即可使用Java的分布式锁。(基于Redisson)

使用方式

1.引包

一定得引入1.1.6的,甚至最新版本,不然有问题!!!

<dependency><groupId>com.suchtool</groupId><artifactId>nicelock-spring-boot-starter</artifactId><version>1.1.6</version>
</dependency>

2.使用

    @Override@Transactional@NiceLock(keys = {"#userId"},acquireTimeout = 3000L,exception = NiceLockLockFailException.class,message = "服务已完成评价,不能重复提交")public void test(String userId) {System.out.println("修改订单: 用户ID=" + userId);}

注解中传入了exception参数后,报错会输出message的内容,更加直观 

测试方式

Apifox中的自动化测试中可以配多个线程同时执行接口,测试重复点击是否生效

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

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

相关文章

微服务拆分的艺术:构建高效、灵活的系统架构

目录 一、微服务拆分的重要性 二、微服务拆分的策略 1. 按照业务领域拆分 2. 按照团队结构拆分 3. 按照业务边界拆分 4. 按照数据和数据库拆分 5. 按照用户界面或外部接口拆分 6. 按照功能模块或领域驱动设计拆分 7. 按照性能和可伸缩性需求拆分 三、微服务拆分的实践…

中建海龙:科技助力福城南产业片区绿色建筑发展

在快速发展的城市化进程中&#xff0c;绿色建筑以其环保、节能、可持续的特点日益受到重视。作为建筑工业化领域的领军企业&#xff0c;中建海龙科技有限公司&#xff08;简称“中建海龙”&#xff09;凭借其卓越的科技实力和创新举措&#xff0c;在推动绿色建筑发展方面做出了…

大模型数据采集和预处理:把所有数据格式,word、excel、ppt、jpg、pdf、表格等转为数据

大模型数据采集和预处理&#xff1a;把所有数据格式&#xff0c;word、excel、ppt、jpg、pdf、表格等转为数据 文本/图片/表格&#xff0c;分别提取处理工具选择不同格式文件&#xff0c;使用不同工具处理1. 确认目标2. 分析过程(目标-手段分析法)3. 实现步骤4. 代码封装效果展…

三甲医院等级评审八维数据分析应用(五)--数据集成与共享篇

一、引言 1.1 研究背景与意义 随着医疗卫生体制改革的不断深化以及信息技术的飞速发展,三甲医院评审作为衡量医院综合实力与服务水平的重要标准,对数据集成与共享提出了更为严苛的要求。在传统医疗模式下,医院内部各业务系统往往各自为政,形成诸多“信息孤岛”,使得数据…

论文泛读《LPFHE: Low-Complexity Polynomial CNNs for Secure Inference over FHE》

文章目录 1、摘要2、介绍3、文章结构4、总结 1、摘要 Machine learning as a service (MLaaS) 在客户中越来越受欢迎。为了解决 MLaaS 中的隐私问题&#xff0c;引入了 FHE 来保护客户端的数据。  然而&#xff0c;FHE 不能直接评估 卷积神经网络 (CNNs) 中的非算数激活函数。…

Redission红锁

目录 一、什么是红锁 二、Redission红锁的使用 一、什么是红锁 Redis 的作者 Salvatore Sanfilippo&#xff08;又名 antirez&#xff09;提出的一种基于多个 Redis 实例实现分布式锁的算法。红锁&#xff08;Redlock&#xff09;旨在解决单点故障问题&#xff0c;即当使用单…

VTK 鼠标+键盘重构

1、鼠标事件 如果有鼠标事件处理等相应的需求,可以重写该事件。 void OnMouseMove() override; //鼠标移动事件 void OnLeftButtonDown() override;//左键按下事件 void OnLeftButtonUp() override;//左键抬起事件 void OnMiddleButtonDown() override;//滚轮按下事件 …

ELK 使用教程采集系统日志 Elasticsearch、Logstash、Kibana

前言 你知道对于一个系统的上线考察&#xff0c;必备的几样东西是什么吗&#xff1f;其实这也是面试中考察求职者&#xff0c;是否真的做过系统开发和上线的必备问题。包括&#xff1a;服务治理(熔断/限流) (opens new window)、监控 (opens new window)和日志&#xff0c;如果…

node内置模块之---path 模块

path 模块的作用 path 模块是 Node.js 的核心模块之一&#xff0c;提供了用于处理和转换文件路径的功能。它能帮助你在不同操作系统间处理文件路径时避免平台差异&#xff08;如 Windows 和 Unix 系统使用不同的路径分隔符&#xff09; path 模块api介绍 使用场景&#xff1a; …

STM32G0B1 can Error_Handler 解决方法

问题现象 MCU上电&#xff0c;发送0x13帧数据固定进入 Error_Handler 硬件介绍 MCU :STM32G0B1 can:NSI1042 tx 接TX RX 接RX 折腾了一下午&#xff0c;无解&#xff0c;问题依旧&#xff1b; 对比测试 STM32G431 手头有块G431 官方评估版CAN 模块&#xff1b; 同样的…

在ros2 jazzy和gazebo harmonic下的建图导航(cartographer和navigation)实现(基本)

我的github分支&#xff01;&#xff01;&#xff01; 你可以在这里找到相对应的源码。 DWDROME的MOGI分支 来源于&#xff01;&#xff01; MOGI-ROS/Week-3-4-Gazebo-basics 学习分支整理日志 分支概述 这是一个用于个人学习的新分支&#xff0c;目的是扩展基本模型并添加…

Redis 实现分布式锁

文章目录 引言一、Redis的两种原子操作1.1 Redis 的原子性1.2 单命令1.3 Lua 脚本1.4 对比单命令与 Lua 脚本 二、Redis 实现分布式锁2.1 分布式锁的概念与需求2.1.1 什么是分布式锁&#xff1f;2.1.2 分布式锁的常见应用场景 2.2 基于 Redis 的分布式锁实现2.2.1 锁的获取与释…

区块链与微服务研究报告

摘要 区块链与微服务架构的结合为现代企业级应用提供了新的解决方案。区块链技术以其不可篡改性和透明性&#xff0c;解决了微服务在分布式环境下的数据一致性和安全性问题。本文将探讨区块链与微服务的基本概念、技术原理、应用案例以及未来研究方向。 1. 引言 随着信息技术…

SAP MM物料管理模块常见BAPI函数清单

【SAP系统研究】 #SAP #MM #物料管理 #函数 #BAPI 1、物料主数据 BAPI_MATERIAL_SAVEDATA 创建/更改物料主数据 BAPI_MATERIAL_SAVEREPLICA 物料主数据视图扩充 BAPI_MATERIAL_EXISTENCECHECK 检查物料主数据是否存在 BAPI_MATERIAL_GETLIST 显示物料主数据明细 BAPI_MATERIALG…

Stable Diffusion和Midjourney有什么区别?

Stable Diffusion 和 Midjourney 主要有以下区别&#xff1a; 目录 费用与可访问性 设备要求 安装与使用 学习成本 图像生成效果 可控性与定制性 私密性 费用与可访问性 Stable Diffusion&#xff1a;开源免费&#xff0c;任何人都可以免费下载并自行部署使用&#xf…

104周六复盘 (188)UI

1、早上继续看二手书的一个章节&#xff0c;程序开发流程、引擎、AI等内容&#xff0c; 内容很浅&#xff0c;基本上没啥用&#xff0c;算是复习。 最大感触就是N年前看同类书的里程碑、AI相关章节时&#xff0c;会感觉跟自己没啥关系&#xff0c; 而如今则密切相关&#xf…

Mono里运行C#脚本23—mono_jit_exec

前面已经分析一部分代码,可以打下基础知识,当然还有很多其它部分的内容,没有深入去了解。 接着下来,我们去探索一下怎么样找到执行应用程序的入口。 在这个嵌入脚本程序里,有一个这样的函数调用: main_function (domain, file, argc - 1, argv + 1); 这个函数的作用,…

浅谈分布式共识算法

分布式共识算法 基础概念1、容错2、共识3、拜占庭将军问题4、多数派5、共识算法分类6、ACID&BASE&CAP Paxos1、相关概念2、三种角色3、运行阶段4、Multi Paxos5、总结6、演化 ZAB1、相关概念2、三种角色3、成员状态4、运行阶段5、ZooKeeper流程6、总结 Raft1、相关概念…

你喜欢看哪类的网上视频教程?

作为前端开发&#xff0c;我通常喜欢看以下几类网上视频教程&#xff1a; 技术框架和库教程&#xff1a;例如React、Vue、Angular等前端框架的教程。这些教程能帮助我深入了解这些框架的工作原理&#xff0c;以及如何高效地使用它们来开发Web应用。 CSS和JavaScript高级技巧&a…

(leetcode算法题)382. 链表随机节点

如果给你一个 智能记录 k行内容的小笔记本&#xff0c;从一本你也不知道有多少行的 C Primer 中进行摘抄&#xff0c;你应该怎么做才能让抄写的时候能让书中的每一行都等概率的出现在小笔记本中&#xff1f; 答&#xff1a;准备好一个公平的轮盘和一个巨大的摇奖机&#xff0c…