SpringBoot在一定時(shí)間內(nèi)限制接口請(qǐng)求次數(shù)的實(shí)現(xiàn)示例
需要用到的知識(shí):注解、AOP、ExpiringMap(帶有有效期的映射)
我們可以自定義注解,把注解添加到我們的接口上。定義一個(gè)切面,執(zhí)行方法前去ExpiringMap查詢?cè)揑P在規(guī)定時(shí)間內(nèi)請(qǐng)求了多少次,如超過(guò)次數(shù)則直接返回請(qǐng)求失敗。
需要用到的依賴
<!-- AOP依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.1.5.RELEASE</version>
</dependency>
<!-- Map依賴 -->
<dependency>
<groupId>net.jodah</groupId>
<artifactId>expiringmap</artifactId>
<version>0.5.8</version>
</dependency>自定義注解@LimitRequest
@Documented
@Target(ElementType.METHOD) // 說(shuō)明該注解只能放在方法上面
@Retention(RetentionPolicy.RUNTIME)
public @interface LimitRequest {
long time() default 6000; // 限制時(shí)間 單位:毫秒
int count() default 1; // 允許請(qǐng)求的次數(shù)
}自定義AOP
@Aspect
@Component
public class LimitRequestAspect {
private static ConcurrentHashMap<String, ExpiringMap<String, Integer>> book = new ConcurrentHashMap<>();
// 定義切點(diǎn)
// 讓所有有@LimitRequest注解的方法都執(zhí)行切面方法
@Pointcut("@annotation(limitRequest)")
public void excudeService(LimitRequest limitRequest) {
}
@Around("excudeService(limitRequest)")
public Object doAround(ProceedingJoinPoint pjp, LimitRequest limitRequest) throws Throwable {
// 獲得request對(duì)象
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
HttpServletRequest request = sra.getRequest();
// 獲取Map對(duì)象, 如果沒(méi)有則返回默認(rèn)值
// 第一個(gè)參數(shù)是key, 第二個(gè)參數(shù)是默認(rèn)值
ExpiringMap<String, Integer> uc = book.getOrDefault(request.getRequestURI(), ExpiringMap.builder().variableExpiration().build());
Integer uCount = uc.getOrDefault(request.getRemoteAddr(), 0);
if (uCount >= limitRequest.count()) { // 超過(guò)次數(shù),不執(zhí)行目標(biāo)方法
return "接口請(qǐng)求超過(guò)次數(shù)";
} else if (uCount == 0){ // 第一次請(qǐng)求時(shí),設(shè)置有效時(shí)間
// /** Expires entries based on when they were last accessed */
// ACCESSED,
// /** Expires entries based on when they were created */
// CREATED;
uc.put(request.getRemoteAddr(), uCount + 1, ExpirationPolicy.CREATED, limitRequest.time(), TimeUnit.MILLISECONDS);
} else { // 未超過(guò)次數(shù), 記錄加一
uc.put(request.getRemoteAddr(), uCount + 1);
}
book.put(request.getRequestURI(), uc);
// result的值就是被攔截方法的返回值
Object result = pjp.proceed();
return result;
}
}第一個(gè)靜態(tài)Map是多線程安全的Map(ConcurrentHashMap),它的key是接口對(duì)于的url,它的value是一個(gè)多線程安全且鍵值對(duì)是有有效期的Map(ExpiringMap)。
ExpiringMap的key是請(qǐng)求的ip地址,value是已經(jīng)請(qǐng)求的次數(shù)。
ExpiringMap更多的使用方法可以參考:https://github.com/jhalterman/expiringmap

最后在方法上面加上@LimitRequest就行了

到此這篇關(guān)于SpringBoot在一定時(shí)間內(nèi)限制接口請(qǐng)求次數(shù)的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)SpringBoot 限制接口請(qǐng)求次數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在java中使用SPI創(chuàng)建可擴(kuò)展的應(yīng)用程序操作
這篇文章主要介紹了在java中使用SPI創(chuàng)建可擴(kuò)展的應(yīng)用程序操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09
springboot集成ES實(shí)現(xiàn)磁盤文件全文檢索的示例代碼
這篇文章主要介紹了springboot集成ES實(shí)現(xiàn)磁盤文件全文檢索的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11
Java OpenCV利用KNN算法實(shí)現(xiàn)圖像背景移除
這篇文章主要為大家介紹了Java OpenCV利用K最鄰近(KNN,K-NearestNeighbor)分類算法實(shí)現(xiàn)圖像背景移除的示例代碼,需要的可以參考一下2022-01-01
Spring boot實(shí)現(xiàn)上傳文件到本地服務(wù)器
這篇文章主要為大家詳細(xì)介紹了Spring boot實(shí)現(xiàn)上傳文件到本地服務(wù)器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08
詳解SpringBoot+Thymeleaf 基于HTML5的現(xiàn)代模板引擎
本篇文章主要介紹了SpringBoot+Thymeleaf 基于HTML5的現(xiàn)代模板引擎,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10
關(guān)于Java的動(dòng)態(tài)代理機(jī)制
這篇文章主要介紹了關(guān)于Java的動(dòng)態(tài)代理機(jī)制,動(dòng)態(tài)代理就是,在程序運(yùn)行期,創(chuàng)建目標(biāo)對(duì)象的代理對(duì)象,并對(duì)目標(biāo)對(duì)象中的方法進(jìn)行功能性增強(qiáng)的一種技術(shù),需要的朋友可以參考下2023-05-05
關(guān)于SpringCloudStream配置問(wèn)題
這篇文章主要介紹了關(guān)于SpringCloudStream配置問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12
java Collection 之List學(xué)習(xí)介紹
本篇文章小編為大家介紹,java Collection 之List學(xué)習(xí)介紹。需要的朋友參考下2013-04-04

