|
@@ -0,0 +1,87 @@
|
|
|
+package com.backendsys.aspect;
|
|
|
+
|
|
|
+import jakarta.servlet.http.HttpServletRequest;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.aspectj.lang.JoinPoint;
|
|
|
+import org.aspectj.lang.annotation.Aspect;
|
|
|
+import org.aspectj.lang.annotation.Before;
|
|
|
+import org.aspectj.lang.reflect.MethodSignature;
|
|
|
+import org.springframework.data.redis.core.RedisTemplate;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
+import org.springframework.web.context.request.RequestContextHolder;
|
|
|
+import org.springframework.web.context.request.ServletRequestAttributes;
|
|
|
+
|
|
|
+import java.lang.reflect.Method;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+
|
|
|
+@Slf4j
|
|
|
+@Aspect
|
|
|
+@Component
|
|
|
+@RequiredArgsConstructor
|
|
|
+public class CurrentLimitingAspect {
|
|
|
+
|
|
|
+ private final RedisTemplate redisTemplate;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 带有注解的方法之前执行
|
|
|
+ */
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ @Before("@annotation(currentLimiting)")
|
|
|
+ public void doBefore(JoinPoint point, CurrentLimiting currentLimiting) throws Throwable {
|
|
|
+ int time = currentLimiting.time();
|
|
|
+ int count = currentLimiting.count();
|
|
|
+ // 将接口方法和用户IP构建Redis的key
|
|
|
+ String key = getCurrentLimitingKey(currentLimiting.key(), point);
|
|
|
+ // 未达到限流次数,自增
|
|
|
+ long value = redisTemplate.opsForValue().increment(key, 1);
|
|
|
+
|
|
|
+ if (value > count) {
|
|
|
+ log.error("接口限流,key:{},count:{},currentCount:{}", key, count, value);
|
|
|
+ throw new RuntimeException("访问过于频繁,请稍后再试!");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 第一次请求设置过期时间
|
|
|
+ if(value == 1){
|
|
|
+ redisTemplate.expire(key, time, TimeUnit.SECONDS);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 组装 redis 的 key
|
|
|
+ */
|
|
|
+ private String getCurrentLimitingKey(String prefixKey,JoinPoint point) {
|
|
|
+ StringBuilder sb = new StringBuilder(prefixKey);
|
|
|
+ ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
|
|
+ HttpServletRequest request = attributes.getRequest();
|
|
|
+// sb.append( Utils.getIpAddress(request) );
|
|
|
+
|
|
|
+ MethodSignature signature = (MethodSignature) point.getSignature();
|
|
|
+ Method method = signature.getMethod();
|
|
|
+ Class<?> targetClass = method.getDeclaringClass();
|
|
|
+ return sb.append("_")
|
|
|
+// .append( targetClass.getName() )
|
|
|
+ .append("_").append(method.getName()).toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取ip地址
|
|
|
+ * @param request
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private String getIpAddress(HttpServletRequest request) {
|
|
|
+ // 从请求头或代理头中获取真实IP地址
|
|
|
+ String ipAddress = request.getHeader("X-Forwarded-For");
|
|
|
+ if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
|
|
|
+ ipAddress = request.getHeader("Proxy-Client-IP");
|
|
|
+ }
|
|
|
+ if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
|
|
|
+ ipAddress = request.getHeader("WL-Proxy-Client-IP");
|
|
|
+ }
|
|
|
+ if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
|
|
|
+ ipAddress = request.getRemoteAddr();
|
|
|
+ }
|
|
|
+ return ipAddress;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|