自定义防重提交切面类AOP

@Pointcut("@annotation(repeatSubmit)")
    public void pointCutNoRepeatSubmit(RepeatSubmit repeatSubmit){}

    @Around("pointCutNoRepeatSubmit(repeatSubmit)")
    public Object around(ProceedingJoinPoint joinPoint,RepeatSubmit repeatSubmit) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

        long accountNo = LoginInterceptor.threadLocal.get().getAccountNo();

        //用于记录成功或者失败
        boolean res =false;

        //防重提交类型
        String type = repeatSubmit.limitType().name();
        if (type.equalsIgnoreCase(RepeatSubmit.Type.PARAM.name())){
            //方式一:参数形式的防重提交 todo
        }else{
            //方式二:令牌形式防重提交
            String requestToken = request.getHeader("request-token");
            if (StringUtils.isBlank(requestToken)){
                throw new BizException(BizCodeEnum.ORDER_CONFIRM_TOKEN_EQUAL_FAIL);
            }
            String key = String.format(RedisKey.SUBMIT_ORDER_TOKEN_KEY,accountNo,requestToken);

            res = redisTemplate.delete(key);
        }
        if (!res){
            throw new BizException(BizCodeEnum.ORDER_CONFIRM_REPEAT);
        }
        Object obj = joinPoint.proceed();
        return obj;
 }

这段代码使用了Spring AOP(面向切面编程)来实现一个防止重复提交的功能。以下是对代码的详细逐行解释:

  1. 定义切点:

    @Pointcut("@annotation(repeatSubmit)")
    public void pointCutNoRepeatSubmit(RepeatSubmit repeatSubmit){}
    
    • @Pointcut: 定义了一个切点,用于匹配所有使用@RepeatSubmit注解的方法。
    • pointCutNoRepeatSubmit: 是切点的名称,它是一个方法签名,该方法接收一个RepeatSubmit注解作为参数。
  2. 环绕通知:

    @Around("pointCutNoRepeatSubmit(repeatSubmit)")
    public Object around(ProceedingJoinPoint joinPoint, RepeatSubmit repeatSubmit) throws Throwable {
    
    • @Around: 表示这是一个环绕通知,它会在目标方法执行前后以及抛出异常时执行。
    • pointCutNoRepeatSubmit(repeatSubmit): 指定了环绕通知绑定的切点表达式,这里使用了上面定义的切点。
    • around: 是环绕通知的方法名,它接收两个参数:joinPointrepeatSubmit
  3. 获取请求对象:

    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    
    • 从Spring的请求上下文中获取当前的HTTP请求对象。
  4. 获取账户编号:

    long accountNo = LoginInterceptor.threadLocal.get().getAccountNo();
    
    • 从自定义的拦截器LoginInterceptor的线程局部变量中获取账户编号。
  5. 定义结果变量:

    boolean res = false;
    
    • 定义一个布尔变量res,用于记录操作是否成功。
  6. 获取防重提交类型:

    String type = repeatSubmit.limitType().name();
    
    • RepeatSubmit注解中获取limitType属性的值,并将其转换为字符串。
  7. 根据类型处理:

    if (type.equalsIgnoreCase(RepeatSubmit.Type.PARAM.name())) {
        // 方式一:参数形式的防重提交
    } else {
        // 方式二:令牌形式防重提交
    
    • 根据limitType的值,选择不同的防重提交方式。
  8. 令牌形式防重提交:

    String requestToken = request.getHeader("request-token");
    if (StringUtils.isBlank(requestToken)) {
        throw new BizException(BizCodeEnum.ORDER_CONFIRM_TOKEN_EQUAL_FAIL);
    }
    String key = String.format(RedisKey.SUBMIT_ORDER_TOKEN_KEY, accountNo, requestToken);
    res = redisTemplate.delete(key);
    
    • 从HTTP请求头中获取request-token
    • 如果请求头中没有request-token,则抛出业务异常。
    • 使用账户编号和request-token构建Redis中的key。
    • 尝试从Redis中删除对应的key,如果删除成功,则res设置为true
  9. 检查操作结果:

    if (!res) {
        throw new BizException(BizCodeEnum.ORDER_CONFIRM_REPEAT);
    }
    
    • 如果resfalse,表示防重提交操作失败,抛出业务异常。
  10. 执行原方法:

    Object obj = joinPoint.proceed();
    
    • 使用joinPoint.proceed()执行原方法,即使用环绕通知的目标方法。
  11. 返回结果:

    return obj;
    
    • 返回原方法的执行结果。

这段代码实现了一个基于AOP的防重提交机制,通过检查HTTP请求头中的令牌或方法参数来防止重复提交。如果检测到重复提交,将抛出异常;否则,允许执行原方法并返回结果。

  • 23
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值