From dd4d882393f81fcc6ad615ca80ff35d477f0b5f5 Mon Sep 17 00:00:00 2001 From: kaede10 Date: Thu, 22 Feb 2024 14:47:36 +0800 Subject: [PATCH 1/2] Add LimitRequest --- .../query/ApplicationVersionAdapter.java | 5 ++ .../java/com/easysoftware/aop/CallMark.java | 12 ++++ .../com/easysoftware/aop/LimitRequest.java | 15 +++++ .../easysoftware/aop/LimitRequestAspect.java | 65 +++++++++++++++++++ .../com/easysoftware/result/MessageCode.java | 1 + 5 files changed, 98 insertions(+) create mode 100644 src/main/java/com/easysoftware/aop/CallMark.java create mode 100644 src/main/java/com/easysoftware/aop/LimitRequest.java create mode 100644 src/main/java/com/easysoftware/aop/LimitRequestAspect.java diff --git a/src/main/java/com/easysoftware/adapter/query/ApplicationVersionAdapter.java b/src/main/java/com/easysoftware/adapter/query/ApplicationVersionAdapter.java index 8448d28..ca92c5c 100644 --- a/src/main/java/com/easysoftware/adapter/query/ApplicationVersionAdapter.java +++ b/src/main/java/com/easysoftware/adapter/query/ApplicationVersionAdapter.java @@ -13,6 +13,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import com.easysoftware.aop.LimitRequest; import com.easysoftware.application.applicationversion.ApplicationVersionService; import com.easysoftware.application.applicationversion.dto.ApplicationVersionSearchCondition; import com.easysoftware.application.applicationversion.dto.InputApplicationVersion; @@ -26,24 +27,28 @@ public class ApplicationVersionAdapter { private ApplicationVersionService appVersionService; @PostMapping("") + @LimitRequest(callTime = 10, callCount = 30) public ResponseEntity insertAppVersion(@Valid @RequestBody InputApplicationVersion inputAppVersion) { ResponseEntity res = appVersionService.insertAppVersion(inputAppVersion); return res; } @PutMapping() + @LimitRequest() public ResponseEntity updateAppVersion(@Valid @RequestBody InputApplicationVersion inputAppVersion) { ResponseEntity res = appVersionService.updateAppVersion(inputAppVersion); return res; } @DeleteMapping(value = "/{names}") + @LimitRequest() public ResponseEntity deleteAppVersion(@PathVariable List names) { ResponseEntity res = appVersionService.deleteAppVersion(names); return res; } @GetMapping() + @LimitRequest() public ResponseEntity searchAppVersion(@Valid ApplicationVersionSearchCondition condition) { ResponseEntity res = appVersionService.searchAppVersion(condition); return res; diff --git a/src/main/java/com/easysoftware/aop/CallMark.java b/src/main/java/com/easysoftware/aop/CallMark.java new file mode 100644 index 0000000..0975ba8 --- /dev/null +++ b/src/main/java/com/easysoftware/aop/CallMark.java @@ -0,0 +1,12 @@ +package com.easysoftware.aop; + +import java.time.Instant; + +import lombok.Data; + +@Data +public class CallMark { + private Instant lastCallTime; + private int callCount; + +} diff --git a/src/main/java/com/easysoftware/aop/LimitRequest.java b/src/main/java/com/easysoftware/aop/LimitRequest.java new file mode 100644 index 0000000..f07e72f --- /dev/null +++ b/src/main/java/com/easysoftware/aop/LimitRequest.java @@ -0,0 +1,15 @@ +package com.easysoftware.aop; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Documented +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface LimitRequest { + int callTime() default 1; + int callCount() default 10; +} diff --git a/src/main/java/com/easysoftware/aop/LimitRequestAspect.java b/src/main/java/com/easysoftware/aop/LimitRequestAspect.java new file mode 100644 index 0000000..1f4b973 --- /dev/null +++ b/src/main/java/com/easysoftware/aop/LimitRequestAspect.java @@ -0,0 +1,65 @@ +package com.easysoftware.aop; + +import java.time.Duration; +import java.time.Instant; +import java.util.concurrent.ConcurrentHashMap; + +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.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; + +import com.easysoftware.result.MessageCode; +import com.easysoftware.result.Result; + +@Aspect +@Component +public class LimitRequestAspect { + + private final ConcurrentHashMap callMarkMap = new ConcurrentHashMap<>(); + + @Pointcut("@annotation(limitRequest)") + public void exudeService(LimitRequest limitRequest) {} + + + @Around(value = "exudeService(limitRequest)", argNames = "joinPoint,limitRequest") + public Object before(ProceedingJoinPoint joinPoint, LimitRequest limitRequest) throws Throwable { + if (!isAllowed(joinPoint.getSignature().getName(), limitRequest)) { + return Result.fail(HttpStatus.BANDWIDTH_LIMIT_EXCEEDED, MessageCode.EC00010); + } + + return joinPoint.proceed(); + } + + + public boolean isAllowed(String methodName, LimitRequest limitRequest) { + Duration timeWindow = Duration.ofSeconds(limitRequest.callTime()); + Instant now = Instant.now(); + if (callMarkMap.containsKey(methodName)) { + CallMark callMark = callMarkMap.get(methodName); + + if (Duration.between(callMark.getLastCallTime(), now).compareTo(timeWindow) > 0) { + callMark.setLastCallTime(now); + callMark.setCallCount(0); + } + + if (callMark.getCallCount() < limitRequest.callCount()) { + callMark.setCallCount(callMark.getCallCount() + 1); + callMarkMap.put(methodName, callMark); + return true; + } + return false; + + } else { + CallMark callMark = new CallMark(); + callMark.setLastCallTime(now); + callMark.setCallCount(1); + callMarkMap.put(methodName, callMark); + return true; + } + } + +} + diff --git a/src/main/java/com/easysoftware/result/MessageCode.java b/src/main/java/com/easysoftware/result/MessageCode.java index 9f6b414..c4d15c8 100644 --- a/src/main/java/com/easysoftware/result/MessageCode.java +++ b/src/main/java/com/easysoftware/result/MessageCode.java @@ -26,6 +26,7 @@ public enum MessageCode { EC0007("EC0007", "query failed", "查找失败"), EC0008("EC0008", "Item existed", "项目已存在"), EC0009("EC0009", "Item not existed", "项目不存在"), + EC00010("EC00010", "Request exceeds the limit", "请求超过限制"), // self service exception ES0001("ES0001", "Internal Server Error", "服务异常"); -- Gitee From 275fd8cce206c3caea9820fd0b6871a447a5bdbb Mon Sep 17 00:00:00 2001 From: kaede10 Date: Thu, 22 Feb 2024 14:55:25 +0800 Subject: [PATCH 2/2] update error code --- src/main/java/com/easysoftware/aop/LimitRequestAspect.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/easysoftware/aop/LimitRequestAspect.java b/src/main/java/com/easysoftware/aop/LimitRequestAspect.java index 1f4b973..e32b778 100644 --- a/src/main/java/com/easysoftware/aop/LimitRequestAspect.java +++ b/src/main/java/com/easysoftware/aop/LimitRequestAspect.java @@ -27,7 +27,7 @@ public class LimitRequestAspect { @Around(value = "exudeService(limitRequest)", argNames = "joinPoint,limitRequest") public Object before(ProceedingJoinPoint joinPoint, LimitRequest limitRequest) throws Throwable { if (!isAllowed(joinPoint.getSignature().getName(), limitRequest)) { - return Result.fail(HttpStatus.BANDWIDTH_LIMIT_EXCEEDED, MessageCode.EC00010); + return Result.fail(HttpStatus.TOO_MANY_REQUESTS, MessageCode.EC00010); } return joinPoint.proceed(); -- Gitee