This commit is contained in:
2025-08-12 17:03:11 +08:00
parent bc165f5d60
commit 61ed9f0154
24 changed files with 742 additions and 19 deletions

View File

@ -36,4 +36,7 @@ public interface GlobalConstants {
* 三方认证 redis key
*/
String SOCIAL_AUTH_CODE_KEY = GLOBAL_REDIS_KEY + "social_auth_codes:";
String FUNCTION_ACCESS_KEY = GLOBAL_REDIS_KEY + "device:function_access:";
}

View File

@ -0,0 +1,11 @@
package com.fuyuanshen.common.ratelimiter.annotation;// DeviceRedisKeyAnnotation.java
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 FunctionAccessAnnotation {
String value() default "";
}

View File

@ -0,0 +1,11 @@
package com.fuyuanshen.common.ratelimiter.annotation;// DeviceRedisKeyAnnotation.java
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 FunctionAccessBatcAnnotation {
String value() default "";
}

View File

@ -0,0 +1,103 @@
package com.fuyuanshen.common.ratelimiter.aspectj;// DeviceRedisKeyAspect.java
import com.fuyuanshen.common.core.exception.ServiceException;
import com.fuyuanshen.common.core.utils.StringUtils;
import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessAnnotation;
import com.fuyuanshen.common.redis.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import java.time.Duration;
import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY;
@Slf4j
@Aspect
@Component
public class FunctionAccessAspect {
// 定义切点拦截带有DeviceRedisKeyAnnotation注解的方法
@Around("@annotation(functionAccessAnnotation)")
public Object addDeviceRedisKey(ProceedingJoinPoint joinPoint, FunctionAccessAnnotation functionAccessAnnotation) throws Throwable {
Object result;
String deviceImei = null;
// 获取方法参数查找设备ID
Object[] args = joinPoint.getArgs();
deviceImei = extractDeviceImei(args);
if (StringUtils.isNotBlank(deviceImei)) {
// 生成全局Redis key
String redisKey = generateDeviceRedisKey(deviceImei);
String cacheKey = RedisUtils.getCacheObject(redisKey);
if(StringUtils.isNotBlank(cacheKey) && "ACTIVE".equals(cacheKey)){
throw new ServiceException("设备已存在访问限制,请稍后再试", 500);
}
// 存储到Redis中设置过期时间
RedisUtils.setCacheObject(redisKey, "ACTIVE", Duration.ofMinutes(30));
log.info("设备Redis key已添加: {}", redisKey);
}
// 执行原方法
result = joinPoint.proceed();
return result;
}
/**
* 从方法参数中提取设备ID
*/
private String extractDeviceImei(Object[] args) {
if (args == null || args.length == 0) {
return null;
}
for (Object arg : args) {
if (arg == null) continue;
// 如果参数本身就是设备ID (Long类型)
if (arg instanceof Long) {
return arg.toString();
}
// 如果参数是对象尝试获取deviceId字段
try {
// 使用反射获取deviceId字段
java.lang.reflect.Field[] fields = arg.getClass().getDeclaredFields();
for (java.lang.reflect.Field field : fields) {
if ("deviceImei".equalsIgnoreCase(field.getName()) ||
"device_imei".equalsIgnoreCase(field.getName())) {
field.setAccessible(true);
Object value = field.get(arg);
if (value != null) {
return value.toString();
}
}
}
// 尝试获取getId方法
try {
java.lang.reflect.Method getIdMethod = arg.getClass().getMethod("getDeviceImei");
Object value = getIdMethod.invoke(arg);
if (value != null) {
return value.toString();
}
} catch (Exception ignored) {}
} catch (Exception e) {
log.debug("从参数中提取设备ID时出错: {}", e.getMessage());
}
}
return null;
}
/**
* 生成设备的全局Redis key
*/
private String generateDeviceRedisKey(String deviceImei) {
return FUNCTION_ACCESS_KEY + deviceImei;
}
}

View File

@ -0,0 +1,184 @@
package com.fuyuanshen.common.ratelimiter.aspectj;// DeviceRedisKeyAspect.java
import cn.hutool.json.JSON;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.fuyuanshen.common.core.exception.ServiceException;
import com.fuyuanshen.common.core.utils.StringUtils;
import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessAnnotation;
import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessBatcAnnotation;
import com.fuyuanshen.common.redis.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY;
@Slf4j
@Aspect
@Component
public class FunctionAccessBatchAspect {
// 定义切点拦截带有DeviceRedisKeyAnnotation注解的方法
@Around("@annotation(functionAccessBatchAspect)")
public Object addDeviceRedisKey(ProceedingJoinPoint joinPoint, FunctionAccessBatcAnnotation functionAccessBatchAspect) throws Throwable {
Object result;
String batchId = null;
List<String> deviceImeiList = null;
// 获取方法参数查找设备ID
Object[] args = joinPoint.getArgs();
batchId = extractDeviceBatchId(args);
deviceImeiList = extractDeviceImeiList(args);
if (StringUtils.isNotBlank(batchId)) {
// 生成全局Redis key
String redisKey = generateDeviceRedisKey(batchId);
String cacheKey = RedisUtils.getCacheObject(redisKey);
if(StringUtils.isNotBlank(cacheKey) && "ACTIVE".equals(cacheKey)){
throw new ServiceException("设备已存在访问限制,请稍后再试", 500);
}
// 存储到Redis中设置过期时间
RedisUtils.setCacheObject(redisKey, JSONUtil.toJsonStr(deviceImeiList), Duration.ofMinutes(30));
log.info("设备Redis key已添加: {}", redisKey);
}
// 执行原方法
result = joinPoint.proceed();
return result;
}
/**
* 从方法参数中提取设备IMEI列表
*/
private List<String> extractDeviceImeiList(Object[] args) {
if (args == null || args.length == 0) {
return null;
}
for (Object arg : args) {
if (arg == null) continue;
// 如果参数本身就是List<String>类型
if (arg instanceof List) {
List<?> list = (List<?>) arg;
if (!list.isEmpty() && list.get(0) instanceof String) {
// 检查是否为deviceImeiList
return (List<String>) list;
}
}
// 如果参数是对象尝试获取deviceImeiList字段
try {
// 使用反射获取deviceImeiList字段
java.lang.reflect.Field[] fields = arg.getClass().getDeclaredFields();
for (java.lang.reflect.Field field : fields) {
if ("deviceImeiList".equalsIgnoreCase(field.getName()) ||
"device_imei_list".equalsIgnoreCase(field.getName()) ||
"deviceImeis".equalsIgnoreCase(field.getName()) ||
"device_imeis".equalsIgnoreCase(field.getName())) {
field.setAccessible(true);
Object value = field.get(arg);
if (value instanceof List) {
List<?> list = (List<?>) value;
if (!list.isEmpty() && list.get(0) instanceof String) {
return (List<String>) list;
}
}
}
}
// 尝试获取getDeviceImeiList方法
try {
java.lang.reflect.Method getDeviceImeiListMethod = arg.getClass().getMethod("getDeviceImeiList");
Object value = getDeviceImeiListMethod.invoke(arg);
if (value instanceof List) {
List<?> list = (List<?>) value;
if (!list.isEmpty() && list.get(0) instanceof String) {
return (List<String>) list;
}
}
} catch (Exception ignored) {}
// 尝试获取getDeviceImeis方法
try {
java.lang.reflect.Method getDeviceImeisMethod = arg.getClass().getMethod("getDeviceImeis");
Object value = getDeviceImeisMethod.invoke(arg);
if (value instanceof List) {
List<?> list = (List<?>) value;
if (!list.isEmpty() && list.get(0) instanceof String) {
return (List<String>) list;
}
}
} catch (Exception ignored) {}
} catch (Exception e) {
log.debug("从参数中提取设备IMEI列表时出错: {}", e.getMessage());
}
}
return null;
}
/**
* 从方法参数中提取设备ID
*/
private String extractDeviceBatchId(Object[] args) {
if (args == null || args.length == 0) {
return null;
}
for (Object arg : args) {
if (arg == null) continue;
// 如果参数本身就是设备ID (Long类型)
if (arg instanceof Long) {
return arg.toString();
}
// 如果参数是对象尝试获取deviceId字段
try {
// 使用反射获取deviceId字段
java.lang.reflect.Field[] fields = arg.getClass().getDeclaredFields();
for (java.lang.reflect.Field field : fields) {
if ("batchId".equalsIgnoreCase(field.getName()) ||
"batch_id".equalsIgnoreCase(field.getName())) {
field.setAccessible(true);
Object value = field.get(arg);
if (value != null) {
return value.toString();
}
}
}
// 尝试获取getId方法
try {
java.lang.reflect.Method getIdMethod = arg.getClass().getMethod("batchId");
Object value = getIdMethod.invoke(arg);
if (value != null) {
return value.toString();
}
} catch (Exception ignored) {}
} catch (Exception e) {
log.debug("从参数中提取批次号时出错: {}", e.getMessage());
}
}
return null;
}
/**
* 生成设备的全局Redis key
*/
private String generateDeviceRedisKey(String batchId) {
return FUNCTION_ACCESS_KEY + batchId;
}
}