diff --git a/ruoyi/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java b/ruoyi/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java index b836c210..8c19564b 100644 --- a/ruoyi/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java +++ b/ruoyi/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java @@ -1,9 +1,12 @@ package com.ruoyi.framework.config; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import com.ruoyi.common.constant.Constants; +import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor; /** * 通用配置 @@ -13,6 +16,9 @@ import com.ruoyi.common.constant.Constants; @Configuration public class ResourcesConfig implements WebMvcConfigurer { + @Autowired + private RepeatSubmitInterceptor repeatSubmitInterceptor; + @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { @@ -23,4 +29,13 @@ public class ResourcesConfig implements WebMvcConfigurer registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/"); registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); } + + /** + * 自定义拦截规则 + */ + @Override + public void addInterceptors(InterceptorRegistry registry) + { + registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**"); + } } \ No newline at end of file diff --git a/ruoyi/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java b/ruoyi/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java new file mode 100644 index 00000000..088798d5 --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java @@ -0,0 +1,55 @@ +package com.ruoyi.framework.interceptor; + +import java.lang.reflect.Method; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.stereotype.Component; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; +import com.alibaba.fastjson.JSONObject; +import com.ruoyi.common.utils.ServletUtils; +import com.ruoyi.framework.interceptor.annotation.RepeatSubmit; +import com.ruoyi.framework.web.domain.AjaxResult; + +/** + * 防止重复提交拦截器 + * + * @author ruoyi + */ +@Component +public abstract class RepeatSubmitInterceptor extends HandlerInterceptorAdapter +{ + @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)) + { + AjaxResult ajaxResult = AjaxResult.error("不允许重复提交,请稍后再试"); + ServletUtils.renderString(response, JSONObject.toJSONString(ajaxResult)); + return false; + } + } + return true; + } + else + { + return super.preHandle(request, response, handler); + } + } + + /** + * 验证是否重复提交由子类实现具体的防重复提交的规则 + * + * @param httpServletRequest + * @return + * @throws Exception + */ + public abstract boolean isRepeatSubmit(HttpServletRequest request); +} diff --git a/ruoyi/src/main/java/com/ruoyi/framework/interceptor/annotation/RepeatSubmit.java b/ruoyi/src/main/java/com/ruoyi/framework/interceptor/annotation/RepeatSubmit.java new file mode 100644 index 00000000..0fbd73b6 --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/framework/interceptor/annotation/RepeatSubmit.java @@ -0,0 +1,23 @@ +package com.ruoyi.framework.interceptor.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 自定义注解防止表单重复提交 + * + * @author ruoyi + * + */ +@Inherited +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RepeatSubmit +{ + +} \ No newline at end of file diff --git a/ruoyi/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java b/ruoyi/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java new file mode 100644 index 00000000..9d915c6e --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java @@ -0,0 +1,94 @@ +package com.ruoyi.framework.interceptor.impl; + +import java.util.HashMap; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; +import org.springframework.stereotype.Component; +import com.alibaba.fastjson.JSONObject; +import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor; + +/** + * 判断请求url和数据是否和上一次相同, + * 如果和上次相同,则是重复提交表单。 有效时间为10秒内。 + * + * @author ruoyi + */ +@Component +public class SameUrlDataInterceptor extends RepeatSubmitInterceptor +{ + public final String REPEAT_PARAMS = "repeatParams"; + + public final String REPEAT_TIME = "repeatTime"; + + public final String SESSION_REPEAT_KEY = "repeatData"; + + /** + * 间隔时间,单位:秒 默认10秒 + * + * 两次相同参数的请求,如果间隔时间大于该参数,系统不会认定为重复提交的数据 + */ + private int intervalTime = 10; + + public void setIntervalTime(int intervalTime) + { + this.intervalTime = intervalTime; + } + + @SuppressWarnings("unchecked") + @Override + public boolean isRepeatSubmit(HttpServletRequest request) + { + // 本次参数及系统时间 + String nowParams = JSONObject.toJSONString(request.getParameterMap()); + Map nowDataMap = new HashMap(); + nowDataMap.put(REPEAT_PARAMS, nowParams); + nowDataMap.put(REPEAT_TIME, System.currentTimeMillis()); + + // 请求地址(作为存放session的key值) + String url = request.getRequestURI(); + + HttpSession session = request.getSession(); + Object sessionObj = session.getAttribute(SESSION_REPEAT_KEY); + if (sessionObj != null) + { + Map sessionMap = (Map) sessionObj; + if (sessionMap.containsKey(url)) + { + Map preDataMap = (Map) sessionMap.get(url); + if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap)) + { + return true; + } + } + } + Map sessionMap = new HashMap(); + sessionMap.put(url, nowDataMap); + session.setAttribute(SESSION_REPEAT_KEY, sessionMap); + return false; + } + + /** + * 判断参数是否相同 + */ + private boolean compareParams(Map nowMap, Map preMap) + { + String nowParams = (String) nowMap.get(REPEAT_PARAMS); + String preParams = (String) preMap.get(REPEAT_PARAMS); + return nowParams.equals(preParams); + } + + /** + * 判断两次间隔时间 + */ + private boolean compareTime(Map nowMap, Map preMap) + { + long time1 = (Long) nowMap.get(REPEAT_TIME); + long time2 = (Long) preMap.get(REPEAT_TIME); + if ((time1 - time2) < (this.intervalTime * 1000)) + { + return true; + } + return false; + } +}