• SpringBoot实现表单重复提交检测


    前言

    在实际开发过程中,web应用经常会出现网络延迟,接口处理时间略长,用户习惯等原因造成的客户连续多次点击提交按钮调用接口,导致数据库会出现重复数据或这接口业务逻辑bug等问题

    方案

    利用redis锁实同一个用户同一个请求2秒内重复提交返回错误路由

    SubmitLock

    标记需要拦截的方法

    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    public @interface SubmitLock {
        int expire() default 2;
    }
    

    RedisLockUtil

    redis锁校验及写入

    @Component
    public class RedisLockUtil {
        @Autowired
        private RedisUtil redisUtil;
    
        private int lockDBIndex = 1;
    
        public boolean lock(String key,String clientID,int lockExpire){
           if(redisUtil.isValid(key,lockDBIndex)){
                return false;
           }else{
               redisUtil.redisTemplateSet(key,clientID,lockDBIndex);
               redisUtil.setExpire(key,lockExpire, TimeUnit.SECONDS,lockDBIndex);
               return true;
           }
        }
    }
    

    RepeatSubmitAspect

    统一拦截切面

    @Aspect
    @Component
    @Order(value = 100)
    public class RepeatSubmitAspect {
        private static Logger logger = LoggerFactory.getLogger(RepeatSubmitAspect.class);
        @Autowired
        private RedisLockUtil redisLockUtil;
    
        /**
         * 切面点 指定注解
         */
        @Pointcut("@annotation(com.haopan.frame.common.annotation.SubmitLock) " +
                "|| @within(com.haopan.frame.common.annotation.SubmitLock)")
        public void repeatSubmitAspect() {
    
        }
    
        /**
         * 拦截方法指定为 repeatSubmitAspect
         */
        @Around("repeatSubmitAspect()")
        public Object around(ProceedingJoinPoint point) throws Throwable {
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
            SubmitLock submitLock = method.getAnnotation(SubmitLock.class);
            if (submitLock != null) {
                ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                HttpServletRequest request = requestAttributes.getRequest();
                String token = request.getHeader("token");
                if (!StringUtil.isEmpty(token)) {
                    String path = request.getServletPath();
                    String key = "submitLock|" + token + "|" + path;
                    String clientId = CommonUtil.getNewGuid();
                    if (redisLockUtil.lock(key, clientId, submitLock.expire())) {
                        // 获取锁成功
                        return point.proceed();
                    } else {
                        System.out.println("tryLock fail, key = ["+key+"]");
                        return Result.errorResult().setMsg("重复请求,请稍后再试").setCode(-980);
                    }
                } else {
                    return point.proceed();
                }
            } else {
                return point.proceed();
            }
        }
    }
    
  • 相关阅读:
    java接口
    java抽象类的特点
    java中的继承
    java中的exception模块
    java中的抽象类abstract
    java多态的案例
    iPhone开发重构:固化条件判断【转】
    服务器负载分析及问题排查
    tidb数据库
    TIDB数据库下载
  • 原文地址:https://www.cnblogs.com/yanpeng19940119/p/15202095.html
Copyright © 2020-2023  润新知