java 防止客户端重复调用接口 使用幂等性

中心思想

每次客户端调用接口向redis中存储唯一的key值,执行完添加后删除掉改key值

boolean flag = redisService.setIfAbsent("key值", "标书", 过期时间, 过期时间单位);

如果redis中已经存在 key,则返回fasle
如果redis中没有key,设置key值并返回true

可单独使用,也可在starter公共组件编写统一的注解,通过AOP思想实现,代码如下

引入pom依赖

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
        </dependency>

定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Idempotent {
    String moduleName() default ""; // 模块名称
    long expire() default 3; // 过期时间,默认3秒
}

编写实现的AOP

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Slf4j
@Aspect
@Component
public class IdempotentAspect {

    @Autowired
    private RedisService redisService;

    @Pointcut("@annotation(idempotent)")
    public void idempotentPointcut(Idempotent idempotent) {
    }

    @Around("@annotation(idempotent)")
    public Object around(ProceedingJoinPoint joinPoint, Idempotent idempotent) throws Throwable {
    	// 获取当前登录用户信息
        LoginUser loginUser = UserContextHolder.getCurrentUser();

        // 构造幂等性部分key
        String idempotentKey = idempotent.moduleName() + ":" + loginUser.getId();

        // 获取完整key
        String redisKey = RedisKeyCommonUtils.getIdempotentKey(idempotentKey);

        boolean flag = redisService.setIfAbsent(redisKey , "used", idempotent.expire(), TimeUnit.SECONDS);
        // 检查Redis中是否存在此键
        if (!flag) {
            return Response.failed400("请勿频繁操作!");
        }
        try {
            // 继续执行目标方法
            return joinPoint.proceed();
        } finally {
            // 删除幂等性键
            redisService.deleteObject(redisKey);
        }
    }
}

使用

// 未传入 expire 默认是 3s, 传入则使用传入的值
// @Idempotent(moduleName = "add", expire = 5)
@Idempotent(moduleName = "add")
public Response<?> add(Object obj){
	service.add(obj)
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值