接口冪等就是不管客戶端調用服務端接口發起多少次請求,有且只有一次有效。mysql
1.暴露獲取冪等token接口,且在此時存儲redis、mysql、本地內存等(可根據具體業務場景選擇token存儲方式)redis
@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.客戶端在請求接口前先獲取冪等接口,而後在請求接口前寫入請求頭中.spring
key | value |
---|---|
ldempotent_token | ba4b441e75f2449792fce5eb0ccfa2ab |
3.利用spring aop技術代碼須要處理冪等接口。在執行接口以前驗證客戶端請求頭中的冪等token,驗證成功則刪除token,驗證失敗則直接返回錯誤信息.sql
@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();
}
}
複製代碼
那麼按照上述步驟則能夠保證接口冪等性(這種方式除了能夠處理接口冪等,還能處理其餘問題嗎?哈哈哈哈哈哈)bash