美文网首页
前后端分离防止重复提交

前后端分离防止重复提交

作者: 陈柴盐 | 来源:发表于2020-01-08 14:45 被阅读0次

    Part1.AOP切面

    @Aspect
    @Component
    @Log
    public class NoRepeatSubmitAspect {
    
        @Value("${submitCode.header}")
        private String submitCodeHeader;
    
        @Autowired
        private RedisService redisService;
    
        @Autowired
        private JwtTokenUtil jwtTokenUtil;
    
        @Autowired
        private HttpServletRequest request;
    
    
        @Pointcut("execution(* com..*.controller.*(..))")
        public void noRepeatSubmitPointcut() {
    
        }
    
        @Before("noRepeatSubmitPointcut()")
        public  void submitBefore(JoinPoint point) {
            //用户身份的唯一标识,也可以用session来做到这个
            String token = jwtTokenUtil.getToken(request);
            
            String method = request.getMethod();
    
            /*防止重复提交请求前提是用户属于登录状况,且不是Get和DELETE类型的方法*/
            if (token != null&&!"GET".equals(method)&&!"DELETE".equals(method)) {
    
                /*构建查询重复提交的key值*/
                String servletPath = request.getServletPath();
                final String submitCode = submitCodeHeader+"-"+token + "-" + servletPath;
    
                /*
                //不处理参数不重复的情况,在限定时间内重复发送该请求都判定为重复提交
                boolean exist = redisService.isExist(submitCode);
                if (!exist) {
                    redisService.saveSubmitStatus(submitCode);
                }else{
                    throw new RepeatSubmitException(servletPath);
                }*/
    
                /*处理并发*/
                synchronized(this){
                    /*获取所有传入参数*/
                    String submitParam = JSON.toJSONString(point.getArgs());
                    /*获取存储的参数*/
                    Optional<String> storeSubmitParamOpt = redisService.getSubmitParams(submitCode);
    
                    if (storeSubmitParamOpt.isPresent()) {
                        if (submitParam.equals(storeSubmitParamOpt.get())) {
                            /*传入参数与之前请求携带的参数一致判定为相同请求*/
                            throw new RepeatSubmitException(servletPath);
                        }else{
                            /*参数不一致判定为不同请求*/
                            redisService.saveSubmitStatus(submitCode,submitParam);
                        }
                    }else{
                        /*新请求*/
                        redisService.saveSubmitStatus(submitCode,submitParam);
                    }
                }
            }
    
        }
    
    
    
    
    }
    
    

    Part2.redis存储请求参数

    @Value("${submitCode.expiration}")
        private Long submitExpiration;
    
    @Override
        public void saveSubmitStatus(String submitCode, String submitParam) {
            redisTemplate.opsForValue().set(submitCode,submitParam,submitExpiration,TimeUnit.SECONDS);
        }
    
        @Override
        public Optional<String> getSubmitParams(String submitCode) {
            return Optional.ofNullable((String) redisTemplate.opsForValue().get(submitCode));
        }
    

    Part3.在application.yml配置
    submitCode.header
    submitCode.expiration

    Part4.RepeatSubmitException为自定义异常,最后可用@ExceptionHandler做一个全局的处理

    原创文章,转载请注明出处:https://www.jianshu.com/p/ab486fb5be47

    相关文章

      网友评论

          本文标题:前后端分离防止重复提交

          本文链接:https://www.haomeiwen.com/subject/nfksactx.html