diff --git a/接口防抖防重复提交/woniu-springboot-interface-demo-master/pom.xml b/接口防抖防重复提交/woniu-springboot-interface-demo-master/pom.xml
index 071937b..bc3d89d 100644
--- a/接口防抖防重复提交/woniu-springboot-interface-demo-master/pom.xml
+++ b/接口防抖防重复提交/woniu-springboot-interface-demo-master/pom.xml
@@ -23,6 +23,12 @@
spring-boot-starter-web
+
+ org.redisson
+ redisson-spring-boot-starter
+ 3.10.6
+
+
mysql
diff --git a/接口防抖防重复提交/woniu-springboot-interface-demo-master/src/main/java/com/woniu/demo/config/RedissonConfig.java b/接口防抖防重复提交/woniu-springboot-interface-demo-master/src/main/java/com/woniu/demo/config/RedissonConfig.java
new file mode 100644
index 0000000..3d9993d
--- /dev/null
+++ b/接口防抖防重复提交/woniu-springboot-interface-demo-master/src/main/java/com/woniu/demo/config/RedissonConfig.java
@@ -0,0 +1,22 @@
+package com.woniu.demo.config;
+
+import org.redisson.Redisson;
+import org.redisson.api.RedissonClient;
+import org.redisson.config.Config;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class RedissonConfig {
+
+ @Bean
+ public RedissonClient redissonClient() {
+ Config config = new Config();
+ // 这里假设你使用单节点的Redis服务器
+ config.useSingleServer()
+ // 使用与Spring Data Redis相同的地址
+ .setAddress("redis://127.0.0.1:6379");
+ return Redisson.create(config);
+ }
+}
+
diff --git a/接口防抖防重复提交/woniu-springboot-interface-demo-master/src/main/java/com/woniu/demo/redisson/RedissonRequestLockAspect.java b/接口防抖防重复提交/woniu-springboot-interface-demo-master/src/main/java/com/woniu/demo/redisson/RedissonRequestLockAspect.java
new file mode 100644
index 0000000..aa102da
--- /dev/null
+++ b/接口防抖防重复提交/woniu-springboot-interface-demo-master/src/main/java/com/woniu/demo/redisson/RedissonRequestLockAspect.java
@@ -0,0 +1,126 @@
+package com.woniu.demo.redisson;
+
+import com.woniu.demo.annotation.RequestKeyParam;
+import com.woniu.demo.annotation.RequestLock;
+import com.woniu.demo.exception.biz.BizException;
+import com.woniu.demo.model.response.ResponseCodeEnum;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.Order;
+import org.springframework.util.ReflectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+
+/**
+ * 接口优化,如何接口防抖(防重复提交)?
+ * 分布式锁实现方案!
+ * @description
+ */
+@Aspect
+@Configuration
+@Order(2)
+public class RedissonRequestLockAspect {
+
+ private RedissonClient redissonClient;
+
+ @Autowired
+ public RedissonRequestLockAspect(RedissonClient redissonClient) {
+ this.redissonClient = redissonClient;
+ }
+
+ @Around("execution(public * * (..)) && @annotation(com.summo.demo.config.requestlock.RequestLock)")
+ public Object interceptor(ProceedingJoinPoint joinPoint) {
+ MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
+ Method method = methodSignature.getMethod();
+ RequestLock requestLock = method.getAnnotation(RequestLock.class);
+ if (StringUtils.isEmpty(requestLock.prefix())) {
+ throw new BizException(ResponseCodeEnum.BIZ_CHECK_FAIL, "重复提交前缀不能为空");
+ }
+ //获取自定义key
+ final String lockKey = getLockKey(joinPoint);
+ // 使用Redisson分布式锁的方式判断是否重复提交
+ RLock lock = redissonClient.getLock(lockKey);
+ boolean isLocked = false;
+ try {
+ //尝试抢占锁
+ isLocked = lock.tryLock();
+ //没有拿到锁说明已经有了请求了
+ if (!isLocked) {
+ throw new BizException(ResponseCodeEnum.BIZ_CHECK_FAIL, "您的操作太快了,请稍后重试");
+ }
+ //拿到锁后设置过期时间
+ lock.lock(requestLock.expire(), requestLock.timeUnit());
+ try {
+ return joinPoint.proceed();
+ } catch (Throwable throwable) {
+ throw new BizException(ResponseCodeEnum.BIZ_CHECK_FAIL, "系统异常");
+ }
+ } catch (Exception e) {
+ throw new BizException(ResponseCodeEnum.BIZ_CHECK_FAIL, "您的操作太快了,请稍后重试");
+ } finally {
+ //释放锁
+ if (isLocked && lock.isHeldByCurrentThread()) {
+ lock.unlock();
+ }
+ }
+
+ }
+
+ public String getLockKey(ProceedingJoinPoint joinPoint) {
+ //获取连接点的方法签名对象
+ MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
+ //Method对象
+ Method method = methodSignature.getMethod();
+ //获取Method对象上的注解对象
+ RequestLock requestLock = method.getAnnotation(RequestLock.class);
+ //获取方法参数
+ final Object[] args = joinPoint.getArgs();
+ //获取Method对象上所有的注解
+ final Parameter[] parameters = method.getParameters();
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < parameters.length; i++) {
+ final RequestKeyParam keyParam = parameters[i].getAnnotation(RequestKeyParam.class);
+ //如果属性不是RequestKeyParam注解,则不处理
+ if (keyParam == null) {
+ continue;
+ }
+ //如果属性是RequestKeyParam注解,则拼接 连接符 "& + RequestKeyParam"
+ sb.append(requestLock.delimiter()).append(args[i]);
+ }
+ //如果方法上没有加RequestKeyParam注解
+ if (StringUtils.isEmpty(sb.toString())) {
+ //获取方法上的多个注解(为什么是两层数组:因为第二层数组是只有一个元素的数组)
+ final Annotation[][] parameterAnnotations = method.getParameterAnnotations();
+ //循环注解
+ for (int i = 0; i < parameterAnnotations.length; i++) {
+ final Object object = args[i];
+ //获取注解类中所有的属性字段
+ final Field[] fields = object.getClass().getDeclaredFields();
+ for (Field field : fields) {
+ //判断字段上是否有RequestKeyParam注解
+ final RequestKeyParam annotation = field.getAnnotation(RequestKeyParam.class);
+ //如果没有,跳过
+ if (annotation == null) {
+ continue;
+ }
+ //如果有,设置Accessible为true(为true时可以使用反射访问私有变量,否则不能访问私有变量)
+ field.setAccessible(true);
+ //如果属性是RequestKeyParam注解,则拼接 连接符" & + RequestKeyParam"
+ sb.append(requestLock.delimiter()).append(ReflectionUtils.getField(field, object));
+ }
+ }
+ }
+ //返回指定前缀的key
+ return requestLock.prefix() + sb;
+ }
+}