Spring Boot 如何使用 AOP 防止重复提交

在 Spring Boot 中,可以使用 AOP(面向切面编程)来防止重复提交。通过 AOP,可以在方法调用前后添加额外的逻辑,而不需要修改方法本身的代码。下面是一个基于 AOP 的解决方案:

使用 AOP 防止重复提交

步骤:

  1. 定义注解:创建一个自定义注解,用于标记需要防止重复提交的方法。
  2. 编写切面:使用 AOP 切面,在方法调用前检查重复提交的条件。

1. 定义注解

首先,创建一个自定义注解 @NoRepeatSubmit

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 NoRepeatSubmit {
    // 可以定义属性以配置注解,例如设置过期时间等
}

2. 编写切面

然后,编写一个 AOP 切面类,在方法调用前检查请求是否重复提交。

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
public class NoRepeatSubmitAspect {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Around("@annotation(noRepeatSubmit)")
    public Object around(ProceedingJoinPoint joinPoint, NoRepeatSubmit noRepeatSubmit) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        
        // 这里也可以从请求头里取Token,和前端商量好就行。
        String sessionId = request.getSession().getId();
        String uri = request.getRequestURI();
        String key = "no_repeat_submit:" + sessionId + ":" + uri;

        // 这里可以改为用一个分布式锁工具
        Boolean isAbsent = stringRedisTemplate.opsForValue().setIfAbsent(key, "locked", 5, TimeUnit.SECONDS);
        if (Boolean.TRUE.equals(isAbsent)) {
            try {
                return joinPoint.proceed();
            } finally {
                stringRedisTemplate.delete(key);
            }
        } else {
            throw new RuntimeException("重复提交");
        }
    }
}

3. 应用注解

在需要防止重复提交的方法上使用 @NoRepeatSubmit 注解。

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class FormController {

    @NoRepeatSubmit
    @PostMapping("/submitForm")
    public String submitForm() {
        // 处理表单提交逻辑
        return "success";
    }
}

说明

  1. 注解 @NoRepeatSubmit:用于标记需要防止重复提交的方法。
  2. 切面 NoRepeatSubmitAspect:通过 Redis 锁机制来防止重复提交。在方法调用前,生成一个基于 session ID 和请求 URI 的唯一键,尝试获取 Redis 锁,如果获取成功则继续执行方法并在执行完成后释放锁;如果获取失败,则抛出重复提交异常。

注意事项

  1. Redis 配置:确保应用程序中已经配置了 Redis。
  2. 异常处理:可以通过全局异常处理器来捕获和处理重复提交异常。

这种方式适用于单节点和分布式部署的场景,因为 Redis 可以作为一个全局的锁服务,保证分布式环境下的唯一性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

济南大飞哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值