Spring防止重复点击的两种实现方法
第一种:@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 { @Resource private LockException lockException; @Resource RedissonClient 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
简介
大佬提供的公共组件,引包后可直接使用,使用简单
使用方式
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中的自动化测试中可以配多个线程同时执行接口,测试重复点击是否生效
到此这篇关于Spring防止重复点击的两种实现方法的文章就介绍到这了,更多相关Spring防止重复点击内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Spring、SpringMvc和SpringBoot的区别及说明
Spring框架提供了全面的Java开发解决方案,核心包括IOC和AOP,SpringMvc作为其中的WEB层开发框架,通过复杂的XML配置管理前端视图和后台逻辑,SpringBoot则简化了配置,专注于微服务接口开发,支持嵌入式服务器,提高了开发效率2024-10-10Java开发HashMap key必须实现hashCode equals方法原理
这篇文章主要为大家介绍了Java开发HashMap key必须实现hashCode equals方法原理详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪2023-03-03Java httpcomponents发送get post请求代码实例
这篇文章主要介绍了Java httpcomponents发送get post请求代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下2020-09-09
最新评论