Browse Source

2022年12月1日18:15:48

纪新园 3 years ago
parent
commit
68cd36830a
33 changed files with 2063 additions and 69 deletions
  1. 6 0
      blade-common/pom.xml
  2. 18 0
      blade-common/src/main/java/org/springblade/common/annotation/RepeatSubmit.java
  3. 138 0
      blade-common/src/main/java/org/springblade/common/constant/Constants.java
  4. 74 0
      blade-common/src/main/java/org/springblade/common/filter/RepeatedlyRequestWrapper.java
  5. 56 0
      blade-common/src/main/java/org/springblade/common/http/HttpHelper.java
  6. 253 0
      blade-common/src/main/java/org/springblade/common/http/HttpUtils.java
  7. 21 0
      blade-service/blade-box-tube/src/main/java/org/springblade/box/tube/Interceptor/RepeatSubmitConfig.java
  8. 145 0
      blade-service/blade-box-tube/src/main/java/org/springblade/box/tube/Interceptor/SubmitInterceptor.java
  9. 3 0
      blade-service/blade-box-tube/src/main/java/org/springblade/box/tube/controller/ArchivesController.java
  10. 3 0
      blade-service/blade-box-tube/src/main/java/org/springblade/box/tube/controller/RepairController.java
  11. 3 0
      blade-service/blade-box-tube/src/main/java/org/springblade/box/tube/controller/TradingBoxController.java
  12. 4 0
      blade-service/blade-box-tube/src/main/java/org/springblade/box/tube/controller/TransportController.java
  13. 21 0
      blade-service/blade-check/src/main/java/org/springblade/check/Interceptor/RepeatSubmitConfig.java
  14. 145 0
      blade-service/blade-check/src/main/java/org/springblade/check/Interceptor/SubmitInterceptor.java
  15. 2 0
      blade-service/blade-check/src/main/java/org/springblade/check/controller/AuditProecessController.java
  16. 21 0
      blade-service/blade-client/src/main/java/org/springblade/client/Interceptor/RepeatSubmitConfig.java
  17. 145 0
      blade-service/blade-client/src/main/java/org/springblade/client/Interceptor/SubmitInterceptor.java
  18. 0 37
      blade-service/blade-client/src/main/java/org/springblade/client/Interceptor/WebSocketInterceptor.java
  19. 0 32
      blade-service/blade-client/src/main/java/org/springblade/client/config/WebSocketAutoConfig.java
  20. 21 0
      blade-service/blade-deliver-goods/src/main/java/org/springblade/deliver/goods/Interceptor/RepeatSubmitConfig.java
  21. 145 0
      blade-service/blade-deliver-goods/src/main/java/org/springblade/deliver/goods/Interceptor/SubmitInterceptor.java
  22. 3 0
      blade-service/blade-deliver-goods/src/main/java/org/springblade/deliver/goods/controller/DeliveryController.java
  23. 21 0
      blade-service/blade-land/src/main/java/org/springblade/land/Interceptor/RepeatSubmitConfig.java
  24. 145 0
      blade-service/blade-land/src/main/java/org/springblade/land/Interceptor/SubmitInterceptor.java
  25. 21 0
      blade-service/blade-purchase-sales/src/main/java/org/springblade/purchase/sales/Interceptor/RepeatSubmitConfig.java
  26. 145 0
      blade-service/blade-purchase-sales/src/main/java/org/springblade/purchase/sales/Interceptor/SubmitInterceptor.java
  27. 21 0
      blade-service/blade-stock/src/main/java/org/springblade/stock/Interceptor/RepeatSubmitConfig.java
  28. 145 0
      blade-service/blade-stock/src/main/java/org/springblade/stock/Interceptor/SubmitInterceptor.java
  29. 21 0
      blade-service/trade-finance/src/main/java/org/springblade/finance/Interceptor/RepeatSubmitConfig.java
  30. 145 0
      blade-service/trade-finance/src/main/java/org/springblade/finance/Interceptor/SubmitInterceptor.java
  31. 21 0
      blade-service/trade-purchase/src/main/java/com/trade/purchase/Interceptor/RepeatSubmitConfig.java
  32. 145 0
      blade-service/trade-purchase/src/main/java/com/trade/purchase/Interceptor/SubmitInterceptor.java
  33. 6 0
      blade-service/trade-purchase/src/main/java/com/trade/purchase/order/controller/WoodHarvestingCloudController.java

+ 6 - 0
blade-common/pom.xml

@@ -17,6 +17,12 @@
     <dependencies>
 
         <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+            <version>1.4</version>
+        </dependency>
+
+        <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>easyexcel</artifactId>
             <version>3.1.1</version>

+ 18 - 0
blade-common/src/main/java/org/springblade/common/annotation/RepeatSubmit.java

@@ -0,0 +1,18 @@
+package org.springblade.common.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 自定义注解防止表单重复提交
+ *
+ * @author
+ *
+ */
+@Inherited
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RepeatSubmit
+{
+
+}

+ 138 - 0
blade-common/src/main/java/org/springblade/common/constant/Constants.java

@@ -0,0 +1,138 @@
+package org.springblade.common.constant;
+
+/**
+ * 通用常量信息
+ *
+ * @author ruoyi
+ */
+public class Constants
+{
+    /**
+     * UTF-8 字符集
+     */
+    public static final String UTF8 = "UTF-8";
+
+    /**
+     * GBK 字符集
+     */
+    public static final String GBK = "GBK";
+
+    /**
+     * http请求
+     */
+    public static final String HTTP = "http://";
+
+    /**
+     * https请求
+     */
+    public static final String HTTPS = "https://";
+
+    /**
+     * 通用成功标识
+     */
+    public static final String SUCCESS = "0";
+
+    /**
+     * 通用失败标识
+     */
+    public static final String FAIL = "1";
+
+    /**
+     * 登录成功
+     */
+    public static final String LOGIN_SUCCESS = "Success";
+
+    /**
+     * 注销
+     */
+    public static final String LOGOUT = "Logout";
+
+    /**
+     * 登录失败
+     */
+    public static final String LOGIN_FAIL = "Error";
+
+    /**
+     * 验证码 redis key
+     */
+    public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
+
+    /**
+     * 登录用户 redis key
+     */
+    public static final String LOGIN_TOKEN_KEY = "login_tokens:";
+
+    /**
+     * 防重提交 redis key
+     */
+    public static final String REPEAT_SUBMIT_KEY = "repeat_submit:";
+
+    /**
+     * 验证码有效期(分钟)
+     */
+    public static final Integer CAPTCHA_EXPIRATION = 2;
+
+    /**
+     * 令牌
+     */
+    public static final String TOKEN = "token";
+
+    /**
+     * 令牌前缀
+     */
+    public static final String TOKEN_PREFIX = "Bearer ";
+
+    /**
+     * 令牌前缀
+     */
+    public static final String LOGIN_USER_KEY = "login_user_key";
+
+    /**
+     * 用户ID
+     */
+    public static final String JWT_USERID = "userid";
+
+    /**
+     * 用户名称
+     */
+    public static final String JWT_USERNAME = "sub";
+
+    /**
+     * 用户头像
+     */
+    public static final String JWT_AVATAR = "avatar";
+
+    /**
+     * 创建时间
+     */
+    public static final String JWT_CREATED = "created";
+
+    /**
+     * 用户权限
+     */
+    public static final String JWT_AUTHORITIES = "authorities";
+
+    /**
+     * 参数管理 cache key
+     */
+    public static final String SYS_CONFIG_KEY = "sys_config:";
+
+    /**
+     * 字典管理 cache key
+     */
+    public static final String SYS_DICT_KEY = "sys_dict:";
+    /**
+     * app版本管理 cache key
+     */
+    public static final String SYS_VERSION_KEY = "sys_version:";
+
+    /**
+     * 资源映射路径 前缀
+     */
+    public static final String RESOURCE_PREFIX = "/profile";
+
+	public static final String REPEAT_PARAMS = "repeatParams";
+
+	public static final String REPEAT_TIME = "repeatTime";
+
+}

+ 74 - 0
blade-common/src/main/java/org/springblade/common/filter/RepeatedlyRequestWrapper.java

@@ -0,0 +1,74 @@
+package org.springblade.common.filter;
+
+
+import org.springblade.common.http.HttpHelper;
+
+import javax.servlet.ReadListener;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+/**
+ * 构建可重复读取inputStream的request
+ *
+ * @author ruoyi
+ */
+public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper
+{
+    private final byte[] body;
+
+    public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException
+    {
+        super(request);
+        request.setCharacterEncoding("UTF-8");
+        response.setCharacterEncoding("UTF-8");
+
+        body = HttpHelper.getBodyString(request).getBytes("UTF-8");
+    }
+
+    @Override
+    public BufferedReader getReader() throws IOException
+    {
+        return new BufferedReader(new InputStreamReader(getInputStream()));
+    }
+
+    @Override
+    public ServletInputStream getInputStream() throws IOException
+    {
+
+        final ByteArrayInputStream bais = new ByteArrayInputStream(body);
+
+        return new ServletInputStream()
+        {
+
+            @Override
+            public int read() throws IOException
+            {
+                return bais.read();
+            }
+
+            @Override
+            public boolean isFinished()
+            {
+                return false;
+            }
+
+            @Override
+            public boolean isReady()
+            {
+                return false;
+            }
+
+            @Override
+            public void setReadListener(ReadListener readListener)
+            {
+
+            }
+        };
+    }
+}

+ 56 - 0
blade-common/src/main/java/org/springblade/common/http/HttpHelper.java

@@ -0,0 +1,56 @@
+package org.springblade.common.http;
+
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.ServletRequest;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.Charset;
+
+/**
+ * 通用http工具封装
+ *
+ * @author ruoyi
+ */
+public class HttpHelper
+{
+    private static final Logger LOGGER = LoggerFactory.getLogger(HttpHelper.class);
+
+    public static String getBodyString(ServletRequest request)
+    {
+        StringBuilder sb = new StringBuilder();
+        BufferedReader reader = null;
+        try (InputStream inputStream = request.getInputStream())
+        {
+            reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
+            String line = "";
+            while ((line = reader.readLine()) != null)
+            {
+                sb.append(line);
+            }
+        }
+        catch (IOException e)
+        {
+            LOGGER.warn("getBodyString出现问题!");
+        }
+        finally
+        {
+            if (reader != null)
+            {
+                try
+                {
+                    reader.close();
+                }
+                catch (IOException e)
+                {
+                    LOGGER.error(ExceptionUtils.getMessage(e));
+                }
+            }
+        }
+        return sb.toString();
+    }
+}

+ 253 - 0
blade-common/src/main/java/org/springblade/common/http/HttpUtils.java

@@ -0,0 +1,253 @@
+package org.springblade.common.http;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.net.ssl.*;
+import java.io.*;
+import java.net.ConnectException;
+import java.net.SocketTimeoutException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.cert.X509Certificate;
+
+/**
+ * 通用http发送方法
+ *
+ * @author ruoyi
+ */
+public class HttpUtils
+{
+    private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
+
+    /**
+     * 向指定 URL 发送GET方法的请求
+     *
+     * @param url 发送请求的 URL
+     * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
+     * @return 所代表远程资源的响应结果
+     */
+    public static String sendGet(String url, String param)
+    {
+        return sendGet(url, param, "UTF-8");
+    }
+
+    /**
+     * 向指定 URL 发送GET方法的请求
+     *
+     * @param url 发送请求的 URL
+     * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
+     * @param contentType 编码类型
+     * @return 所代表远程资源的响应结果
+     */
+    public static String sendGet(String url, String param, String contentType)
+    {
+        StringBuilder result = new StringBuilder();
+        BufferedReader in = null;
+        try
+        {
+            String urlNameString = url + "?" + param;
+            log.info("sendGet - {}", urlNameString);
+            URL realUrl = new URL(urlNameString);
+            URLConnection connection = realUrl.openConnection();
+            connection.setRequestProperty("accept", "*/*");
+            connection.setRequestProperty("connection", "Keep-Alive");
+            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
+            connection.connect();
+            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType));
+            String line;
+            while ((line = in.readLine()) != null)
+            {
+                result.append(line);
+            }
+            log.info("recv - {}", result);
+        }
+        catch (ConnectException e)
+        {
+            log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e);
+        }
+        catch (SocketTimeoutException e)
+        {
+            log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e);
+        }
+        catch (IOException e)
+        {
+            log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e);
+        }
+        catch (Exception e)
+        {
+            log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e);
+        }
+        finally
+        {
+            try
+            {
+                if (in != null)
+                {
+                    in.close();
+                }
+            }
+            catch (Exception ex)
+            {
+                log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
+            }
+        }
+        return result.toString();
+    }
+
+    /**
+     * 向指定 URL 发送POST方法的请求
+     *
+     * @param url 发送请求的 URL
+     * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
+     * @return 所代表远程资源的响应结果
+     */
+    public static String sendPost(String url, String param)
+    {
+        PrintWriter out = null;
+        BufferedReader in = null;
+        StringBuilder result = new StringBuilder();
+        try
+        {
+            String urlNameString = url;
+            log.info("sendPost - {}", urlNameString);
+            URL realUrl = new URL(urlNameString);
+            URLConnection conn = realUrl.openConnection();
+            conn.setRequestProperty("accept", "*/*");
+            conn.setRequestProperty("connection", "Keep-Alive");
+            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
+            conn.setRequestProperty("Accept-Charset", "utf-8");
+            conn.setRequestProperty("contentType", "utf-8");
+            conn.setDoOutput(true);
+            conn.setDoInput(true);
+            out = new PrintWriter(conn.getOutputStream());
+            out.print(param);
+            out.flush();
+            in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
+            String line;
+            while ((line = in.readLine()) != null)
+            {
+                result.append(line);
+            }
+            log.info("recv - {}", result);
+        }
+        catch (ConnectException e)
+        {
+            log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e);
+        }
+        catch (SocketTimeoutException e)
+        {
+            log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e);
+        }
+        catch (IOException e)
+        {
+            log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e);
+        }
+        catch (Exception e)
+        {
+            log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e);
+        }
+        finally
+        {
+            try
+            {
+                if (out != null)
+                {
+                    out.close();
+                }
+                if (in != null)
+                {
+                    in.close();
+                }
+            }
+            catch (IOException ex)
+            {
+                log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
+            }
+        }
+        return result.toString();
+    }
+
+    public static String sendSSLPost(String url, String param)
+    {
+        StringBuilder result = new StringBuilder();
+        String urlNameString = url + "?" + param;
+        try
+        {
+            log.info("sendSSLPost - {}", urlNameString);
+            SSLContext sc = SSLContext.getInstance("SSL");
+            sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom());
+            URL console = new URL(urlNameString);
+            HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
+            conn.setRequestProperty("accept", "*/*");
+            conn.setRequestProperty("connection", "Keep-Alive");
+            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
+            conn.setRequestProperty("Accept-Charset", "utf-8");
+            conn.setRequestProperty("contentType", "utf-8");
+            conn.setDoOutput(true);
+            conn.setDoInput(true);
+
+            conn.setSSLSocketFactory(sc.getSocketFactory());
+            conn.setHostnameVerifier(new TrustAnyHostnameVerifier());
+            conn.connect();
+            InputStream is = conn.getInputStream();
+            BufferedReader br = new BufferedReader(new InputStreamReader(is));
+            String ret = "";
+            while ((ret = br.readLine()) != null)
+            {
+                if (ret != null && !"".equals(ret.trim()))
+                {
+                    result.append(new String(ret.getBytes("ISO-8859-1"), "utf-8"));
+                }
+            }
+            log.info("recv - {}", result);
+            conn.disconnect();
+            br.close();
+        }
+        catch (ConnectException e)
+        {
+            log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + param, e);
+        }
+        catch (SocketTimeoutException e)
+        {
+            log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + param, e);
+        }
+        catch (IOException e)
+        {
+            log.error("调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + param, e);
+        }
+        catch (Exception e)
+        {
+            log.error("调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + param, e);
+        }
+        return result.toString();
+    }
+
+    private static class TrustAnyTrustManager implements X509TrustManager
+    {
+        @Override
+        public void checkClientTrusted(X509Certificate[] chain, String authType)
+        {
+        }
+
+        @Override
+        public void checkServerTrusted(X509Certificate[] chain, String authType)
+        {
+        }
+
+        @Override
+        public X509Certificate[] getAcceptedIssuers()
+        {
+            return new X509Certificate[] {};
+        }
+    }
+
+    private static class TrustAnyHostnameVerifier implements HostnameVerifier
+    {
+        @Override
+        public boolean verify(String hostname, SSLSession session)
+        {
+            return true;
+        }
+    }
+}

+ 21 - 0
blade-service/blade-box-tube/src/main/java/org/springblade/box/tube/Interceptor/RepeatSubmitConfig.java

@@ -0,0 +1,21 @@
+package org.springblade.box.tube.Interceptor;
+
+import lombok.AllArgsConstructor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+@EnableWebMvc
+@AllArgsConstructor
+public class RepeatSubmitConfig implements WebMvcConfigurer {
+
+	private final SubmitInterceptor submitInterceptor;
+
+	@Override
+	public void addInterceptors(InterceptorRegistry registry) {
+		registry.addInterceptor(submitInterceptor).addPathPatterns("/**");
+	}
+}
+

+ 145 - 0
blade-service/blade-box-tube/src/main/java/org/springblade/box/tube/Interceptor/SubmitInterceptor.java

@@ -0,0 +1,145 @@
+package org.springblade.box.tube.Interceptor;
+
+import com.alibaba.cloud.commons.lang.StringUtils;
+import com.alibaba.fastjson.JSONObject;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.formula.functions.T;
+import org.springblade.common.annotation.RepeatSubmit;
+import org.springblade.common.constant.Constants;
+import org.springblade.common.filter.RepeatedlyRequestWrapper;
+import org.springblade.common.http.HttpHelper;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.stereotype.Component;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 防止重复提交拦截器
+ *
+ * @author
+ */
+@Slf4j
+@Component
+@AllArgsConstructor
+public class SubmitInterceptor implements HandlerInterceptor {
+
+	public final RedisTemplate redisTemplate;
+
+	/**
+	 * 间隔时间,单位:秒 默认10秒
+	 *
+	 * 两次相同参数的请求,如果间隔时间大于该参数,系统不会认定为重复提交的数据
+	 */
+
+	@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 (this.isRepeatSubmit(request)) {
+					throw new RuntimeException("操作过于频繁,请稍后再试!");
+				}
+			}
+			return true;
+		} else {
+			return true;
+		}
+	}
+
+	/**
+	 * 验证是否重复提交由子类实现具体的防重复提交的规则
+	 *
+	 * @param request
+	 * @return
+	 * @throws Exception
+	 */
+	@SuppressWarnings("unchecked")
+	public boolean isRepeatSubmit(HttpServletRequest request)
+	{
+		String nowParams = "";
+		if (request instanceof RepeatedlyRequestWrapper)
+		{
+			RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
+			nowParams = HttpHelper.getBodyString(repeatedlyRequest);
+		}
+
+		// body参数为空,获取Parameter的数据
+		if (StringUtils.isEmpty(nowParams))
+		{
+			nowParams = JSONObject.toJSONString(request.getParameterMap());
+		}
+		Map<String, Object> nowDataMap = new HashMap<String, Object>();
+		nowDataMap.put(Constants.REPEAT_PARAMS, nowParams);
+		nowDataMap.put(Constants.REPEAT_TIME, System.currentTimeMillis());
+
+		// 请求地址(作为存放cache的key值)
+		String url = request.getRequestURI();
+
+		// 唯一值(没有消息头则使用请求地址)
+		String submitKey = "";
+		if (StringUtils.isEmpty(submitKey))
+		{
+			submitKey = url;
+		}
+
+		// 唯一标识(指定key + 消息头)
+		String cache_repeat_key = Constants.REPEAT_SUBMIT_KEY + submitKey;
+
+		ValueOperations<String, T> operation = redisTemplate.opsForValue();
+		Object sessionObj = operation.get(cache_repeat_key);
+		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))
+				{
+					return true;
+				}
+			}
+		}
+		Map<String, Object> cacheMap = new HashMap<String, Object>();
+		cacheMap.put(url, nowDataMap);
+		redisTemplate.opsForValue().set(cache_repeat_key, cacheMap, 2, TimeUnit.SECONDS);
+		return false;
+	}
+
+	/**
+	 * 判断参数是否相同
+	 */
+
+	private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap)
+	{
+		String nowParams = (String) nowMap.get(Constants.REPEAT_PARAMS);
+		String preParams = (String) preMap.get(Constants.REPEAT_PARAMS);
+		return nowParams.equals(preParams);
+	}
+
+	/**
+	 * 判断两次间隔时间
+	 */
+
+	private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap)
+	{
+		long time1 = (Long) nowMap.get(Constants.REPEAT_TIME);
+		long time2 = (Long) preMap.get(Constants.REPEAT_TIME);
+		if ((time1 - time2) < (2 * 1000))
+		{
+			return true;
+		}
+		return false;
+	}
+
+}

+ 3 - 0
blade-service/blade-box-tube/src/main/java/org/springblade/box/tube/controller/ArchivesController.java

@@ -32,6 +32,7 @@ import org.springblade.box.tube.entity.ArchivesFiles;
 import org.springblade.box.tube.service.IArchivesFilesService;
 import org.springblade.box.tube.service.IArchivesService;
 import org.springblade.box.tube.vo.ArchivesVO;
+import org.springblade.common.annotation.RepeatSubmit;
 import org.springblade.core.boot.ctrl.BladeController;
 import org.springblade.core.excel.util.ExcelUtil;
 import org.springblade.core.mp.support.Condition;
@@ -81,6 +82,7 @@ public class ArchivesController extends BladeController {
 	@GetMapping("/list")
 	@ApiOperationSupport(order = 2)
 	@ApiOperation(value = "分页", notes = "传入archives")
+	@RepeatSubmit
 	public R<IPage<Archives>> list(Archives archives, Query query) {
 		LambdaQueryWrapper<Archives> lambdaQueryWrapper = new LambdaQueryWrapper<>();
 		lambdaQueryWrapper.eq(Archives::getTenantId, AuthUtil.getTenantId())
@@ -161,6 +163,7 @@ public class ArchivesController extends BladeController {
 	@PostMapping("/submit")
 	@ApiOperationSupport(order = 6)
 	@ApiOperation(value = "新增或修改", notes = "传入archives")
+	@RepeatSubmit
 	public R submit(@Valid @RequestBody Archives archives) {
 		return R.data(archivesService.add(archives));
 	}

+ 3 - 0
blade-service/blade-box-tube/src/main/java/org/springblade/box/tube/controller/RepairController.java

@@ -27,6 +27,7 @@ import javax.validation.Valid;
 
 import org.springblade.box.tube.entity.TradingBox;
 import org.springblade.box.tube.entity.Transport;
+import org.springblade.common.annotation.RepeatSubmit;
 import org.springblade.core.mp.support.Condition;
 import org.springblade.core.mp.support.Query;
 import org.springblade.core.secure.utils.AuthUtil;
@@ -125,6 +126,7 @@ public class RepairController extends BladeController {
 	@PostMapping("/submit")
 	@ApiOperationSupport(order = 6)
 	@ApiOperation(value = "新增或修改", notes = "传入repair")
+	@RepeatSubmit
 	public R submit(@Valid @RequestBody Repair repair) {
 		return R.data(repairService.add(repair));
 	}
@@ -151,6 +153,7 @@ public class RepairController extends BladeController {
 	 * @return
 	 */
 	@PostMapping("/checkRepair")
+	@RepeatSubmit
 	public R checkRepair(@RequestBody Repair repair) {
 		Repair check = repairService.checkRepair(repair);
 		return R.data(check);

+ 3 - 0
blade-service/blade-box-tube/src/main/java/org/springblade/box/tube/controller/TradingBoxController.java

@@ -27,6 +27,7 @@ import lombok.AllArgsConstructor;
 import org.springblade.box.tube.entity.TradingBox;
 import org.springblade.box.tube.service.ITradingBoxService;
 import org.springblade.box.tube.vo.TradingBoxVO;
+import org.springblade.common.annotation.RepeatSubmit;
 import org.springblade.core.boot.ctrl.BladeController;
 import org.springblade.core.mp.support.Condition;
 import org.springblade.core.mp.support.Query;
@@ -123,6 +124,7 @@ public class TradingBoxController extends BladeController {
 	@PostMapping("/submit")
 	@ApiOperationSupport(order = 6)
 	@ApiOperation(value = "新增或修改", notes = "传入tradingBox")
+	@RepeatSubmit
 	public R submit(@Valid @RequestBody TradingBox tradingBox) {
 		return R.data(tradingBoxService.add(tradingBox));
 	}
@@ -149,6 +151,7 @@ public class TradingBoxController extends BladeController {
 	 * @return
 	 */
 	@PostMapping("/checkTradingBox")
+	@RepeatSubmit
 	public R checkTradingBox(@RequestBody TradingBox tradingBox) {
 		TradingBox check = tradingBoxService.checkTradingBox(tradingBox);
 		return R.data(check);

+ 4 - 0
blade-service/blade-box-tube/src/main/java/org/springblade/box/tube/controller/TransportController.java

@@ -28,6 +28,7 @@ import org.springblade.box.tube.entity.TradingBox;
 import org.springblade.box.tube.entity.Transport;
 import org.springblade.box.tube.service.ITransportService;
 import org.springblade.box.tube.vo.TransportVO;
+import org.springblade.common.annotation.RepeatSubmit;
 import org.springblade.core.boot.ctrl.BladeController;
 import org.springblade.core.mp.support.Condition;
 import org.springblade.core.mp.support.Query;
@@ -133,6 +134,7 @@ public class TransportController extends BladeController {
 	@PostMapping("/submit")
 	@ApiOperationSupport(order = 6)
 	@ApiOperation(value = "新增或修改", notes = "传入transport")
+	@RepeatSubmit
 	public R submit(@Valid @RequestBody Transport transport) {
 		return R.data(transportService.add(transport));
 	}
@@ -158,6 +160,7 @@ public class TransportController extends BladeController {
 	@GetMapping("/statusUpdate")
 	@ApiOperationSupport(order = 5)
 	@ApiOperation(value = "修改", notes = "传入transport")
+	@RepeatSubmit
 	public R statusUpdate(@RequestParam("ids") String ids,
 						  @RequestParam("type") String type,
 						  @RequestParam("date") String date,
@@ -176,6 +179,7 @@ public class TransportController extends BladeController {
 	 * @return
 	 */
 	@PostMapping("/checkTransport")
+	@RepeatSubmit
 	public R checkTradingBox(@RequestBody Transport transport) {
 		Transport check = transportService.checkTransport(transport);
 		return R.data(check);

+ 21 - 0
blade-service/blade-check/src/main/java/org/springblade/check/Interceptor/RepeatSubmitConfig.java

@@ -0,0 +1,21 @@
+package org.springblade.check.Interceptor;
+
+import lombok.AllArgsConstructor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+@EnableWebMvc
+@AllArgsConstructor
+public class RepeatSubmitConfig implements WebMvcConfigurer {
+
+	private final SubmitInterceptor submitInterceptor;
+
+	@Override
+	public void addInterceptors(InterceptorRegistry registry) {
+		registry.addInterceptor(submitInterceptor).addPathPatterns("/**");
+	}
+}
+

+ 145 - 0
blade-service/blade-check/src/main/java/org/springblade/check/Interceptor/SubmitInterceptor.java

@@ -0,0 +1,145 @@
+package org.springblade.check.Interceptor;
+
+import com.alibaba.cloud.commons.lang.StringUtils;
+import com.alibaba.fastjson.JSONObject;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.formula.functions.T;
+import org.springblade.common.annotation.RepeatSubmit;
+import org.springblade.common.constant.Constants;
+import org.springblade.common.filter.RepeatedlyRequestWrapper;
+import org.springblade.common.http.HttpHelper;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.stereotype.Component;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 防止重复提交拦截器
+ *
+ * @author
+ */
+@Slf4j
+@Component
+@AllArgsConstructor
+public class SubmitInterceptor implements HandlerInterceptor {
+
+	public final RedisTemplate redisTemplate;
+
+	/**
+	 * 间隔时间,单位:秒 默认10秒
+	 *
+	 * 两次相同参数的请求,如果间隔时间大于该参数,系统不会认定为重复提交的数据
+	 */
+
+	@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 (this.isRepeatSubmit(request)) {
+					throw new RuntimeException("操作过于频繁,请稍后再试!");
+				}
+			}
+			return true;
+		} else {
+			return true;
+		}
+	}
+
+	/**
+	 * 验证是否重复提交由子类实现具体的防重复提交的规则
+	 *
+	 * @param request
+	 * @return
+	 * @throws Exception
+	 */
+	@SuppressWarnings("unchecked")
+	public boolean isRepeatSubmit(HttpServletRequest request)
+	{
+		String nowParams = "";
+		if (request instanceof RepeatedlyRequestWrapper)
+		{
+			RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
+			nowParams = HttpHelper.getBodyString(repeatedlyRequest);
+		}
+
+		// body参数为空,获取Parameter的数据
+		if (StringUtils.isEmpty(nowParams))
+		{
+			nowParams = JSONObject.toJSONString(request.getParameterMap());
+		}
+		Map<String, Object> nowDataMap = new HashMap<String, Object>();
+		nowDataMap.put(Constants.REPEAT_PARAMS, nowParams);
+		nowDataMap.put(Constants.REPEAT_TIME, System.currentTimeMillis());
+
+		// 请求地址(作为存放cache的key值)
+		String url = request.getRequestURI();
+
+		// 唯一值(没有消息头则使用请求地址)
+		String submitKey = "";
+		if (StringUtils.isEmpty(submitKey))
+		{
+			submitKey = url;
+		}
+
+		// 唯一标识(指定key + 消息头)
+		String cache_repeat_key = Constants.REPEAT_SUBMIT_KEY + submitKey;
+
+		ValueOperations<String, T> operation = redisTemplate.opsForValue();
+		Object sessionObj = operation.get(cache_repeat_key);
+		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))
+				{
+					return true;
+				}
+			}
+		}
+		Map<String, Object> cacheMap = new HashMap<String, Object>();
+		cacheMap.put(url, nowDataMap);
+		redisTemplate.opsForValue().set(cache_repeat_key, cacheMap, 2, TimeUnit.SECONDS);
+		return false;
+	}
+
+	/**
+	 * 判断参数是否相同
+	 */
+
+	private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap)
+	{
+		String nowParams = (String) nowMap.get(Constants.REPEAT_PARAMS);
+		String preParams = (String) preMap.get(Constants.REPEAT_PARAMS);
+		return nowParams.equals(preParams);
+	}
+
+	/**
+	 * 判断两次间隔时间
+	 */
+
+	private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap)
+	{
+		long time1 = (Long) nowMap.get(Constants.REPEAT_TIME);
+		long time2 = (Long) preMap.get(Constants.REPEAT_TIME);
+		if ((time1 - time2) < (2 * 1000))
+		{
+			return true;
+		}
+		return false;
+	}
+
+}

+ 2 - 0
blade-service/blade-check/src/main/java/org/springblade/check/controller/AuditProecessController.java

@@ -41,6 +41,7 @@ import org.springblade.check.service.IAuditProecessService;
 import org.springblade.check.vo.AuditOrderVO;
 import org.springblade.client.entity.CorpsDesc;
 import org.springblade.client.feign.ICorpsDescClient;
+import org.springblade.common.annotation.RepeatSubmit;
 import org.springblade.core.boot.ctrl.BladeController;
 import org.springblade.core.mp.support.Condition;
 import org.springblade.core.mp.support.Query;
@@ -276,6 +277,7 @@ public class AuditProecessController extends BladeController {
 	@PostMapping("operationFinanceProcess")
 	@ApiOperationSupport(order = 2)
 	@ApiOperation(value = "操作-公共审批-根据checkType区别", notes = "传入auditProecessDTO")
+	@RepeatSubmit
 	public R operationFinanceProcess(@RequestBody AuditProecess auditProecess) {
 		AuditProecess proecess = auditProecessService.getById(auditProecess.getId());
 		if (proecess == null) {

+ 21 - 0
blade-service/blade-client/src/main/java/org/springblade/client/Interceptor/RepeatSubmitConfig.java

@@ -0,0 +1,21 @@
+package org.springblade.client.Interceptor;
+
+import lombok.AllArgsConstructor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+@EnableWebMvc
+@AllArgsConstructor
+public class RepeatSubmitConfig implements WebMvcConfigurer {
+
+	private final SubmitInterceptor submitInterceptor;
+
+	@Override
+	public void addInterceptors(InterceptorRegistry registry) {
+		registry.addInterceptor(submitInterceptor).addPathPatterns("/**");
+	}
+}
+

+ 145 - 0
blade-service/blade-client/src/main/java/org/springblade/client/Interceptor/SubmitInterceptor.java

@@ -0,0 +1,145 @@
+package org.springblade.client.Interceptor;
+
+import com.alibaba.cloud.commons.lang.StringUtils;
+import com.alibaba.fastjson.JSONObject;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.formula.functions.T;
+import org.springblade.common.annotation.RepeatSubmit;
+import org.springblade.common.constant.Constants;
+import org.springblade.common.filter.RepeatedlyRequestWrapper;
+import org.springblade.common.http.HttpHelper;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.stereotype.Component;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 防止重复提交拦截器
+ *
+ * @author
+ */
+@Slf4j
+@Component
+@AllArgsConstructor
+public class SubmitInterceptor implements HandlerInterceptor {
+
+	public final RedisTemplate redisTemplate;
+
+	/**
+	 * 间隔时间,单位:秒 默认10秒
+	 *
+	 * 两次相同参数的请求,如果间隔时间大于该参数,系统不会认定为重复提交的数据
+	 */
+
+	@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 (this.isRepeatSubmit(request)) {
+					throw new RuntimeException("操作过于频繁,请稍后再试!");
+				}
+			}
+			return true;
+		} else {
+			return true;
+		}
+	}
+
+	/**
+	 * 验证是否重复提交由子类实现具体的防重复提交的规则
+	 *
+	 * @param request
+	 * @return
+	 * @throws Exception
+	 */
+	@SuppressWarnings("unchecked")
+	public boolean isRepeatSubmit(HttpServletRequest request)
+	{
+		String nowParams = "";
+		if (request instanceof RepeatedlyRequestWrapper)
+		{
+			RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
+			nowParams = HttpHelper.getBodyString(repeatedlyRequest);
+		}
+
+		// body参数为空,获取Parameter的数据
+		if (StringUtils.isEmpty(nowParams))
+		{
+			nowParams = JSONObject.toJSONString(request.getParameterMap());
+		}
+		Map<String, Object> nowDataMap = new HashMap<String, Object>();
+		nowDataMap.put(Constants.REPEAT_PARAMS, nowParams);
+		nowDataMap.put(Constants.REPEAT_TIME, System.currentTimeMillis());
+
+		// 请求地址(作为存放cache的key值)
+		String url = request.getRequestURI();
+
+		// 唯一值(没有消息头则使用请求地址)
+		String submitKey = "";
+		if (StringUtils.isEmpty(submitKey))
+		{
+			submitKey = url;
+		}
+
+		// 唯一标识(指定key + 消息头)
+		String cache_repeat_key = Constants.REPEAT_SUBMIT_KEY + submitKey;
+
+		ValueOperations<String, T> operation = redisTemplate.opsForValue();
+		Object sessionObj = operation.get(cache_repeat_key);
+		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))
+				{
+					return true;
+				}
+			}
+		}
+		Map<String, Object> cacheMap = new HashMap<String, Object>();
+		cacheMap.put(url, nowDataMap);
+		redisTemplate.opsForValue().set(cache_repeat_key, cacheMap, 2, TimeUnit.SECONDS);
+		return false;
+	}
+
+	/**
+	 * 判断参数是否相同
+	 */
+
+	private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap)
+	{
+		String nowParams = (String) nowMap.get(Constants.REPEAT_PARAMS);
+		String preParams = (String) preMap.get(Constants.REPEAT_PARAMS);
+		return nowParams.equals(preParams);
+	}
+
+	/**
+	 * 判断两次间隔时间
+	 */
+
+	private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap)
+	{
+		long time1 = (Long) nowMap.get(Constants.REPEAT_TIME);
+		long time2 = (Long) preMap.get(Constants.REPEAT_TIME);
+		if ((time1 - time2) < (2 * 1000))
+		{
+			return true;
+		}
+		return false;
+	}
+
+}

+ 0 - 37
blade-service/blade-client/src/main/java/org/springblade/client/Interceptor/WebSocketInterceptor.java

@@ -1,37 +0,0 @@
-/*
-package org.springblade.client.Interceptor;
-
-import org.springframework.http.server.ServerHttpRequest;
-import org.springframework.http.server.ServerHttpResponse;
-import org.springframework.http.server.ServletServerHttpRequest;
-import org.springframework.web.socket.WebSocketHandler;
-import org.springframework.web.socket.server.HandshakeInterceptor;
-
-import java.util.Map;
-
-public class WebSocketInterceptor implements HandshakeInterceptor {
-
-	*/
-/**
-	 * handler处理前调用,attributes属性最终在WebSocketSession里,可能通过webSocketSession.getAttributes().get(key值)获得
-	 *//*
-
-	@Override
-	public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) {
-		if (request instanceof ServletServerHttpRequest) {
-			ServletServerHttpRequest serverHttpRequest = (ServletServerHttpRequest) request;
-			// 获取请求路径携带的参数
-			String user = serverHttpRequest.getServletRequest().getParameter("user");
-			attributes.put("user", user);
-			return true;
-		} else {
-			return false;
-		}
-	}
-
-	@Override
-	public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
-
-	}
-}
-*/

+ 0 - 32
blade-service/blade-client/src/main/java/org/springblade/client/config/WebSocketAutoConfig.java

@@ -1,32 +0,0 @@
-/*
-package org.springblade.client.config;
-
-import org.springblade.client.Interceptor.WebSocketInterceptor;
-import org.springblade.client.handler.WebSocketHandler;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.socket.config.annotation.EnableWebSocket;
-import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
-import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
-
-@Configuration
-@EnableWebSocket
-public class WebSocketAutoConfig implements WebSocketConfigurer {
-
-	@Override
-	public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
-		// webSocket通道
-		// 指定处理器和路径
-		registry.addHandler(new WebSocketHandler(), "/websocket")
-			// 指定自定义拦截器
-			.addInterceptors(new WebSocketInterceptor())
-			// 允许跨域
-			.setAllowedOrigins("*");
-		// sockJs通道
-		registry.addHandler(new WebSocketHandler(), "/sock-js")
-			.addInterceptors(new WebSocketInterceptor())
-			.setAllowedOrigins("*")
-			// 开启sockJs支持
-			.withSockJS();
-	}
-}
-*/

+ 21 - 0
blade-service/blade-deliver-goods/src/main/java/org/springblade/deliver/goods/Interceptor/RepeatSubmitConfig.java

@@ -0,0 +1,21 @@
+package org.springblade.deliver.goods.Interceptor;
+
+import lombok.AllArgsConstructor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+@EnableWebMvc
+@AllArgsConstructor
+public class RepeatSubmitConfig implements WebMvcConfigurer {
+
+	private final SubmitInterceptor submitInterceptor;
+
+	@Override
+	public void addInterceptors(InterceptorRegistry registry) {
+		registry.addInterceptor(submitInterceptor).addPathPatterns("/**");
+	}
+}
+

+ 145 - 0
blade-service/blade-deliver-goods/src/main/java/org/springblade/deliver/goods/Interceptor/SubmitInterceptor.java

@@ -0,0 +1,145 @@
+package org.springblade.deliver.goods.Interceptor;
+
+import com.alibaba.cloud.commons.lang.StringUtils;
+import com.alibaba.fastjson.JSONObject;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.formula.functions.T;
+import org.springblade.common.annotation.RepeatSubmit;
+import org.springblade.common.constant.Constants;
+import org.springblade.common.filter.RepeatedlyRequestWrapper;
+import org.springblade.common.http.HttpHelper;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.stereotype.Component;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 防止重复提交拦截器
+ *
+ * @author
+ */
+@Slf4j
+@Component
+@AllArgsConstructor
+public class SubmitInterceptor implements HandlerInterceptor {
+
+	public final RedisTemplate redisTemplate;
+
+	/**
+	 * 间隔时间,单位:秒 默认10秒
+	 *
+	 * 两次相同参数的请求,如果间隔时间大于该参数,系统不会认定为重复提交的数据
+	 */
+
+	@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 (this.isRepeatSubmit(request)) {
+					throw new RuntimeException("操作过于频繁,请稍后再试!");
+				}
+			}
+			return true;
+		} else {
+			return true;
+		}
+	}
+
+	/**
+	 * 验证是否重复提交由子类实现具体的防重复提交的规则
+	 *
+	 * @param request
+	 * @return
+	 * @throws Exception
+	 */
+	@SuppressWarnings("unchecked")
+	public boolean isRepeatSubmit(HttpServletRequest request)
+	{
+		String nowParams = "";
+		if (request instanceof RepeatedlyRequestWrapper)
+		{
+			RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
+			nowParams = HttpHelper.getBodyString(repeatedlyRequest);
+		}
+
+		// body参数为空,获取Parameter的数据
+		if (StringUtils.isEmpty(nowParams))
+		{
+			nowParams = JSONObject.toJSONString(request.getParameterMap());
+		}
+		Map<String, Object> nowDataMap = new HashMap<String, Object>();
+		nowDataMap.put(Constants.REPEAT_PARAMS, nowParams);
+		nowDataMap.put(Constants.REPEAT_TIME, System.currentTimeMillis());
+
+		// 请求地址(作为存放cache的key值)
+		String url = request.getRequestURI();
+
+		// 唯一值(没有消息头则使用请求地址)
+		String submitKey = "";
+		if (StringUtils.isEmpty(submitKey))
+		{
+			submitKey = url;
+		}
+
+		// 唯一标识(指定key + 消息头)
+		String cache_repeat_key = Constants.REPEAT_SUBMIT_KEY + submitKey;
+
+		ValueOperations<String, T> operation = redisTemplate.opsForValue();
+		Object sessionObj = operation.get(cache_repeat_key);
+		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))
+				{
+					return true;
+				}
+			}
+		}
+		Map<String, Object> cacheMap = new HashMap<String, Object>();
+		cacheMap.put(url, nowDataMap);
+		redisTemplate.opsForValue().set(cache_repeat_key, cacheMap, 2, TimeUnit.SECONDS);
+		return false;
+	}
+
+	/**
+	 * 判断参数是否相同
+	 */
+
+	private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap)
+	{
+		String nowParams = (String) nowMap.get(Constants.REPEAT_PARAMS);
+		String preParams = (String) preMap.get(Constants.REPEAT_PARAMS);
+		return nowParams.equals(preParams);
+	}
+
+	/**
+	 * 判断两次间隔时间
+	 */
+
+	private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap)
+	{
+		long time1 = (Long) nowMap.get(Constants.REPEAT_TIME);
+		long time2 = (Long) preMap.get(Constants.REPEAT_TIME);
+		if ((time1 - time2) < (2 * 1000))
+		{
+			return true;
+		}
+		return false;
+	}
+
+}

+ 3 - 0
blade-service/blade-deliver-goods/src/main/java/org/springblade/deliver/goods/controller/DeliveryController.java

@@ -35,6 +35,7 @@ import org.springblade.client.entity.StorageType;
 import org.springblade.client.feign.ICorpsDescClient;
 import org.springblade.client.feign.IRedisClient;
 import org.springblade.client.feign.IStorageClient;
+import org.springblade.common.annotation.RepeatSubmit;
 import org.springblade.core.excel.util.ExcelUtil;
 import org.springblade.core.mp.support.Condition;
 import org.springblade.core.mp.support.Query;
@@ -294,6 +295,7 @@ public class DeliveryController extends BladeController {
 	@PostMapping("/takeDelivery")
 	@ApiOperationSupport(order = 4)
 	@ApiOperation(value = "国内贸易发货单确认收货,确认发货后才能点", notes = "传入delivery")
+	@RepeatSubmit
 	public R takeDelivery(@Valid @RequestBody Delivery delivery) {
 		delivery.setBillType(OrderTypeEnum.SHIP.getType());
 		delivery.setTradeType(OrderTypeEnum.DOMESTIC.getType());
@@ -307,6 +309,7 @@ public class DeliveryController extends BladeController {
 	@PostMapping("/revocation")
 	@ApiOperationSupport(order = 4)
 	@ApiOperation(value = "国内贸易发货单撤销确认到货,确认收货才能点", notes = "传入delivery")
+	@RepeatSubmit
 	public R revocation(@Valid @RequestBody Delivery delivery) {
 		delivery.setBillType(OrderTypeEnum.SHIP.getType());
 		delivery.setTradeType(OrderTypeEnum.DOMESTIC.getType());

+ 21 - 0
blade-service/blade-land/src/main/java/org/springblade/land/Interceptor/RepeatSubmitConfig.java

@@ -0,0 +1,21 @@
+package org.springblade.land.Interceptor;
+
+import lombok.AllArgsConstructor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+@EnableWebMvc
+@AllArgsConstructor
+public class RepeatSubmitConfig implements WebMvcConfigurer {
+
+	private final SubmitInterceptor submitInterceptor;
+
+	@Override
+	public void addInterceptors(InterceptorRegistry registry) {
+		registry.addInterceptor(submitInterceptor).addPathPatterns("/**");
+	}
+}
+

+ 145 - 0
blade-service/blade-land/src/main/java/org/springblade/land/Interceptor/SubmitInterceptor.java

@@ -0,0 +1,145 @@
+package org.springblade.land.Interceptor;
+
+import com.alibaba.cloud.commons.lang.StringUtils;
+import com.alibaba.fastjson.JSONObject;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.formula.functions.T;
+import org.springblade.common.annotation.RepeatSubmit;
+import org.springblade.common.constant.Constants;
+import org.springblade.common.filter.RepeatedlyRequestWrapper;
+import org.springblade.common.http.HttpHelper;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.stereotype.Component;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 防止重复提交拦截器
+ *
+ * @author
+ */
+@Slf4j
+@Component
+@AllArgsConstructor
+public class SubmitInterceptor implements HandlerInterceptor {
+
+	public final RedisTemplate redisTemplate;
+
+	/**
+	 * 间隔时间,单位:秒 默认10秒
+	 *
+	 * 两次相同参数的请求,如果间隔时间大于该参数,系统不会认定为重复提交的数据
+	 */
+
+	@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 (this.isRepeatSubmit(request)) {
+					throw new RuntimeException("操作过于频繁,请稍后再试!");
+				}
+			}
+			return true;
+		} else {
+			return true;
+		}
+	}
+
+	/**
+	 * 验证是否重复提交由子类实现具体的防重复提交的规则
+	 *
+	 * @param request
+	 * @return
+	 * @throws Exception
+	 */
+	@SuppressWarnings("unchecked")
+	public boolean isRepeatSubmit(HttpServletRequest request)
+	{
+		String nowParams = "";
+		if (request instanceof RepeatedlyRequestWrapper)
+		{
+			RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
+			nowParams = HttpHelper.getBodyString(repeatedlyRequest);
+		}
+
+		// body参数为空,获取Parameter的数据
+		if (StringUtils.isEmpty(nowParams))
+		{
+			nowParams = JSONObject.toJSONString(request.getParameterMap());
+		}
+		Map<String, Object> nowDataMap = new HashMap<String, Object>();
+		nowDataMap.put(Constants.REPEAT_PARAMS, nowParams);
+		nowDataMap.put(Constants.REPEAT_TIME, System.currentTimeMillis());
+
+		// 请求地址(作为存放cache的key值)
+		String url = request.getRequestURI();
+
+		// 唯一值(没有消息头则使用请求地址)
+		String submitKey = "";
+		if (StringUtils.isEmpty(submitKey))
+		{
+			submitKey = url;
+		}
+
+		// 唯一标识(指定key + 消息头)
+		String cache_repeat_key = Constants.REPEAT_SUBMIT_KEY + submitKey;
+
+		ValueOperations<String, T> operation = redisTemplate.opsForValue();
+		Object sessionObj = operation.get(cache_repeat_key);
+		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))
+				{
+					return true;
+				}
+			}
+		}
+		Map<String, Object> cacheMap = new HashMap<String, Object>();
+		cacheMap.put(url, nowDataMap);
+		redisTemplate.opsForValue().set(cache_repeat_key, cacheMap, 2, TimeUnit.SECONDS);
+		return false;
+	}
+
+	/**
+	 * 判断参数是否相同
+	 */
+
+	private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap)
+	{
+		String nowParams = (String) nowMap.get(Constants.REPEAT_PARAMS);
+		String preParams = (String) preMap.get(Constants.REPEAT_PARAMS);
+		return nowParams.equals(preParams);
+	}
+
+	/**
+	 * 判断两次间隔时间
+	 */
+
+	private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap)
+	{
+		long time1 = (Long) nowMap.get(Constants.REPEAT_TIME);
+		long time2 = (Long) preMap.get(Constants.REPEAT_TIME);
+		if ((time1 - time2) < (2 * 1000))
+		{
+			return true;
+		}
+		return false;
+	}
+
+}

+ 21 - 0
blade-service/blade-purchase-sales/src/main/java/org/springblade/purchase/sales/Interceptor/RepeatSubmitConfig.java

@@ -0,0 +1,21 @@
+package org.springblade.purchase.sales.Interceptor;
+
+import lombok.AllArgsConstructor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+@EnableWebMvc
+@AllArgsConstructor
+public class RepeatSubmitConfig implements WebMvcConfigurer {
+
+	private final SubmitInterceptor submitInterceptor;
+
+	@Override
+	public void addInterceptors(InterceptorRegistry registry) {
+		registry.addInterceptor(submitInterceptor).addPathPatterns("/**");
+	}
+}
+

+ 145 - 0
blade-service/blade-purchase-sales/src/main/java/org/springblade/purchase/sales/Interceptor/SubmitInterceptor.java

@@ -0,0 +1,145 @@
+package org.springblade.purchase.sales.Interceptor;
+
+import com.alibaba.cloud.commons.lang.StringUtils;
+import com.alibaba.fastjson.JSONObject;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.formula.functions.T;
+import org.springblade.common.annotation.RepeatSubmit;
+import org.springblade.common.constant.Constants;
+import org.springblade.common.filter.RepeatedlyRequestWrapper;
+import org.springblade.common.http.HttpHelper;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.stereotype.Component;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 防止重复提交拦截器
+ *
+ * @author
+ */
+@Slf4j
+@Component
+@AllArgsConstructor
+public class SubmitInterceptor implements HandlerInterceptor {
+
+	public final RedisTemplate redisTemplate;
+
+	/**
+	 * 间隔时间,单位:秒 默认10秒
+	 *
+	 * 两次相同参数的请求,如果间隔时间大于该参数,系统不会认定为重复提交的数据
+	 */
+
+	@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 (this.isRepeatSubmit(request)) {
+					throw new RuntimeException("操作过于频繁,请稍后再试!");
+				}
+			}
+			return true;
+		} else {
+			return true;
+		}
+	}
+
+	/**
+	 * 验证是否重复提交由子类实现具体的防重复提交的规则
+	 *
+	 * @param request
+	 * @return
+	 * @throws Exception
+	 */
+	@SuppressWarnings("unchecked")
+	public boolean isRepeatSubmit(HttpServletRequest request)
+	{
+		String nowParams = "";
+		if (request instanceof RepeatedlyRequestWrapper)
+		{
+			RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
+			nowParams = HttpHelper.getBodyString(repeatedlyRequest);
+		}
+
+		// body参数为空,获取Parameter的数据
+		if (StringUtils.isEmpty(nowParams))
+		{
+			nowParams = JSONObject.toJSONString(request.getParameterMap());
+		}
+		Map<String, Object> nowDataMap = new HashMap<String, Object>();
+		nowDataMap.put(Constants.REPEAT_PARAMS, nowParams);
+		nowDataMap.put(Constants.REPEAT_TIME, System.currentTimeMillis());
+
+		// 请求地址(作为存放cache的key值)
+		String url = request.getRequestURI();
+
+		// 唯一值(没有消息头则使用请求地址)
+		String submitKey = "";
+		if (StringUtils.isEmpty(submitKey))
+		{
+			submitKey = url;
+		}
+
+		// 唯一标识(指定key + 消息头)
+		String cache_repeat_key = Constants.REPEAT_SUBMIT_KEY + submitKey;
+
+		ValueOperations<String, T> operation = redisTemplate.opsForValue();
+		Object sessionObj = operation.get(cache_repeat_key);
+		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))
+				{
+					return true;
+				}
+			}
+		}
+		Map<String, Object> cacheMap = new HashMap<String, Object>();
+		cacheMap.put(url, nowDataMap);
+		redisTemplate.opsForValue().set(cache_repeat_key, cacheMap, 2, TimeUnit.SECONDS);
+		return false;
+	}
+
+	/**
+	 * 判断参数是否相同
+	 */
+
+	private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap)
+	{
+		String nowParams = (String) nowMap.get(Constants.REPEAT_PARAMS);
+		String preParams = (String) preMap.get(Constants.REPEAT_PARAMS);
+		return nowParams.equals(preParams);
+	}
+
+	/**
+	 * 判断两次间隔时间
+	 */
+
+	private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap)
+	{
+		long time1 = (Long) nowMap.get(Constants.REPEAT_TIME);
+		long time2 = (Long) preMap.get(Constants.REPEAT_TIME);
+		if ((time1 - time2) < (2 * 1000))
+		{
+			return true;
+		}
+		return false;
+	}
+
+}

+ 21 - 0
blade-service/blade-stock/src/main/java/org/springblade/stock/Interceptor/RepeatSubmitConfig.java

@@ -0,0 +1,21 @@
+package org.springblade.stock.Interceptor;
+
+import lombok.AllArgsConstructor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+@EnableWebMvc
+@AllArgsConstructor
+public class RepeatSubmitConfig implements WebMvcConfigurer {
+
+	private final SubmitInterceptor submitInterceptor;
+
+	@Override
+	public void addInterceptors(InterceptorRegistry registry) {
+		registry.addInterceptor(submitInterceptor).addPathPatterns("/**");
+	}
+}
+

+ 145 - 0
blade-service/blade-stock/src/main/java/org/springblade/stock/Interceptor/SubmitInterceptor.java

@@ -0,0 +1,145 @@
+package org.springblade.stock.Interceptor;
+
+import com.alibaba.cloud.commons.lang.StringUtils;
+import com.alibaba.fastjson.JSONObject;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.formula.functions.T;
+import org.springblade.common.annotation.RepeatSubmit;
+import org.springblade.common.constant.Constants;
+import org.springblade.common.filter.RepeatedlyRequestWrapper;
+import org.springblade.common.http.HttpHelper;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.stereotype.Component;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 防止重复提交拦截器
+ *
+ * @author
+ */
+@Slf4j
+@Component
+@AllArgsConstructor
+public class SubmitInterceptor implements HandlerInterceptor {
+
+	public final RedisTemplate redisTemplate;
+
+	/**
+	 * 间隔时间,单位:秒 默认10秒
+	 *
+	 * 两次相同参数的请求,如果间隔时间大于该参数,系统不会认定为重复提交的数据
+	 */
+
+	@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 (this.isRepeatSubmit(request)) {
+					throw new RuntimeException("操作过于频繁,请稍后再试!");
+				}
+			}
+			return true;
+		} else {
+			return true;
+		}
+	}
+
+	/**
+	 * 验证是否重复提交由子类实现具体的防重复提交的规则
+	 *
+	 * @param request
+	 * @return
+	 * @throws Exception
+	 */
+	@SuppressWarnings("unchecked")
+	public boolean isRepeatSubmit(HttpServletRequest request)
+	{
+		String nowParams = "";
+		if (request instanceof RepeatedlyRequestWrapper)
+		{
+			RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
+			nowParams = HttpHelper.getBodyString(repeatedlyRequest);
+		}
+
+		// body参数为空,获取Parameter的数据
+		if (StringUtils.isEmpty(nowParams))
+		{
+			nowParams = JSONObject.toJSONString(request.getParameterMap());
+		}
+		Map<String, Object> nowDataMap = new HashMap<String, Object>();
+		nowDataMap.put(Constants.REPEAT_PARAMS, nowParams);
+		nowDataMap.put(Constants.REPEAT_TIME, System.currentTimeMillis());
+
+		// 请求地址(作为存放cache的key值)
+		String url = request.getRequestURI();
+
+		// 唯一值(没有消息头则使用请求地址)
+		String submitKey = "";
+		if (StringUtils.isEmpty(submitKey))
+		{
+			submitKey = url;
+		}
+
+		// 唯一标识(指定key + 消息头)
+		String cache_repeat_key = Constants.REPEAT_SUBMIT_KEY + submitKey;
+
+		ValueOperations<String, T> operation = redisTemplate.opsForValue();
+		Object sessionObj = operation.get(cache_repeat_key);
+		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))
+				{
+					return true;
+				}
+			}
+		}
+		Map<String, Object> cacheMap = new HashMap<String, Object>();
+		cacheMap.put(url, nowDataMap);
+		redisTemplate.opsForValue().set(cache_repeat_key, cacheMap, 2, TimeUnit.SECONDS);
+		return false;
+	}
+
+	/**
+	 * 判断参数是否相同
+	 */
+
+	private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap)
+	{
+		String nowParams = (String) nowMap.get(Constants.REPEAT_PARAMS);
+		String preParams = (String) preMap.get(Constants.REPEAT_PARAMS);
+		return nowParams.equals(preParams);
+	}
+
+	/**
+	 * 判断两次间隔时间
+	 */
+
+	private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap)
+	{
+		long time1 = (Long) nowMap.get(Constants.REPEAT_TIME);
+		long time2 = (Long) preMap.get(Constants.REPEAT_TIME);
+		if ((time1 - time2) < (2 * 1000))
+		{
+			return true;
+		}
+		return false;
+	}
+
+}

+ 21 - 0
blade-service/trade-finance/src/main/java/org/springblade/finance/Interceptor/RepeatSubmitConfig.java

@@ -0,0 +1,21 @@
+package org.springblade.finance.Interceptor;
+
+import lombok.AllArgsConstructor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+@EnableWebMvc
+@AllArgsConstructor
+public class RepeatSubmitConfig implements WebMvcConfigurer {
+
+	private final SubmitInterceptor submitInterceptor;
+
+	@Override
+	public void addInterceptors(InterceptorRegistry registry) {
+		registry.addInterceptor(submitInterceptor).addPathPatterns("/**");
+	}
+}
+

+ 145 - 0
blade-service/trade-finance/src/main/java/org/springblade/finance/Interceptor/SubmitInterceptor.java

@@ -0,0 +1,145 @@
+package org.springblade.finance.Interceptor;
+
+import com.alibaba.cloud.commons.lang.StringUtils;
+import com.alibaba.fastjson.JSONObject;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.formula.functions.T;
+import org.springblade.common.annotation.RepeatSubmit;
+import org.springblade.common.constant.Constants;
+import org.springblade.common.filter.RepeatedlyRequestWrapper;
+import org.springblade.common.http.HttpHelper;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.stereotype.Component;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 防止重复提交拦截器
+ *
+ * @author
+ */
+@Slf4j
+@Component
+@AllArgsConstructor
+public class SubmitInterceptor implements HandlerInterceptor {
+
+	public final RedisTemplate redisTemplate;
+
+	/**
+	 * 间隔时间,单位:秒 默认10秒
+	 *
+	 * 两次相同参数的请求,如果间隔时间大于该参数,系统不会认定为重复提交的数据
+	 */
+
+	@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 (this.isRepeatSubmit(request)) {
+					throw new RuntimeException("操作过于频繁,请稍后再试!");
+				}
+			}
+			return true;
+		} else {
+			return true;
+		}
+	}
+
+	/**
+	 * 验证是否重复提交由子类实现具体的防重复提交的规则
+	 *
+	 * @param request
+	 * @return
+	 * @throws Exception
+	 */
+	@SuppressWarnings("unchecked")
+	public boolean isRepeatSubmit(HttpServletRequest request)
+	{
+		String nowParams = "";
+		if (request instanceof RepeatedlyRequestWrapper)
+		{
+			RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
+			nowParams = HttpHelper.getBodyString(repeatedlyRequest);
+		}
+
+		// body参数为空,获取Parameter的数据
+		if (StringUtils.isEmpty(nowParams))
+		{
+			nowParams = JSONObject.toJSONString(request.getParameterMap());
+		}
+		Map<String, Object> nowDataMap = new HashMap<String, Object>();
+		nowDataMap.put(Constants.REPEAT_PARAMS, nowParams);
+		nowDataMap.put(Constants.REPEAT_TIME, System.currentTimeMillis());
+
+		// 请求地址(作为存放cache的key值)
+		String url = request.getRequestURI();
+
+		// 唯一值(没有消息头则使用请求地址)
+		String submitKey = "";
+		if (StringUtils.isEmpty(submitKey))
+		{
+			submitKey = url;
+		}
+
+		// 唯一标识(指定key + 消息头)
+		String cache_repeat_key = Constants.REPEAT_SUBMIT_KEY + submitKey;
+
+		ValueOperations<String, T> operation = redisTemplate.opsForValue();
+		Object sessionObj = operation.get(cache_repeat_key);
+		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))
+				{
+					return true;
+				}
+			}
+		}
+		Map<String, Object> cacheMap = new HashMap<String, Object>();
+		cacheMap.put(url, nowDataMap);
+		redisTemplate.opsForValue().set(cache_repeat_key, cacheMap, 2, TimeUnit.SECONDS);
+		return false;
+	}
+
+	/**
+	 * 判断参数是否相同
+	 */
+
+	private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap)
+	{
+		String nowParams = (String) nowMap.get(Constants.REPEAT_PARAMS);
+		String preParams = (String) preMap.get(Constants.REPEAT_PARAMS);
+		return nowParams.equals(preParams);
+	}
+
+	/**
+	 * 判断两次间隔时间
+	 */
+
+	private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap)
+	{
+		long time1 = (Long) nowMap.get(Constants.REPEAT_TIME);
+		long time2 = (Long) preMap.get(Constants.REPEAT_TIME);
+		if ((time1 - time2) < (2 * 1000))
+		{
+			return true;
+		}
+		return false;
+	}
+
+}

+ 21 - 0
blade-service/trade-purchase/src/main/java/com/trade/purchase/Interceptor/RepeatSubmitConfig.java

@@ -0,0 +1,21 @@
+package com.trade.purchase.Interceptor;
+
+import lombok.AllArgsConstructor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+@EnableWebMvc
+@AllArgsConstructor
+public class RepeatSubmitConfig implements WebMvcConfigurer {
+
+	private final SubmitInterceptor submitInterceptor;
+
+	@Override
+	public void addInterceptors(InterceptorRegistry registry) {
+		registry.addInterceptor(submitInterceptor).addPathPatterns("/**");
+	}
+}
+

+ 145 - 0
blade-service/trade-purchase/src/main/java/com/trade/purchase/Interceptor/SubmitInterceptor.java

@@ -0,0 +1,145 @@
+package com.trade.purchase.Interceptor;
+
+import com.alibaba.cloud.commons.lang.StringUtils;
+import com.alibaba.fastjson.JSONObject;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.formula.functions.T;
+import org.springblade.common.annotation.RepeatSubmit;
+import org.springblade.common.constant.Constants;
+import org.springblade.common.filter.RepeatedlyRequestWrapper;
+import org.springblade.common.http.HttpHelper;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.stereotype.Component;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 防止重复提交拦截器
+ *
+ * @author
+ */
+@Slf4j
+@Component
+@AllArgsConstructor
+public class SubmitInterceptor implements HandlerInterceptor {
+
+	public final RedisTemplate redisTemplate;
+
+	/**
+	 * 间隔时间,单位:秒 默认10秒
+	 *
+	 * 两次相同参数的请求,如果间隔时间大于该参数,系统不会认定为重复提交的数据
+	 */
+
+	@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 (this.isRepeatSubmit(request)) {
+					throw new RuntimeException("操作过于频繁,请稍后再试!");
+				}
+			}
+			return true;
+		} else {
+			return true;
+		}
+	}
+
+	/**
+	 * 验证是否重复提交由子类实现具体的防重复提交的规则
+	 *
+	 * @param request
+	 * @return
+	 * @throws Exception
+	 */
+	@SuppressWarnings("unchecked")
+	public boolean isRepeatSubmit(HttpServletRequest request)
+	{
+		String nowParams = "";
+		if (request instanceof RepeatedlyRequestWrapper)
+		{
+			RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
+			nowParams = HttpHelper.getBodyString(repeatedlyRequest);
+		}
+
+		// body参数为空,获取Parameter的数据
+		if (StringUtils.isEmpty(nowParams))
+		{
+			nowParams = JSONObject.toJSONString(request.getParameterMap());
+		}
+		Map<String, Object> nowDataMap = new HashMap<String, Object>();
+		nowDataMap.put(Constants.REPEAT_PARAMS, nowParams);
+		nowDataMap.put(Constants.REPEAT_TIME, System.currentTimeMillis());
+
+		// 请求地址(作为存放cache的key值)
+		String url = request.getRequestURI();
+
+		// 唯一值(没有消息头则使用请求地址)
+		String submitKey = "";
+		if (StringUtils.isEmpty(submitKey))
+		{
+			submitKey = url;
+		}
+
+		// 唯一标识(指定key + 消息头)
+		String cache_repeat_key = Constants.REPEAT_SUBMIT_KEY + submitKey;
+
+		ValueOperations<String, T> operation = redisTemplate.opsForValue();
+		Object sessionObj = operation.get(cache_repeat_key);
+		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))
+				{
+					return true;
+				}
+			}
+		}
+		Map<String, Object> cacheMap = new HashMap<String, Object>();
+		cacheMap.put(url, nowDataMap);
+		redisTemplate.opsForValue().set(cache_repeat_key, cacheMap, 2, TimeUnit.SECONDS);
+		return false;
+	}
+
+	/**
+	 * 判断参数是否相同
+	 */
+
+	private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap)
+	{
+		String nowParams = (String) nowMap.get(Constants.REPEAT_PARAMS);
+		String preParams = (String) preMap.get(Constants.REPEAT_PARAMS);
+		return nowParams.equals(preParams);
+	}
+
+	/**
+	 * 判断两次间隔时间
+	 */
+
+	private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap)
+	{
+		long time1 = (Long) nowMap.get(Constants.REPEAT_TIME);
+		long time2 = (Long) preMap.get(Constants.REPEAT_TIME);
+		if ((time1 - time2) < (2 * 1000))
+		{
+			return true;
+		}
+		return false;
+	}
+
+}

+ 6 - 0
blade-service/trade-purchase/src/main/java/com/trade/purchase/order/controller/WoodHarvestingCloudController.java

@@ -28,6 +28,7 @@ import org.springblade.client.feign.ICorpsDescClient;
 import org.springblade.client.feign.IGoodsDescClient;
 import org.springblade.client.feign.IStorageClient;
 import org.springblade.client.vo.GoodsDescVO;
+import org.springblade.common.annotation.RepeatSubmit;
 import org.springblade.core.excel.util.ExcelUtil;
 import org.springblade.core.mp.support.Condition;
 import org.springblade.core.mp.support.Query;
@@ -144,6 +145,7 @@ public class WoodHarvestingCloudController {
 	@PostMapping("/submit")
 	@ApiOperationSupport(order = 6)
 	@ApiOperation(value = "新增或修改", notes = "传入order")
+	@RepeatSubmit
 	public R submit(@Valid @RequestBody OrderSubmitDto submitDto) {
 		submitDto.setTradeType(OrderTypeEnum.WOOD_HARVESTING_CLOUD.getType());
 		return orderService.submitWarehousing(submitDto);
@@ -196,6 +198,7 @@ public class WoodHarvestingCloudController {
 	@GetMapping("/withdraw")
 	@ApiOperationSupport(order = 7)
 	@ApiOperation(value = "电脑端提交", notes = "传入id")
+	@RepeatSubmit
 	public R pcSubmit(@RequestParam(value = "id") Long id,
 					  @RequestParam(value = "type") String type,
 					  @RequestParam(value = "toolType", required = false) String toolType,
@@ -214,6 +217,7 @@ public class WoodHarvestingCloudController {
 	 * @return
 	 */
 	@PostMapping("/checkWarehousing")
+	@RepeatSubmit
 	public R checkOrder(@RequestBody OrderSubmitDto submitDto) {
 		orderService.checkWarehousing(submitDto);
 		return R.data("操作成功");
@@ -226,6 +230,7 @@ public class WoodHarvestingCloudController {
 	 * @return
 	 */
 	@PostMapping("/revokeWarehousing")
+	@RepeatSubmit
 	public R revokeOrder(@RequestBody OrderSubmitDto submitDto) {
 		return R.data(orderService.revokeWarehousing(submitDto));
 	}
@@ -278,6 +283,7 @@ public class WoodHarvestingCloudController {
 	@GetMapping("/confirm")
 	@ApiOperationSupport(order = 8)
 	@ApiOperation(value = "手动入出库确认", notes = "主表id")
+	@RepeatSubmit
 	public R confirm(@ApiParam(value = "主表id", required = true) @RequestParam Long id) {
 		if (ObjectUtils.isNull(id)) {
 			return R.fail("缺少必要参数");