• 一种轻量级单体springboot防重复提交的解决方案


    一种轻量级单体springboot防重复提交的解决方案

    物料准备

    pom添加依赖

    
    			<dependency>
    				<groupId>net.jodahgroupId>
    				<artifactId>expiringmapartifactId>
    				<version>0.5.10version>
    			dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    定义1个java注解

    package com.xxx.xxx.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface AvoidRepeatableCommit {
    
        /**
         * 指定时间内不可重复提交,单位毫秒
         */
        long timeout() default 3000;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    定义注解对应的切面

    package com.xxx.xxx.annotation;
    
    import cn.hutool.core.util.StrUtil;
    import com.xxx.xxx.exception.BusinessException;
    import net.jodah.expiringmap.ExpirationPolicy;
    import net.jodah.expiringmap.ExpiringMap;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    import org.springframework.web.util.WebUtils;
    
    import javax.servlet.http.HttpServletRequest;
    import java.lang.reflect.Method;
    import java.util.UUID;
    import java.util.concurrent.TimeUnit;
    
    @Aspect
    @Component
    public class AvoidRepeatableCommitAspect {
    
        private static final long TIMEOUT = 3000L;
    
        private static final ExpiringMap<String, String> expiringMap = ExpiringMap.builder()
                .variableExpiration() // 可变有效期,即单独为每个entity设置过期时间和策略
                .expirationPolicy(ExpirationPolicy.CREATED) // 过期策略:CREATED:在每次更新元素时,过期倒计时清零
                .expiration(TIMEOUT, TimeUnit.MILLISECONDS) // 过期时间
                .maxSize(1000) // Map中映射数目超过最大值的大小时,先过期第一个要过期的entity
                .build();
    
        @Around("@annotation(com.xxx.xxx.annotation.AvoidRepeatableCommit)")
        public Object around(ProceedingJoinPoint point) throws Throwable {
    
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
    
            Long account = (Long) WebUtils.getSessionAttribute(request, "cur_userId");
            if (account == null) {
                return point.proceed();
            }
            StringBuffer requestURL = request.getRequestURL();
            String reqMethod = request.getMethod();
            String key = String.format("%s_%s_%s", account, reqMethod, requestURL);
    
            // 获取注解
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
            AvoidRepeatableCommit avoidRepeatableCommit = method.getAnnotation(AvoidRepeatableCommit.class);
            long timeout = avoidRepeatableCommit.timeout();
            if (timeout < 0) {
                timeout = TIMEOUT;
            }
            if (StrUtil.isNotBlank(expiringMap.get(key))) {
                throw new BusinessException("请勿重复提交");
            }
            expiringMap.put(key, UUID.randomUUID().toString(), ExpirationPolicy.CREATED, timeout, TimeUnit.MILLISECONDS);
    
            //执行方法
            return point.proceed();
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    使用案例

    可以在你自定义的Controller类或RestController类里的@RequestMapping 对应的方法上加这个注解

    @AvoidRepeatableCommit(timeout = 1000L)
    
    • 1

    这样被注解标注的api接口就会在请求时被切面处理到,并判断前端是否重复提交了。

  • 相关阅读:
    用GPT 4o提高效率
    【深度学习】实现基于MNIST数据集的TensorFlow/Keras深度学习案例
    linux篇---修改图片权限
    2015-10《信息资源管理 02378》真卷解析,逐题解析+背诵技巧
    SpringBoot中静态变量注入方案,一网打尽
    Shell--常用小工具(sort、uniq、tr、cut)
    软件行业迫切需要基于正向生成的编码模型
    【Kafka】Kafka Producer 分区-05
    零基础安装分布式数据服务注册系统
    企业im即时通讯软件私有化部署,确保信息安全与高效办公
  • 原文地址:https://blog.csdn.net/ThinkPet/article/details/132788222