Browse Source

增加重复性校验

master
xsx 1 year ago
parent
commit
6749e15e9d
  1. 31
      im-platform/src/main/java/com/bx/implatform/annotation/RepeatSubmit.java
  2. 100
      im-platform/src/main/java/com/bx/implatform/aspect/RepeatSubmitAspect.java
  3. 5
      im-platform/src/main/java/com/bx/implatform/contant/RedisKey.java
  4. 2
      im-platform/src/main/java/com/bx/implatform/controller/FriendController.java
  5. 2
      im-platform/src/main/java/com/bx/implatform/controller/GroupController.java
  6. 2
      im-platform/src/main/java/com/bx/implatform/controller/LoginController.java

31
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
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;
}
}

5
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
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
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
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) {

Loading…
Cancel
Save