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

前后端分离防止重复提交

作者: 陈柴盐 | 来源:发表于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