最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring防止重復(fù)點(diǎn)擊的兩種實(shí)現(xiàn)方法

 更新時(shí)間:2025年01月07日 10:08:14   作者:小呂學(xué)編程  
頁面重復(fù)提交導(dǎo)致的問題就是數(shù)據(jù)被重復(fù)保存,我們經(jīng)常會誤觸點(diǎn)擊兩次,所以本文小編給大家介紹了Spring防止重復(fù)點(diǎn)擊的兩種實(shí)現(xiàn)方法,需要的朋友可以參考下

第一種:@EasyLock

簡介

為了簡化可復(fù)用注解,自己實(shí)現(xiàn)的注解,代碼簡單隨拿隨用

使用方式

1.創(chuàng)建一個(gè)注解

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

 2. 創(chuàng)建一個(gè)AOP切面類(異??梢宰远x,這里我用的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("當(dāng)前線程{},釋放鎖:{}", Thread.currentThread().getId(), redisLockKey);
            }
        }
    }
@CicadaBean(namespace = "lock")
public interface LockException {
    @ExceptionInfo(errCode = 13001, errMessage = "沒找到分布式鎖key")
    CicadaException lockKeyNotExist();
 
    @ExceptionInfo(errCode = 13002, errMessage = "超時(shí)未獲取到鎖: %s")
    CicadaException getLockTimeOut(String key);
}

3.使用方式

 注意點(diǎn):

必須包含名為redisLockKey的參數(shù),作為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的,甚至最新版本,不然有問題!?。?/p>

<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 = "服務(wù)已完成評價(jià),不能重復(fù)提交"
    )
    public void test(String userId) {
        System.out.println("修改訂單: 用戶ID=" + userId);
    }

注解中傳入了exception參數(shù)后,報(bào)錯會輸出message的內(nèi)容,更加直觀 

測試方式

Apifox中的自動化測試中可以配多個(gè)線程同時(shí)執(zhí)行接口,測試重復(fù)點(diǎn)擊是否生效

到此這篇關(guān)于Spring防止重復(fù)點(diǎn)擊的兩種實(shí)現(xiàn)方法的文章就介紹到這了,更多相關(guān)Spring防止重復(fù)點(diǎn)擊內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java解決約瑟夫問題代碼實(shí)例

    Java解決約瑟夫問題代碼實(shí)例

    這篇文章主要介紹了Java解決約瑟夫(環(huán))問題的代碼實(shí)例,決約瑟問題貌似經(jīng)常出現(xiàn)在面試題中,需要的朋友可以參考下
    2014-03-03
  • Java 使用Filter實(shí)現(xiàn)用戶自動登陸

    Java 使用Filter實(shí)現(xiàn)用戶自動登陸

    這篇文章主要介紹了Java 使用Filter實(shí)現(xiàn)用戶自動登陸的方法,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下
    2021-05-05
  • Java源碼刨析之ArrayQueue

    Java源碼刨析之ArrayQueue

    在本篇文章當(dāng)中主要給大家介紹一個(gè)比較簡單的JDK為我們提供的容器ArrayQueue,這個(gè)容器主要是用數(shù)組實(shí)現(xiàn)的一個(gè)單向隊(duì)列,整體的結(jié)構(gòu)相對其他容器來說就比較簡單了
    2022-07-07
  • java中的4種循環(huán)方法示例詳情

    java中的4種循環(huán)方法示例詳情

    大家好,本篇文章主要講的是java中的4種循環(huán)方法示例詳情,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • JAVA實(shí)現(xiàn)微信APPV3支付保姆級教程

    JAVA實(shí)現(xiàn)微信APPV3支付保姆級教程

    微信實(shí)現(xiàn)支付功能與支付寶實(shí)現(xiàn)支付功能是相似的,這篇文章主要介紹了JAVA實(shí)現(xiàn)微信APPV3支付的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-01-01
  • Java的MyBatis框架中XML映射緩存的使用教程

    Java的MyBatis框架中XML映射緩存的使用教程

    MyBatis程序在做好XML映射后能夠有緩存的功能,這樣映射過SQL語句的配置以后就可以拿過來直接用了,這里我們來一起總結(jié)一下Java的MyBatis框架中XML映射緩存的使用教程
    2016-06-06
  • Java多線程中Thread.currentThread()和this的區(qū)別詳解

    Java多線程中Thread.currentThread()和this的區(qū)別詳解

    這篇文章主要介紹了Java多線程中Thread.currentThread()和this的區(qū)別詳解,Thread.currentThread()方法返回的是對當(dāng)前正在執(zhí)行的線程對象的引用,this代表的是當(dāng)前調(diào)用它所在函數(shù)所屬的對象的引用,需要的朋友可以參考下
    2023-08-08
  • Java實(shí)現(xiàn)簡單連連看游戲

    Java實(shí)現(xiàn)簡單連連看游戲

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)簡單連連看游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • Echarts+SpringMvc顯示后臺實(shí)時(shí)數(shù)據(jù)

    Echarts+SpringMvc顯示后臺實(shí)時(shí)數(shù)據(jù)

    這篇文章主要為大家詳細(xì)介紹了Echarts+SpringMvc顯示后臺實(shí)時(shí)數(shù)據(jù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • 在idea中顯示springboot面板的方法

    在idea中顯示springboot面板的方法

    這篇文章主要介紹了在idea中顯示springboot面板的方法方便啟動調(diào)試,本文通過代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11

最新評論

萨嘎县| 盐亭县| 红桥区| 东山县| 肃宁县| 错那县| 绥棱县| 东山县| 宣威市| 广宗县| 兴和县| 台南县| 五指山市| 巫山县| 栖霞市| 威海市| 礼泉县| 天等县| 石渠县| 鄱阳县| 赤水市| 什邡市| 余江县| 奎屯市| 阳东县| 潮州市| 周口市| 海原县| 冷水江市| 晋宁县| 辉南县| 平顶山市| 连云港市| 隆化县| 彭泽县| 九寨沟县| 莆田市| 呼图壁县| 长春市| 无棣县| 五家渠市|