国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

springboot實(shí)現(xiàn)后端防重復(fù)提交(AOP+redis分布式鎖)單機(jī)情況下

這篇具有很好參考價(jià)值的文章主要介紹了springboot實(shí)現(xiàn)后端防重復(fù)提交(AOP+redis分布式鎖)單機(jī)情況下。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。


為什么要實(shí)現(xiàn)這個(gè)功能呢,可能用戶在提交一份數(shù)據(jù)后,可能因?yàn)榫W(wǎng)絡(luò)的原因、處理數(shù)據(jù)的速度慢等原因?qū)е马?yè)面沒(méi)有及時(shí)將用戶剛提交數(shù)據(jù)的后臺(tái)處理結(jié)果展示給用戶,這時(shí)用戶可能會(huì)進(jìn)行如下操作:
  1. 1秒內(nèi)連續(xù)點(diǎn)擊提交按鈕,導(dǎo)致重復(fù)提交表單。
  2. 使用瀏覽器后退按鈕重復(fù)之前的操作,導(dǎo)致重復(fù)提交表單
    數(shù)據(jù)庫(kù)中會(huì)存在大量重復(fù)的信息。

怎么實(shí)現(xiàn)呢:進(jìn)入正題??

0、依賴

		<dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.6.8</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>9.0.21</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>2.6.3</version>
        </dependency>

1、自定義接口

/**
 * 自定義注解防止表單重復(fù)提交
 * @author Yuan Haozhe
 */
@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RepeatSubmit {
	 /**
     * 防重復(fù)操作過(guò)期時(shí)間,默認(rèn)1s
     */
    long expireTime() default 1;
}

2、實(shí)現(xiàn)redis分布式鎖

@Component
public class RedisLock {
	@Autowired
    private StringRedisTemplate redisTemplate;
	
	 /**
     * 該加鎖方法僅針對(duì)單實(shí)例 Redis 可實(shí)現(xiàn)分布式加鎖
     * 對(duì)于 Redis 集群則無(wú)法使用
     *
     * 支持重復(fù),線程安全
     *
     * @param lockKey   加鎖鍵
     * @param clientId  加鎖客戶端唯一標(biāo)識(shí)(采用UUID)
     * @param seconds   鎖過(guò)期時(shí)間
     * @return
     */
    public boolean tryLock(String lockKey, String clientId, long seconds) {
        //
        return redisTemplate.opsForValue().setIfAbsent(lockKey, clientId, seconds, TimeUnit.SECONDS);
    }


}

對(duì)參數(shù)進(jìn)行介紹:
第一個(gè)為key,我們使用key來(lái)當(dāng)鎖,因?yàn)閗ey是唯一的。我們傳的是lockKey
第二個(gè)為value,通過(guò)給value賦值為clientId,我們就知道這把鎖是哪個(gè)請(qǐng)求加的了,在解鎖的時(shí)候就可以有依據(jù)。clientId可以使用UUID.randomUUID().toString()方法生成。
第三個(gè)為time,代表key的過(guò)期時(shí)間
第四個(gè)為time的單位
setIfAbsent 相當(dāng)于NX,設(shè)置過(guò)期時(shí)間相當(dāng)于EX

也可用Jedis實(shí)現(xiàn):

  1. 添加依賴:
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
</dependency>
  1. 加鎖代碼
	private static final String LOCK_SUCCESS = "OK";
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";
    private static final String RELEASE_LOCK_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";

    @Autowired
    private Jedis jedis;
    
	public boolean tryLock(String lockKey, String clientId, long seconds) {
        String result = jedis.set(lockKey, clientId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, seconds);
        if (LOCK_SUCCESS.equals(result)) {
            return true;
        }
        return false;
    }
    /**
     * 與 tryLock 相對(duì)應(yīng),用作釋放鎖
     *
     * @param lockKey
     * @param clientId
     * @return
     */
    public boolean releaseLock(String lockKey, String clientId) {
    	//這里使用Lua腳本的方式,盡量保證原子性。
       return jedis.eval(RELEASE_LOCK_SCRIPT,Collections.singletonList(lockKey),Collections.singletonList(clientId)).equals(1L);
        
    }

對(duì)參數(shù)進(jìn)行介紹:
第一個(gè)為key,我們使用key來(lái)當(dāng)鎖,因?yàn)閗ey是唯一的。我們傳的是lockKey
第二個(gè)為value,通過(guò)給value賦值為clientId,我們就知道這把鎖是哪個(gè)請(qǐng)求加的了,在解鎖的時(shí)候就可以有依據(jù)。clientId可以使用UUID.randomUUID().toString()方法生成。
第三個(gè)為nxxx,這個(gè)參數(shù)我們填的是NX,意思是SET IF NOT EXIST,即當(dāng)key不存在時(shí),我們進(jìn)行set操作;若key已經(jīng)存在,則不做任何操作;
第四個(gè)為expx,這個(gè)參數(shù)我們傳的是PX,意思是我們要給這個(gè)key加一個(gè)過(guò)期的設(shè)置,具體時(shí)間由第五個(gè)參數(shù)決定。
第五個(gè)為time,與第四個(gè)參數(shù)相呼應(yīng),代表key的過(guò)期時(shí)間。

可以看到,我們的加鎖就一行代碼,保證了原子性,總的來(lái)說(shuō),執(zhí)行上面的set()方法就只會(huì)導(dǎo)致兩種結(jié)果:1. 當(dāng)前沒(méi)有鎖(key不存在),那么就進(jìn)行加鎖操作,并對(duì)鎖設(shè)置個(gè)有效期,同時(shí)value表示加鎖的客戶端。2. 已有鎖存在,不做任何操作。

3、統(tǒng)一返回值ReturnT

public class ReturnT<T> implements Serializable {
	public static final long serialVersionUID = 42L;

	public static final int SUCCESS_CODE = 200;
	public static final int FAIL_CODE = 500;
	public static final ReturnT<String> SUCCESS = new ReturnT<String>(null);
	public static final ReturnT<String> FAIL = new ReturnT<String>(FAIL_CODE, null);
	
	private int code;
	private String msg;
	private T data;
	
	public ReturnT(int code, String msg) {
		this.code = code;
		this.msg = msg;
	}
	public ReturnT(T data) {
		this.code = SUCCESS_CODE;
		this.data = data;
	}
	
	public int getCode() {
		return code;
	}
	public void setCode(int code) {
		this.code = code;
	}
	public String getMsg() {
		return msg;
	}
	public void setMsg(String msg) {
		this.msg = msg;
	}
	public T getData() {
		return data;
	}
	public void setData(T data) {
		this.data = data;
	}

}

4、CookieUtil

public class CookieUtil {

/**
	 * 查詢value
	 *
	 * @param request
	 * @param key
	 * @return
	 */
	public static String getValue(HttpServletRequest request, String key) {
		Cookie cookie = get(request, key);
		if (cookie != null) {
			return cookie.getValue();
		}
		return null;
	}


}

5、自定義AOP

@Component
@Aspect
@Slf4j
public class NoRepeatSubmitAspect {
    @Pointcut("@annotation(com.xxl.sso.base.annotation.RepeatSubmit)")
    public void repeatSubmit(){}

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private RedisLock redisLock;


    @Around("repeatSubmit()")
    public ReturnT around(ProceedingJoinPoint joinPoint) {
        log.info("校驗(yàn)重復(fù)提交");
        //用戶的身份標(biāo)識(shí),這里用cookie只是方便做測(cè)試
        String userId = CookieUtil.getValue(request, Conf.SSO_SESSIONID).split("_")[0];
        String key = getKey(userId, request.getServletPath());
        String clientId = getClientId();
        
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        // 獲取防重復(fù)提交注解
        RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
        
        boolean isSuccess = redisLock.tryLock(key, clientId, annotation.expireTime());
        // 如果緩存中有這個(gè)url視為重復(fù)提交
        if (isSuccess) {
            Object result = null;
            try {
                result = joinPoint.proceed();

            } catch (Throwable e) {
                log.error(e.getMessage());
            }
            //finall{
            //redisLock.releaseLock(key, clientId)
            //}
            return ReturnT.SUCCESS;
        } else {
            log.error("重復(fù)提交");
            return ReturnT.FAIL;
        }
    }

    private String getKey(String token, String path) {
        return token + path;
    }

    private String getClientId() {
        return UUID.randomUUID().toString();
    }
}

6、測(cè)試

 //測(cè)試重復(fù)提交
    @GetMapping("/test-get")
    //添加RepeatSubmit注解,默認(rèn)1s,方便測(cè)試查看,寫3s
    @RepeatSubmit(expireTime = 3)
    public ReturnT repeatTest(){
        return ReturnT.SUCCESS;
    }

結(jié)果:
springboot實(shí)現(xiàn)后端防重復(fù)提交(AOP+redis分布式鎖)單機(jī)情況下文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-480003.html

到了這里,關(guān)于springboot實(shí)現(xiàn)后端防重復(fù)提交(AOP+redis分布式鎖)單機(jī)情況下的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • springboot aop實(shí)現(xiàn)接口防重復(fù)操作

    一、前言 有時(shí)在項(xiàng)目開(kāi)發(fā)中某些接口邏輯比較復(fù)雜,響應(yīng)時(shí)間長(zhǎng),那么可能導(dǎo)致重復(fù)提交問(wèn)題。 二、如何解決 1.先定義一個(gè)防重復(fù)提交的注解。 2.編寫防重復(fù)操作的AOP 3.接下來(lái)定義redisService類 4.最后在Controller接口加上注解就行了。

    2024年02月11日
    瀏覽(23)
  • Java 解決重復(fù)提交問(wèn)題和表單唯一標(biāo)識(shí)的 Redis 緩存實(shí)現(xiàn)

    在開(kāi)發(fā) Web 應(yīng)用程序時(shí),重復(fù)提交和表單唯一標(biāo)識(shí)是常見(jiàn)的問(wèn)題。重復(fù)提交可能導(dǎo)致數(shù)據(jù)重復(fù)插入或重復(fù)操作,而表單唯一標(biāo)識(shí)則用于確保每個(gè)表單提交都是唯一的。本文將介紹如何使用 Java 來(lái)解決這些問(wèn)題,并結(jié)合 Redis 緩存提供實(shí)際的案例。 什么是重復(fù)提交問(wèn)題? 重復(fù)提

    2024年02月11日
    瀏覽(23)
  • springboot自定義注解+aop+redis實(shí)現(xiàn)延時(shí)雙刪

    springboot自定義注解+aop+redis實(shí)現(xiàn)延時(shí)雙刪

    redis作為用的非常多的緩存數(shù)據(jù)庫(kù),在多線程場(chǎng)景下,可能會(huì)出現(xiàn)數(shù)據(jù)庫(kù)與redis數(shù)據(jù)不一致的現(xiàn)象 數(shù)據(jù)不一致的現(xiàn)象:https://blog.csdn.net/m0_73700925/article/details/133447466 這里采用aop+redis來(lái)解決這個(gè)方法: 刪除緩存 更新數(shù)據(jù)庫(kù) 延時(shí)一定時(shí)間,比如500ms 刪除緩存 這里之所以要延時(shí)一

    2024年01月17日
    瀏覽(21)
  • 【springboot】spring的Aop結(jié)合Redis實(shí)現(xiàn)對(duì)短信接口的限流

    【springboot】spring的Aop結(jié)合Redis實(shí)現(xiàn)對(duì)短信接口的限流

    場(chǎng)景: 為了限制短信驗(yàn)證碼接口的訪問(wèn)次數(shù),防止被刷,結(jié)合Aop和redis根據(jù)用戶ip對(duì)用戶限流 首先我們創(chuàng)建一個(gè) Spring Boot 工程,引入 Web 和 Redis 依賴,同時(shí)考慮到接口限流一般是通過(guò)注解來(lái)標(biāo)記,而注解是通過(guò) AOP 來(lái)解析的,所以我們還需要加上 AOP 的依賴,最終的依賴如下:

    2024年02月05日
    瀏覽(20)
  • SpringBoot使用Redis實(shí)現(xiàn)分布式緩存

    SpringBoot使用Redis實(shí)現(xiàn)分布式緩存

    ?作者簡(jiǎn)介:2022年 博客新星 第八 。熱愛(ài)國(guó)學(xué)的Java后端開(kāi)發(fā)者,修心和技術(shù)同步精進(jìn)。 ??個(gè)人主頁(yè):Java Fans的博客 ??個(gè)人信條:不遷怒,不貳過(guò)。小知識(shí),大智慧。 ??當(dāng)前專欄:SpringBoot 框架從入門到精通 ?特色專欄:國(guó)學(xué)周更-心性養(yǎng)成之路 ??本文內(nèi)容:SpringBoot使用

    2023年04月09日
    瀏覽(20)
  • 基于 SpringBoot + Redis 實(shí)現(xiàn)分布式鎖

    基于 SpringBoot + Redis 實(shí)現(xiàn)分布式鎖

    大家好,我是余數(shù),這兩天溫習(xí)了下分布式鎖,然后就順便整理了這篇文章出來(lái)。 文末附有源碼鏈接,需要的朋友可以自取。 至于什么是分布式鎖,這里不做贅述,不了解的可以自行去查閱資料。 1. 使用 Redis 的 Setnx(SET if Not Exists) 命令加鎖。 即鎖不存在的時(shí)候才能加鎖成功

    2024年02月05日
    瀏覽(18)
  • 使用Redis控制表單重復(fù)提交控制接口訪問(wèn)頻率

    防重提交有很多方案,從前端的按鈕置灰,到后端synchronize鎖、Lock鎖、借助Redis語(yǔ)法實(shí)現(xiàn)簡(jiǎn)單鎖、Redis+Lua分布式鎖、Redisson分布式鎖,再到DB的悲觀鎖、樂(lè)觀鎖、借助表唯一索引等等都可以實(shí)現(xiàn)防重提交,以保證數(shù)據(jù)的安全性。 這篇文章我們介紹其中一種方案– 借助Redis語(yǔ)法實(shí)

    2024年02月09日
    瀏覽(20)
  • springboot3 redis 實(shí)現(xiàn)分布式鎖

    分布式鎖介紹 分布式鎖是一種在分布式系統(tǒng)中用于控制不同節(jié)點(diǎn)上的進(jìn)程或線程對(duì)共享資源進(jìn)行互斥訪問(wèn)的技術(shù)機(jī)制。 在分布式環(huán)境中,多個(gè)服務(wù)可能同時(shí)訪問(wèn)和操作共享資源,如數(shù)據(jù)庫(kù)、文件系統(tǒng)等。為了保持?jǐn)?shù)據(jù)的一致性和完整性,需要確保在同一時(shí)刻只有一個(gè)服務(wù)能

    2024年04月16日
    瀏覽(23)
  • springboot防重復(fù)提交

    1、場(chǎng)景 網(wǎng)頁(yè)卡頓的時(shí)候,用戶點(diǎn)擊會(huì)造成重復(fù)操作 如果前端不做防重復(fù)操作。會(huì)導(dǎo)致重復(fù)提交,重復(fù)下單等意外操作。而且對(duì)于系統(tǒng)資源來(lái)說(shuō)也是一種浪費(fèi) 常規(guī)的解決方法是讓前端把點(diǎn)擊后的按鈕設(shè)置為不可點(diǎn)擊,這樣基本上能就能解決了。99.999999%能解決。前端這么弄過(guò)

    2024年02月09日
    瀏覽(19)
  • springBoot防止重復(fù)提交

    springBoot防止重復(fù)提交

    兩種方法, 一種是后端實(shí)現(xiàn),較復(fù)雜,要通過(guò)自定義注解和AOP以及Redis組合實(shí)現(xiàn) 另一種是前端實(shí)現(xiàn),簡(jiǎn)單,只需通過(guò)js,設(shè)置過(guò)期時(shí)間,一定時(shí)間內(nèi),多次點(diǎn)擊按鈕只生效一次 自定義注解+AOP+Redis 自定義異常類和全局異常處理 自定義異常類:CustomException 全局異常處理:Cust

    2024年02月11日
    瀏覽(21)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包