AOP + Redis实现防止表单重复提交(注解方式)

本文介绍如何在SpringBoot项目中引入AOP并利用Redis实现防止表单重复提交的功能。通过创建自定义注解@FormLock和AOP切面,可在指定方法上避免短时间内重复提交表单,提高系统稳定性和用户体验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 引入SpringAOP
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
  • 配置redis,并创建redis工具类

               redis配置此处略过

@Service
@Slf4j
public class RedisService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    public boolean existKey(String key) {
        log.debug("existKey().params:" + key);
        return stringRedisTemplate.hasKey(key);
    }

    public Boolean delKey(String key) {
        log.debug("delKey().params:" + key);
        Boolean delete = stringRedisTemplate.delete(key);
        return delete;
    }

    public boolean addString(String key, String value) {
        BoundValueOperations<String, String> ops = stringRedisTemplate.boundValueOps(key);
        try {
            ops.set(value);
            return true;
        } catch (Exception e) {
            log.error("redis添加异常." + e.getMessage(), e);
            e.printStackTrace();
            return false;
        }
    }

    public boolean addString(String key, String value, long timeout, TimeUnit timeUnit) {

        BoundValueOperations<String, String> ops = stringRedisTemplate.boundValueOps(key);
        try {
            ops.set(value, timeout, timeUnit);
            return true;
        } catch (Exception e) {
            log.error("redis添加异常." + e.getMessage(), e);
            e.printStackTrace();
            return false;
        }
    }
}
  • 创建注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FormLock {

    /**
     * 指定时间内不可重复提交,单位毫秒
     * @return
     */
    long timeout() default 3000;

}
  • 创建AOP环绕通知处理类
@Slf4j
@Aspect
@Component
public class FormLockAspect {

    @Autowired
    private RedisService redisService;

    @Pointcut("@annotation(com.wetran.codex.business.avoid_repetition.AFormLock)")
    public void reqLock() {
    }

    /**
     * @param point
     */
    @Around("reqLock()")
    public Object constructionSite(ProceedingJoinPoint point) throws Throwable {

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        //获取注解
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        //目标类、方法
        String className = method.getDeclaringClass().getName();
        String methodName = method.getName();
        //由于使用方法名+用户ID创建的Key,,,必须要有用户id参数
        Long userId = Long.parseLong(request.getParameter("id"));
        log.info("防止表单重复提交类:{}. 方法:{}.用户ID:{}.", className, methodName, userId);
        String key = RedisConstants.BLACKlIST_LOCK_KEY + methodName + ":" + userId;

        FormLock formLock = method.getAnnotation(FormLock.class);
        long timeout = formLock.timeout();
        if (timeout < 0) {
            //过期时间3000毫秒
            timeout = 3000;
        }
        //校验该方法该用户的key是否存在,存在直接返回错误
        if (redisService.existKey(key)) {
            return RespUtils.fail("请勿重复提交");
        }
        boolean b = redisService.addString(key, DateUtils.getNow(), timeout, TimeUnit.MILLISECONDS);
        log.info("创建锁结果:{}. key:{}.", b, key);
        //执行方法
        Object object = point.proceed();

        //整理施工现场
        Boolean aBoolean = redisService.delKey(key);
        log.info("删除redis锁结果:{}.", aBoolean);
        return object;
    }
}

redis有效时间根据自身业务需求进行调整即可

在需要防止表单重复提交的方法上添加@FormLock注解即可,可根据不同方法指定相应的有效时间

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值