xsx 1 год назад
Родитель
Сommit
6749e15e9d

+ 31 - 0
im-platform/src/main/java/com/bx/implatform/annotation/RepeatSubmit.java

@@ -0,0 +1,31 @@
+package com.bx.implatform.annotation;
+
+import java.lang.annotation.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ *  防止表单重复提交注解
+ */
+@Inherited
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RepeatSubmit {
+
+
+    /**
+     * 间隔时间,小于此时间视为重复提交
+     */
+    int interval() default 5000;
+
+    /**
+     * 间隔时间单位
+     */
+    TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
+
+    /**
+     * 提示消息
+     */
+    String message() default "请勿提交重复请求";
+
+}

+ 100 - 0
im-platform/src/main/java/com/bx/implatform/aspect/RepeatSubmitAspect.java

@@ -0,0 +1,100 @@
+package com.bx.implatform.aspect;
+
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.crypto.SecureUtil;
+import com.alibaba.fastjson.JSON;
+import com.bx.implatform.annotation.RepeatSubmit;
+import com.bx.implatform.contant.RedisKey;
+import com.bx.implatform.exception.GlobalException;
+import com.bx.implatform.session.SessionContext;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.AllArgsConstructor;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+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 org.springframework.web.multipart.MultipartFile;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.StringJoiner;
+
+/**
+ * @author: blue
+ * @date: 2024-12-08
+ * @version: 1.0
+ */
+
+@Aspect
+@Component
+@AllArgsConstructor
+public class RepeatSubmitAspect {
+
+    private final RedisTemplate<String, Object> redisTemplate;
+
+    @Before("@annotation(repeatSubmit)")
+    public void doBefore(JoinPoint point, RepeatSubmit repeatSubmit) throws Throwable {
+        // 如果注解不为0 则使用注解数值
+        long interval = repeatSubmit.timeUnit().toMillis(repeatSubmit.interval());
+        HttpServletRequest request =
+            ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
+        String url = request.getRequestURL().toString();
+        Long userId = SessionContext.getSession().getUserId();
+        String reqParams = argsArrayToString(point.getArgs());
+        String md5 = SecureUtil.md5(StrUtil.join(":", userId, url, reqParams));
+        // 唯一标识
+        String key = String.join(":",RedisKey.IM_REPEAT_SUBMIT,md5) ;
+        if(redisTemplate.hasKey(key)){
+            throw new GlobalException(repeatSubmit.message());
+        }
+        redisTemplate.opsForValue().set(key,1,repeatSubmit.interval(),repeatSubmit.timeUnit());
+    }
+
+
+    /**
+     * 参数拼装
+     */
+    private String argsArrayToString(Object[] paramsArray) {
+        StringJoiner params = new StringJoiner(" ");
+        if (ArrayUtil.isEmpty(paramsArray)) {
+            return params.toString();
+        }
+        for (Object o : paramsArray) {
+            if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) {
+                params.add(JSON.toJSONString(o));
+            }
+        }
+        return params.toString();
+    }
+
+    /**
+     * 判断是否需要过滤的对象。
+     *
+     * @param o 对象信息。
+     * @return 如果是需要过滤的对象,则返回true;否则返回false。
+     */
+    @SuppressWarnings("rawtypes")
+    public boolean isFilterObject(final Object o) {
+        Class<?> clazz = o.getClass();
+        if (clazz.isArray()) {
+            return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
+        } else if (Collection.class.isAssignableFrom(clazz)) {
+            Collection collection = (Collection)o;
+            for (Object value : collection) {
+                return value instanceof MultipartFile;
+            }
+        } else if (Map.class.isAssignableFrom(clazz)) {
+            Map map = (Map)o;
+            for (Object value : map.values()) {
+                return value instanceof MultipartFile;
+            }
+        }
+        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse;
+    }
+}

+ 3 - 2
im-platform/src/main/java/com/bx/implatform/contant/RedisKey.java

@@ -47,9 +47,10 @@ public final class RedisKey {
      * 缓存群聊成员id
      */
     public static final String IM_CACHE_GROUP_MEMBER_ID = "im:cache:group_member_ids";
+
     /**
-     * 分布式锁前缀
+     * 重复提交
      */
-    public static final String IM_LOCK_RTC_GROUP =  "im:lock:rtc:group";
+    public static final String IM_REPEAT_SUBMIT = "im:repeat:submit";
 
 }

+ 2 - 0
im-platform/src/main/java/com/bx/implatform/controller/FriendController.java

@@ -1,5 +1,6 @@
 package com.bx.implatform.controller;
 
+import com.bx.implatform.annotation.RepeatSubmit;
 import com.bx.implatform.entity.Friend;
 import com.bx.implatform.result.Result;
 import com.bx.implatform.result.ResultUtils;
@@ -39,6 +40,7 @@ public class FriendController {
     }
 
 
+    @RepeatSubmit
     @PostMapping("/add")
     @Operation(summary = "添加好友", description = "双方建立好友关系")
     public Result addFriend(@NotNull(message = "好友id不可为空") @RequestParam Long friendId) {

+ 2 - 0
im-platform/src/main/java/com/bx/implatform/controller/GroupController.java

@@ -1,5 +1,6 @@
 package com.bx.implatform.controller;
 
+import com.bx.implatform.annotation.RepeatSubmit;
 import com.bx.implatform.result.Result;
 import com.bx.implatform.result.ResultUtils;
 import com.bx.implatform.service.GroupService;
@@ -23,6 +24,7 @@ public class GroupController {
 
     private final GroupService groupService;
 
+    @RepeatSubmit
     @Operation(summary = "创建群聊", description = "创建群聊")
     @PostMapping("/create")
     public Result<GroupVO> createGroup(@Valid @RequestBody GroupVO vo) {

+ 2 - 0
im-platform/src/main/java/com/bx/implatform/controller/LoginController.java

@@ -1,5 +1,6 @@
 package com.bx.implatform.controller;
 
+import com.bx.implatform.annotation.RepeatSubmit;
 import com.bx.implatform.dto.LoginDTO;
 import com.bx.implatform.dto.ModifyPwdDTO;
 import com.bx.implatform.dto.RegisterDTO;
@@ -34,6 +35,7 @@ public class LoginController {
         return ResultUtils.success(vo);
     }
 
+    @RepeatSubmit
     @PostMapping("/register")
     @Operation(summary = "用户注册", description = "用户注册")
     public Result register(@Valid @RequestBody RegisterDTO dto) {