Просмотр исходного кода

Merge remote-tracking branch 'origin/dev' into dev

xucaiqin 2 лет назад
Родитель
Сommit
209f2e95b1

+ 26 - 0
sckw-common/sckw-common-core/src/main/java/com/sckw/core/annotation/RepeatSubmit.java

@@ -0,0 +1,26 @@
+package com.sckw.core.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * @author czh
+ * @desc 重复请求校验
+ * @date 2023/9/1
+ */
+@Inherited
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RepeatSubmit {
+
+    /**
+     * 间隔时间(ms),小于此时间视为重复提交
+     */
+    long interval() default 5000;
+
+    /**
+     * 提示消息
+     */
+    String message() default "请求频率限制,请稍候再试";
+
+}

+ 72 - 0
sckw-common/sckw-common-core/src/main/java/com/sckw/core/aspect/NoRepeatSubmitAspect.java

@@ -0,0 +1,72 @@
+package com.sckw.core.aspect;
+
+import com.sckw.core.annotation.RepeatSubmit;
+import com.sckw.core.exception.SystemException;
+import com.sckw.core.model.constant.Global;
+import com.sckw.core.model.page.PageRes;
+import com.sckw.core.utils.EncryUtil;
+import com.sckw.core.utils.NumberUtils;
+import com.sckw.core.utils.StringUtils;
+import com.sckw.redis.utils.RedissonUtils;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.IOUtils;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author czh
+ * @desc TODO
+ * @date 2023/9/1
+ */
+@Aspect
+@Slf4j
+public class NoRepeatSubmitAspect {
+
+    @Around("@annotation(com.sckw.core.annotation.RepeatSubmit)")
+    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
+        // 获取request
+        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
+        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
+        HttpServletRequest request = servletRequestAttributes.getRequest();
+        String requestURI = request.getRequestURI();
+        String token = request.getHeader(Global.ACCESS_TOKEN);
+        Map<String, Object> tokenMap = EncryUtil.descryV2(Global.PRI_KEY, token);
+        Long userId = NumberUtils.parseLong(tokenMap.get("userId"));
+        String key = Global.getRepeatSubmitKey(userId, requestURI);
+        String string = RedissonUtils.getString(key);
+        MethodSignature signature = (MethodSignature) pjp.getSignature();
+        Method method = signature.getMethod();
+        RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
+        long interval = annotation.interval();
+        if (StringUtils.isNotBlank(string)) {
+            if (System.currentTimeMillis() - Long.parseLong(string) < interval) {
+                throw new SystemException(annotation.message());
+            }
+            return pjp.proceed();
+        }
+
+        RedissonUtils.putString(key, String.valueOf(System.currentTimeMillis()), interval, TimeUnit.MILLISECONDS);
+        return pjp.proceed();
+    }
+}

+ 134 - 39
sckw-common/sckw-common-core/src/main/java/com/sckw/core/filter/RequestCheckInterceptor.java

@@ -1,39 +1,134 @@
-package com.sckw.core.filter;
-
-import com.sckw.core.model.auth.context.LoginEnterpriseHolder;
-import com.sckw.core.web.context.LoginUserHolder;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-import org.springframework.lang.Nullable;
-import org.springframework.web.servlet.HandlerInterceptor;
-
-/**
- * @desc 拦截器
- * @author zk
- * @date 2023/8/18
- */
-public class RequestCheckInterceptor implements HandlerInterceptor {
-
-    /**
-     * @desc 请求处理之前执行
-     * @author zk
-     * @date 2023/8/18
-     **/
-    @Override
-    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
-
-        return true;
-    }
-
-
-    /**
-     * @desc preHandle成功后执行
-     * @author zk
-     * @date 2023/8/18
-     **/
-    @Override
-    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
-        LoginUserHolder.remove();
-        LoginEnterpriseHolder.remove();
-    }
-}
+//package com.sckw.core.filter;
+//
+//import com.sckw.core.annotation.RepeatSubmit;
+//import com.sckw.core.model.auth.context.LoginEnterpriseHolder;
+//import com.sckw.core.web.context.LoginUserHolder;
+//import jakarta.servlet.http.HttpServletRequest;
+//import jakarta.servlet.http.HttpServletResponse;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.lang.Nullable;
+//import org.springframework.web.method.HandlerMethod;
+//import org.springframework.web.servlet.HandlerInterceptor;
+//
+//import java.lang.reflect.Method;
+//import java.util.Map;
+//
+///**
+// * @author zk
+// * @desc 拦截器
+// * @date 2023/8/18
+// */
+//public class RequestCheckInterceptor implements HandlerInterceptor {
+//
+//    /**
+//     * @desc 请求处理之前执行
+//     * @author zk
+//     * @date 2023/8/18
+//     **/
+//    @Override
+//    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+////        if (handler instanceof HandlerMethod) {
+////            HandlerMethod handlerMethod = (HandlerMethod) handler;
+////            Method method = handlerMethod.getMethod();
+////            //判断是否添加了防重复提交的注解
+////            RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
+////            if (annotation != null) {
+////                //判断该请求是否重复提交
+////                if (isRepeatSubmit(request, annotation)) {
+////                    //封装错误信息,直接返回
+////                    String message = annotation.message();
+////                    return false;
+////                }
+////            }
+////            return true;
+////        } else {
+////            return true;
+////        }
+//    }
+//
+//
+//    /**
+//     * @desc preHandle成功后执行
+//     * @author zk
+//     * @date 2023/8/18
+//     **/
+//    @Override
+//    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
+//        LoginUserHolder.remove();
+//        LoginEnterpriseHolder.remove();
+//    }
+//
+//
+//    public boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation)
+//    {
+//        String nowParams = "";
+//        if (request instanceof RepeatedlyRequestWrapper)
+//        {
+//            RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
+//            nowParams = HttpHelper.getBodyString(repeatedlyRequest);
+//        }
+//        //获取请求参数
+//        // body参数为空,获取Parameter的数据
+//        if (StringUtils.isEmpty(nowParams))
+//        {
+//            nowParams = JSON.toJSONString(request.getParameterMap());
+//        }
+//        Map<String, Object> nowDataMap = new HashMap<String, Object>();
+//        nowDataMap.put(REPEAT_PARAMS, nowParams);
+//        nowDataMap.put(REPEAT_TIME, System.currentTimeMillis());
+//
+//        // 请求地址(作为存进Redis的key值),没有使用url是因为所有请求的前缀都是一样的(http://ip地址:端口号),微服务
+//        项目使用nginx所在服务器的IP地址和端口号,之后再转发到网关。
+//        String url = request.getRequestURI();
+//        // 唯一值(没有消息头则使用请求地址)
+//        String submitKey = StringUtils.trimToEmpty(request.getHeader(header));
+//
+//        // 唯一标识(指定key + url + 消息头) 消息头相当于登录用户的唯一标识,唯一标识主要靠token区分。
+//        String cacheRepeatKey = CacheConstants.REPEAT_SUBMIT_KEY + url + submitKey;
+//        //从Redis获取锁
+//        Object sessionObj = redisCache.getCacheObject(cacheRepeatKey);
+//        if (sessionObj != null)
+//        {
+//            Map<String, Object> sessionMap = (Map<String, Object>) sessionObj;
+//            if (sessionMap.containsKey(url))
+//            {
+//                Map<String, Object> preDataMap = (Map<String, Object>) sessionMap.get(url);
+//                //如果请求地址相同、请求参数相同而且时间间隔小于间隔时间,则视为重复请求,直接返回。
+//                if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap, annotation.interval()))
+//                {
+//                    return true;
+//                }
+//            }
+//        }
+//        //如果不是重复请求则将锁存进Redis中,过期时间为所设定的时间间隔然后返回。
+//        Map<String, Object> cacheMap = new HashMap<String, Object>();
+//        cacheMap.put(url, nowDataMap);
+//        redisCache.setCacheObject(cacheRepeatKey, cacheMap, annotation.interval(), TimeUnit.MILLISECONDS);
+//        return false;
+//    }
+//
+//    /**
+//     * 判断参数是否相同
+//     */
+//    private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap)
+//    {
+//        String nowParams = (String) nowMap.get(REPEAT_PARAMS);
+//        String preParams = (String) preMap.get(REPEAT_PARAMS);
+//        return nowParams.equals(preParams);
+//    }
+//
+//    /**
+//     * 判断两次间隔时间
+//     */
+//    private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap, int interval)
+//    {
+//        long time1 = (Long) nowMap.get(REPEAT_TIME);
+//        long time2 = (Long) preMap.get(REPEAT_TIME);
+//        if ((time1 - time2) < interval)
+//        {
+//            return true;
+//        }
+//        return false;
+//    }
+//
+//}

+ 10 - 0
sckw-common/sckw-common-core/src/main/java/com/sckw/core/model/constant/Global.java

@@ -65,6 +65,8 @@ public class Global {
     public static final int NUMERICAL_ONE = 1;
     public static final int NUMERICAL_TWO = 2;
     public static final int NUMERICAL_THREE = 3;
+    public static final int NUMERICAL_FOUR = 4;
+    public static final int NUMERICAL_EIGHT = 8;
     public static final int NUMERICAL_TWELVE = 12;
     public static final int NUMERICAL_SIXTEEN = 16;
 
@@ -83,6 +85,9 @@ public class Global {
     /**忘记密码获取验证码*/
     public static final String FORGET_SMS = "forget:";
 
+    /**忘记密码获取验证码*/
+    public static final String REPEAT_SUBMIT = "repeatSubmit:";
+
     /**用户登录验证码*/
     public static final String USER_LOGIN_CAPTCHA = "userLoginCaptcha:";
 
@@ -289,4 +294,9 @@ public class Global {
     public static String getForgetKey(Integer systemType, String account) {
         return FORGET_SMS + systemType + COLON + account;
     }
+
+    /**完整的校验重复请求key*/
+    public static String getRepeatSubmitKey(Long userId, String url) {
+        return REPEAT_SUBMIT + userId + COLON + url;
+    }
 }

+ 1 - 0
sckw-common/sckw-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

@@ -1,4 +1,5 @@
 com.sckw.core.aspect.DaoAspect
+com.sckw.core.aspect.NoRepeatSubmitAspect
 com.sckw.core.exception.GlobalSystemExceptionHandler
 com.sckw.core.web.config.CustomConfig
 #com.sckw.core.filter.LoginFilter

+ 12 - 0
sckw-common/sckw-common-redis/src/main/java/com/sckw/redis/utils/RedissonUtils.java

@@ -135,6 +135,18 @@ public class RedissonUtils {
         log.debug("添加缓存【{}】 【{}】开始", key, value);
         RBucket<String> bucket = redissonUtils.redissonClient.getBucket(key, StringCodec.INSTANCE);
         bucket.set(value, expired <= 0 ? DEFAULT_EXPIRED : expired, TimeUnit.SECONDS);
+
+    }
+    /**
+     * 以string的方式设置缓存
+     *
+     * @param key
+     * @param value
+     */
+    public static void putString(String key, String value, long expired, TimeUnit timeUnit) {
+        log.debug("添加缓存【{}】 【{}】开始", key, value);
+        RBucket<String> bucket = redissonUtils.redissonClient.getBucket(key, StringCodec.INSTANCE);
+        bucket.set(value, expired <= 0 ? DEFAULT_EXPIRED : expired, timeUnit);
     }
 
     /**

+ 5 - 2
sckw-modules/sckw-system/src/main/java/com/sckw/system/controller/KwsUserController.java

@@ -2,6 +2,7 @@ package com.sckw.system.controller;
 
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
+import com.sckw.core.annotation.RepeatSubmit;
 import com.sckw.core.exception.SystemException;
 import com.sckw.core.model.page.PageHelperUtil;
 import com.sckw.core.model.page.PageResult;
@@ -20,6 +21,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 
@@ -199,9 +201,10 @@ public class KwsUserController {
         return HttpResult.ok(kwsUserService.test(Arrays.stream(type.split(",")).map(Integer::parseInt).toList()));
     }
 
+    @RepeatSubmit
     @PostMapping("testApprove")
-    public HttpResult testApprove() {
-//        commonService.test();
+    public HttpResult testApprove(@RequestBody ForgetPasswordReqVo reqVo) {
+        kwsUserService.test(Collections.singletonList(1));
         return HttpResult.ok(HttpStatus.MSG_004);
     }
 }

+ 7 - 3
sckw-modules/sckw-system/src/main/java/com/sckw/system/service/KwsUserService.java

@@ -1,15 +1,18 @@
 package com.sckw.system.service;
 
+import com.sckw.core.annotation.RepeatSubmit;
 import com.sckw.core.common.enums.enums.DictEnum;
 import com.sckw.core.exception.SystemException;
 import com.sckw.core.model.constant.Global;
 import com.sckw.core.model.enums.ApprovalEnum;
 import com.sckw.core.model.enums.SystemTypeEnum;
+import com.sckw.core.model.page.PageResult;
 import com.sckw.core.utils.*;
 import com.sckw.core.web.constant.HttpStatus;
 import com.sckw.core.web.context.LoginUserHolder;
 import com.sckw.redis.constant.RedisConstant;
 import com.sckw.redis.utils.RedissonUtils;
+import com.sckw.system.api.RemoteUserService;
 import com.sckw.system.api.model.dto.req.RegisterReqDto;
 import com.sckw.system.api.model.dto.req.UpdatePasswordReqDto;
 import com.sckw.system.api.model.dto.res.AreaTreeFrontResDto;
@@ -64,6 +67,8 @@ public class KwsUserService {
 
     @Autowired
     private RemoteSystemServiceImpl remoteSystemService;
+    @Autowired
+    private RemoteUserService remoteUserService;
 
     @Autowired
     private CommonService commonService;
@@ -606,11 +611,10 @@ public class KwsUserService {
     }
 
     public List<AreaTreeFrontResDto> test(List<Integer> list) {
-        List<SysDictResDto> asdasd = remoteSystemService.queryDictByType("asdasd");
-
+        PageResult pageResult = remoteUserService.queryEntInfoByCityCodeAndEntTypesWithPage(null, Collections.singletonList(1), 1, 10);
 
 
-        return remoteSystemService.queryAreaTreeFrontByCodeList(list);
+        return null;
     }
 
     /**