疯狂的狮子li
2021-09-18 931ed0eb0036d3505fd0a4bd7b2f1d54c7d5f903
update [重大改动]重写 防重提交实现 使用分布式锁 解决并发问题 压测通过
已添加1个文件
已修改1个文件
已删除2个文件
284 ■■■■■ 文件已修改
ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RepeatSubmitAspect.java 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RepeatSubmitAspect.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,93 @@
package com.ruoyi.framework.aspectj;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.properties.TokenProperties;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.config.properties.RepeatSubmitProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
/**
 * é˜²æ­¢é‡å¤æäº¤
 *
 * @author Lion Li
 */
@Slf4j
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@Aspect
@Component
public class RepeatSubmitAspect {
    private final TokenProperties tokenProperties;
    private final RepeatSubmitProperties repeatSubmitProperties;
    private final LockTemplate lockTemplate;
    // é…ç½®ç»‡å…¥ç‚¹
    @Pointcut("@annotation(com.ruoyi.common.annotation.RepeatSubmit)")
    public void repeatSubmitPointCut() {
    }
    @Before("repeatSubmitPointCut()")
    public void doBefore(JoinPoint point) throws Throwable {
        RepeatSubmit repeatSubmit = getAnnotationRateLimiter(point);
        // å¦‚果注解不为0 åˆ™ä½¿ç”¨æ³¨è§£æ•°å€¼
        long intervalTime = repeatSubmitProperties.getIntervalTime();
        if (repeatSubmit.intervalTime() > 0) {
            intervalTime = repeatSubmit.timeUnit().toMillis(repeatSubmit.intervalTime());
        }
        if (intervalTime < 1000) {
            throw new ServiceException("重复提交间隔时间不能小于'1'秒");
        }
        HttpServletRequest request = ServletUtils.getRequest();
        String nowParams = StrUtil.join(",", point.getArgs());
        // è¯·æ±‚地址(作为存放cache的key值)
        String url = request.getRequestURI();
        // å”¯ä¸€å€¼ï¼ˆæ²¡æœ‰æ¶ˆæ¯å¤´åˆ™ä½¿ç”¨è¯·æ±‚地址)
        String submitKey = request.getHeader(tokenProperties.getHeader());
        if (StringUtils.isEmpty(submitKey)) {
            submitKey = url;
        }
        submitKey = SecureUtil.md5(submitKey + ":" + nowParams);
        // å”¯ä¸€æ ‡è¯†ï¼ˆæŒ‡å®škey + æ¶ˆæ¯å¤´ï¼‰
        String cacheRepeatKey = Constants.REPEAT_SUBMIT_KEY + submitKey;
        LockInfo lock = lockTemplate.lock(cacheRepeatKey, intervalTime, intervalTime / 2);
        if (lock == null) {
            throw new ServiceException("不允许重复提交,请稍后再试!");
        }
    }
    /**
     * æ˜¯å¦å­˜åœ¨æ³¨è§£ï¼Œå¦‚果存在就获取
     */
    private RepeatSubmit getAnnotationRateLimiter(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        if (method != null) {
            return method.getAnnotation(RepeatSubmit.class);
        }
        return null;
    }
}
ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java
@@ -1,52 +1,35 @@
package com.ruoyi.framework.config;
import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
 * é€šç”¨é…ç½®
 *
 * @author ruoyi
 * @author Lion Li
 */
@Configuration
public class ResourcesConfig implements WebMvcConfigurer
{
    @Autowired
    private RepeatSubmitInterceptor repeatSubmitInterceptor;
public class ResourcesConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry)
    {
    }
    /**
     * è‡ªå®šä¹‰æ‹¦æˆªè§„则
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry)
    {
        registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**");
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
    }
    /**
     * è·¨åŸŸé…ç½®
     */
    @Bean
    public CorsFilter corsFilter()
    {
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        // è®¾ç½®è®¿é—®æºåœ°å€
        config.addAllowedOriginPattern("*");
        config.addAllowedOriginPattern("*");
        // è®¾ç½®è®¿é—®æºè¯·æ±‚头
        config.addAllowedHeader("*");
        // è®¾ç½®è®¿é—®æºè¯·æ±‚方法
ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java
ÎļþÒÑɾ³ý
ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java
ÎļþÒÑɾ³ý