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,一经查实,立即删除!

相关文章

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

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

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

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

STM32G0B1 can Error_Handler 解决方法

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

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 锁的获取与释…

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

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

104周六复盘 (188)UI

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

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

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

腾讯云智能结构化 OCR:驱动多行业数字化转型的核心引擎

在当今数字化时代的汹涌浪潮中&#xff0c;数据已跃升为企业发展的关键要素&#xff0c;其高效、精准的处理成为企业在激烈市场竞争中脱颖而出的核心竞争力。腾讯云智能结构化 OCR 技术凭借其前沿的科技架构与卓越的功能特性&#xff0c;宛如一颗璀璨的明星&#xff0c;在交通、…

2025-01-04 Unity插件 YodaSheet2 —— 基础用法

文章目录 环境配置1 创建 YadeSheetData2 读取方式2.1 表格读取2.2 列表读取 3 自定义设置3.1 修改代码生成位置3.2 添加列表支持3.2.1 修改 DataTypeMapper.cs3.2.2 修改 SheetDataExtensions.cs3.2.3 修改 CodeGeneratorEditor.cs3.2.4 测试 ​ 官方文档&#xff1a; Unity …

matlab时频分析库

time frequency gallery

『 Linux 』高级IO (三) - Epoll模型的封装与EpollEchoServer服务器

文章目录 前情提要Epoll 的封装Epoll封装完整代码(供参考) Epoll Echo ServerEpoll Echo Server 测试及完整代码 前情提要 在上一篇博客『 Linux 』高级IO (二) - 多路转接介绍并完成了两种多路转接方案的介绍以及对应多路转接方案代码的编写,分别为SelectServer服务器与PollSe…

PDF预览插件

PDF预览插件 可用于当前页面弹窗形式查看,可增加一些自定义功能 pdf预览插件 代码块: pdfobject.js <div class="pdfwrap"><div class="item"><h3>笑场</h3><div class="tags"><p>李诞</p><i&…

【Java项目】基于SpringBoot的【新生宿舍管理系统】

【Java项目】基于SpringBoot的【新生宿舍管理系统】 技术简介&#xff1a;本系统使用采用B/S架构、Spring Boot框架、MYSQL数据库进行开发设计。 系统简介&#xff1a;管理员登录进入新生宿舍管理系统可以查看首页、个人中心、公告信息管理、院系管理、班级管理、学生管理、宿舍…

Huginn - 构建代理、执行自动化任务

文章目录 一、关于 Huginn什么是Huginn&#xff1f;Huginn 功能加入Huginn展示 二、安装1、Docker2、本地安装3、开发 三、使用Huginn代理gems四、部署1、Heroku2、OpenShiftOpenShift 在线 3、在任何服务器上手动安装4、可选设置4.1 私人开发设置4.2 启用WeatherAgent4.3 禁用…

电子应用设计方案86:智能 AI背景墙系统设计

智能 AI 背景墙系统设计 一、引言 智能 AI 背景墙系统旨在为用户创造一个动态、个性化且具有交互性的空间装饰体验&#xff0c;通过融合先进的技术和创意设计&#xff0c;提升室内环境的美观度和功能性。 二、系统概述 1. 系统目标 - 提供多种主题和风格的背景墙显示效果&…

基于Spring Boot的IT技术交流和分享平台的设计与实现源码

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的IT技术交流和分享平台的设计与实现。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 基于S…

单元测试3.0+ @RunWith(JMockit.class)+mock+injectable+Expectations

Jmockit使用笔记_基本功能使用Tested_Injectable_Mocked_Expectations_jmockit.class-CSDN博客 静态变量直接赋值就好&#xff0c;没必要mock了 测试框架Jmockit集合junit使用 RunWith(JMockit.class) 写在测试案例类上的注解 Tested 在测试案例中,写在我们要测试的类上…

PADS Logic原理图中有很多页原理图,如何(怎样)删除其中一页或者多页

我们在进行PADS Logic进行原理图设计的时候&#xff0c;有时候可能遇到一次性设计了很多页的原理图&#xff0c;比如说十几页的原理图。那么我们在进行PADS Layout的时候&#xff0c;可能将这些原理图绘制两块板或者多块PCB板&#xff0c;那么这时候我们需要将其中的一张原理图…