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

打印 上一主题 下一主题

主题 1849|帖子 1849|积分 5547

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
第一种:@EasyLock

简介

   为了简化可复用注解,自己实现的注解,代码简朴随拿随用
  使用方式

1.创建一个注解
  1. @Target(ElementType.METHOD)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. public @interface EasyLock {
  5.     long waitTime() default 1;
  6.     long leaseTime() default 3;
  7. }
复制代码
 2. 创建一个AOP切面类(异常可以自界说,这里我用的Cicada)
  1. import lombok.extern.slf4j.Slf4j;
  2. import org.apache.commons.lang.StringUtils;
  3. import org.aspectj.lang.ProceedingJoinPoint;
  4. import org.aspectj.lang.annotation.Around;
  5. import org.aspectj.lang.annotation.Aspect;
  6. import org.aspectj.lang.annotation.Pointcut;
  7. import org.aspectj.lang.reflect.MethodSignature;
  8. import org.redisson.api.RLock;
  9. import org.redisson.api.RedissonClient;
  10. import org.springframework.stereotype.Component;
  11. import vip.lspace.agent.common.annotation.EasyLock;
  12. import vip.lspace.agent.common.exception.LockException;
  13. import javax.annotation.Resource;
  14. import java.util.concurrent.TimeUnit;
  15. @Component
  16. @Aspect
  17. @Slf4j
  18. public class LockAop {
  19.     @Resource
  20.     private LockException lockException;
  21.     @Resource
  22.     RedissonClient redissonClient;
  23.     private static final String redisLockKeyParamName = "redisLockKey";
  24.     @Pointcut("@annotation(vip.lspace.agent.common.annotation.EasyLock)")
  25.     public void lockPointcut() {
  26.     }
  27.     @Around("lockPointcut()")
  28.     public Object doAround(ProceedingJoinPoint proceedingJoinPoint) {
  29.         log.info("EasyLock locking");
  30.         MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
  31.         EasyLock easyLock = methodSignature.getMethod().getAnnotation(EasyLock.class);
  32.         Object[] args = proceedingJoinPoint.getArgs();
  33.         String[] parameterNames = methodSignature.getParameterNames();
  34.         String redisLockKey = "";
  35.         for (int i = 0; i < parameterNames.length; i++) {
  36.             if (parameterNames[i].equals(redisLockKeyParamName)) {
  37.                 redisLockKey = (String) args[i];
  38.             }
  39.         }
  40.         if (StringUtils.isBlank(redisLockKey)) {
  41.             throw lockException.lockKeyNotExist();
  42.         }
  43.         RLock lock = redissonClient.getLock(redisLockKey);
  44.         try {
  45.             if (!lock.tryLock(easyLock.waitTime(), easyLock.leaseTime(), TimeUnit.SECONDS)) {
  46.                 throw lockException.getLockTimeOut(redisLockKey);
  47.             }
  48.             return proceedingJoinPoint.proceed();
  49.         } catch (Throwable e) {
  50.             throw new RuntimeException(e);
  51.         } finally {
  52.             if (lock.isLocked() && lock.isHeldByCurrentThread()) {
  53.                 lock.unlock();
  54.                 log.info("当前线程{},释放锁:{}", Thread.currentThread().getId(), redisLockKey);
  55.             }
  56.         }
  57.     }
复制代码
  1. @CicadaBean(namespace = "lock")
  2. public interface LockException {
  3.     @ExceptionInfo(errCode = 13001, errMessage = "没找到分布式锁key")
  4.     CicadaException lockKeyNotExist();
  5.     @ExceptionInfo(errCode = 13002, errMessage = "超时未获取到锁: %s")
  6.     CicadaException getLockTimeOut(String key);
  7. }
复制代码
3.使用方式
    留意点:
  必须包含名为redisLockKey的参数,作为redis的key
  1. @Override
  2.     @EasyLock(waitTime = 1,
  3.             leaseTime = 3
  4.     )
  5.     @Transactional(rollbackFor = Exception.class)
  6.     public void concurrentTest(String redisLockKey) {
  7.         PaymentBillBacktrack paymentBillBacktrack = paymentBillBacktrackService.getById(1L);
  8.         String refundRequestNo = paymentBillBacktrack.getMerchantRefundRequestNo();
  9.         paymentBillBacktrack.setMerchantRefundRequestNo(String.valueOf(Integer.parseInt(refundRequestNo) + 1));
  10.         paymentBillBacktrackService.updateById(paymentBillBacktrack);
  11.     }
复制代码
第二种:@NiceLock

简介

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

1.引包
肯定得引入1.1.6的,甚至最新版本,否则有问题!!!
  1. <dependency>
  2.      <groupId>com.suchtool</groupId>
  3.      <artifactId>nicelock-spring-boot-starter</artifactId>
  4.      <version>1.1.6</version>
  5. </dependency>
复制代码
2.使用
  1.     @Override
  2.     @Transactional
  3.     @NiceLock(
  4.             keys = {"#userId"},
  5.             acquireTimeout = 3000L,
  6.             exception = NiceLockLockFailException.class,
  7.             message = "服务已完成评价,不能重复提交"
  8.     )
  9.     public void test(String userId) {
  10.         System.out.println("修改订单: 用户ID=" + userId);
  11.     }
复制代码
  注解中传入了exception参数后,报错会输出message的内容,更加直观 
  测试方式

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


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

没腿的鸟

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表