Redis實(shí)現(xiàn)接口防抖的示例代碼
說明:實(shí)際開發(fā)中,我們在前端頁面上點(diǎn)擊了一個按鈕,訪問了一個接口,這時因?yàn)榫W(wǎng)絡(luò)波動或者其他原因,頁面上沒有反應(yīng),用戶可能會在短時間內(nèi)再次點(diǎn)擊一次或者用戶以為沒有點(diǎn)到,很快的又點(diǎn)了一次。導(dǎo)致短時間內(nèi)發(fā)送了兩個請求到后臺,可能會導(dǎo)致數(shù)據(jù)重復(fù)添加。
為了避免短時間內(nèi)對一個接口訪問,我們可以通過AOP+自定義注解+Redis的方式,在接口上加一個自定義注解,然后通過AOP的前置通知,在Redis中存入一個有效期的值,當(dāng)訪問接口時這個值還未過期,則拋出異常,以此來避免短時間內(nèi)對接口的方法。
實(shí)現(xiàn)
第一步:創(chuàng)建一個自定義注解,設(shè)置兩個屬性,一個是key,一個是這個key在Redis中的有效時間;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定義注解
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LimitAccess {
/**
* 限制訪問的key
* @return
*/
String key();
/**
* 限制訪問時間
* @return
*/
int times();
}
第二步:創(chuàng)建對應(yīng)的Aspect;
import com.hezy.annotation.LimitAccess;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* AOP類(通知類)
*/
@Component
@Aspect
public class LimitAspect {
@Autowired
private RedisTemplate redisTemplate;
@Pointcut("@annotation(com.hezy.annotation.LimitAccess)")
public void pt(){};
@Around("pt()")
public Object aopAround(ProceedingJoinPoint pjp) throws Throwable {
// 獲取切入點(diǎn)上面的自定義注解
Signature signature = pjp.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
// 獲取方法上面的注解
LimitAccess limitAccess = methodSignature.getMethod().getAnnotation(LimitAccess.class);
// 獲取注解上面的屬性
int limit = limitAccess.times();
String key = limitAccess.key();
// 根據(jù)key去找Redis中的值
Object o = redisTemplate.opsForValue().get(key);
// 如果不存在,說明是首次訪問,存入Redis,過期時間為limitAccess中的time
if (o == null) {
redisTemplate.opsForValue().set(key, "", limit, TimeUnit.SECONDS);
// 執(zhí)行切入點(diǎn)的方法
return pjp.proceed();
} else {
// 如果存在,說明不是首次訪問,拋出異常
throw new RuntimeException("訪問過于頻繁");
}
}
}
第三步:在需要限制的接口上,加上這個注解,并設(shè)置key和限制訪問時間,如下這個這個接口,設(shè)置key為limit,實(shí)際開發(fā)中可以設(shè)置一個隨機(jī)值,或者按照規(guī)則自定義設(shè)置,times為限制訪問時間;
@GetMapping("/limit")
@LimitAccess(key = "limit", times = 10)
public String limit() {
return "success";
}
演示
啟動項(xiàng)目,訪問該接口;
(首次訪問,沒得問題,同時在Redis中存入值)

(短時間內(nèi),連續(xù)訪問,因?yàn)镽edis中值未過期)


(10秒之后再訪問,又可以了,Redis中的值過期了)

以上就是使用Redis實(shí)現(xiàn)接口防抖,避免短時間內(nèi)連續(xù)訪問接口。實(shí)際開發(fā)中,可以將異常設(shè)置為自定義異常。
到此這篇關(guān)于Redis實(shí)現(xiàn)接口防抖的示例代碼的文章就介紹到這了,更多相關(guān)Redis 接口防抖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Redis實(shí)現(xiàn)每周熱評的項(xiàng)目實(shí)踐
實(shí)時統(tǒng)計(jì)和展示熱門內(nèi)容是一種常見的需求,本文主要介紹了Redis實(shí)現(xiàn)每周熱評的項(xiàng)目實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-03-03
Redisson分布式限流的實(shí)現(xiàn)原理解析
這篇文章主要為大家介紹了Redisson分布式限流的實(shí)現(xiàn)原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02
淺析Redis中String數(shù)據(jù)類型及其底層編碼
這篇文章主要介紹?Redis?中?String?數(shù)據(jù)類型及其底層編碼,文中有詳細(xì)的代碼示例,對大家的工作及學(xué)習(xí)有一定的幫助,需要的朋友可以參考下2023-05-05
基于Redis實(shí)現(xiàn)分布式鎖以及任務(wù)隊(duì)列
這篇文章主要介紹了基于Redis實(shí)現(xiàn)分布式鎖以及任務(wù)隊(duì)列,需要的朋友可以參考下2015-11-11
Redis結(jié)合Lua腳本實(shí)現(xiàn)分布式鎖詳解
Lua?是一種輕量小巧的腳本語言,用標(biāo)準(zhǔn)C語言編寫并以源代碼形式開放,?本文主要為大家介紹了Redis如何結(jié)合Lua腳本實(shí)現(xiàn)分布式鎖,需要的可以參考下2024-02-02
Redis數(shù)據(jù)結(jié)構(gòu)之鏈表與字典的使用
這篇文章主要介紹了Redis數(shù)據(jù)結(jié)構(gòu)之鏈表與字典的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05

