当前位置: 代码网 > it编程>编程语言>Java > Spring防止重复点击的两种实现方法

Spring防止重复点击的两种实现方法

2025年01月08日 Java 我要评论
第一种:@easylock简介为了简化可复用注解,自己实现的注解,代码简单随拿随用使用方式1.创建一个注解@target(elementtype.method)@retention(retention

第一种:@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防止重复点击内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com