注解定义
import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;
@Target(value = {ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RejectRepeatedSubmit {
long duration() default 500;
TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
int retryTimes() default 0;
int lockType() default 0;
}
AOP切面定义
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
@Log4j2
@Component
@Aspect
public class RejectRepeatedSubmitAspect {
@Autowired
private SimpleRedisLockUtil simpleRedisLockUtil;
@Pointcut("@annotation(com.yunti.wanmo.annotation.RejectRepeatedSubmit)")
public void pointCut() {
}
@Around("pointCut()")
public Object invoke(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
String simpleName = signature.getDeclaringType().getName().replace(".", ":");
String methodName = simpleName + ":" + method.getName();
RejectRepeatedSubmit annotation = method.getAnnotation(RejectRepeatedSubmit.class);
String keyPrefix = RedisConstant.genKey(RedisConstant.NAMESPACE_WANMO, RedisConstant.TYPE_STRING, RedisBizConstant.REJECT_REPEATED_SUBMIT_PREFIX);
String uniqueKey = keyPrefix + getUniqueKey(point.getArgs(), annotation, methodName);
boolean lock = false;
try {
for (int retry = annotation.retryTimes() + 1; retry > 0; --retry) {
lock = this.simpleRedisLockUtil.lock(uniqueKey, annotation.timeUnit().toMillis(annotation.duration()));
if (lock) {
break;
}
}
if (lock) {
return point.proceed();
}
throw new BizException("操作频繁,请稍后再试...");
} finally {
if (lock && Objects.equals(0, annotation.lockType())) {
simpleRedisLockUtil.unLock(uniqueKey);
}
}
}
private String getUniqueKey(Object[] args, RejectRepeatedSubmit annotation, String methodName) {
StringBuilder uniqueKey = new StringBuilder(methodName);
if (args.length > 0) {
for (Object arg : args) {
Class<?> paramClass = null;
if (Objects.nonNull(arg)) {
paramClass = arg.getClass();
}
String processedParam = null;
try {
processedParam = processParams(arg, paramClass, true);
} catch (Exception e) {
log.error("参数处理异常", e);
}
if (Objects.nonNull(processedParam)) {
uniqueKey.append("@");
uniqueKey.append(processedParam);
}
}
}
return uniqueKey.toString();
}
private <P> String processParams(Object param, Class<P> paramClass, boolean isContinue) {
String uniqueKey;
if (Objects.isNull(param)) {
uniqueKey = "null";
} else if (param instanceof LoginDTO) {
uniqueKey = ((LoginDTO) param).getUserId().toString();
} else if (paramClass.isPrimitive()) {
uniqueKey = String.valueOf(param);
} else if (param instanceof String) {
uniqueKey = (String) param;
} else if (param instanceof Number) {
uniqueKey = String.valueOf(param);
} else {
if (!paramClass.getName().contains("com.yunti")) {
return null;
}
if (isContinue) {
StringBuilder obj = new StringBuilder();
Field[] fields = param.getClass().getDeclaredFields();
for (int i = 0, size = fields.length; i < size; i++) {
if (i > 0) {
obj.append("@");
}
try {
fields[i].setAccessible(true);
Object value = fields[i].get(param);
String objParam = processParams(value, value.getClass(), false);
if (Objects.nonNull(objParam)) {
obj.append(objParam);
}
} catch (IllegalAccessException e) {
log.error("参数处理异常", e);
}
}
return obj.toString();
} else {
String jsonString = JSON.toJSONString(param);
uniqueKey = DigestUtils.md5DigestAsHex(jsonString.getBytes());
}
}
return uniqueKey;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程