1.暴露获取幂等token接口,且在此时存储redis、mysql、本地内存等(可根据具体业务场景选择token存储方式)
@Autowired private RedissonClient redissonClient; private String createToken(){ return UUID.randomUUID().toString().replace("-",""); } @GetMapping("/getLdempotentToken") public Response<String> getLdempotentToken(){ RMapCache<String,String> rMapCache = redissonClient.getMapCache(LdempotentAspect.LDEMPOTENT_TONE); String token = createToken(); rMapCache.put(token,token); return Response.ok(token); } 复制代码
2.客户端在请求接口前先获取幂等接口,然后在请求接口前写入请求头中.
key | value |
---|---|
ldempotent_token | ba4b441e75f2449792fce5eb0ccfa2ab |
3.利用spring aop技术代码需要处理幂等接口。在执行接口之前验证客户端请求头中的幂等token,验证成功则删除token,验证失败则直接返回错误信息.
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Ldempotent { } 复制代码
@Slf4j @Component @Aspect public class LdempotentAspect { public static final String LDEMPOTENT_TONE = "ldempotent_token"; @Autowired private RedissonClient redissonClient; @Pointcut("@annotation(com.fast.family.framework.core.redis.ldempotent.Ldempotent)") public void pointcut(){} @Around("pointcut()") public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { String token = Optional.ofNullable(WebUtils.getRequestHeader(LDEMPOTENT_TONE)) .orElseThrow(() -> new LdempotentException(ResponseCode.LDEMPOTENT_ERROR.getCode() ,ResponseCode.LDEMPOTENT_ERROR.getMsg())); RMapCache<String,String> rMapCache = redissonClient.getMapCache(LDEMPOTENT_TONE); Optional.ofNullable(rMapCache.get(token)) .orElseThrow(() -> new LdempotentException(ResponseCode.LDEMPOTENT_ERROR.getCode() ,ResponseCode.LDEMPOTENT_ERROR.getMsg())); rMapCache.remove(rMapCache.get(token));//token一次有效,所以在验证完后需删除 return proceedingJoinPoint.proceed(); } } 复制代码
那么按照上述步骤则可以保证接口幂等性(这种方式除了可以处理接口幂等,还能处理其他问题吗?哈哈哈哈哈哈)