赞
踩
通俗理解,同一个接口用相同参数请求多次,必须保证操作只执行一次。
比如,支付接口因为网络原因或其他因素,导致重复支付,这将导致难以弥补的损失,软件的可靠性也会受到客户质疑。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Idempotent {
/**
* 间隔时间(ms),小于此时间视为重复提交
*/
long interval() default 3000l;
/**
* 提示消息
*/
String message() default "不允许重复提交,请稍候再试";
}
@Aspect @Component @Slf4j public class IdempotentAspect { @Autowired private CacheManager cacheManager; /** * 缓存key */ private final String idempotentCacheKey = "idempotent"; @Pointcut("@annotation(com.xxx.xxx.aspect.idempotent.Idempotent)") public void pointCut() { } @Before("pointCut()") public void checkIsRepeatSubmit(JoinPoint joinPoint) { log.info("********开始幂等性校验********"); MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Idempotent annotation = signature.getMethod().getAnnotation(Idempotent.class); //判断是否重复提交 if (this.isRepeatSubmit(joinPoint.getArgs(), annotation.interval())) { throw new CommonException(annotation.message()); } } /** * 判断是否重复执行 * @param args 请求参数 * @param interval 过期时间 * @return 是否重复执行 */ private boolean isRepeatSubmit(Object[] args, Long interval) { String key = DigestUtil.md5Hex(Arrays.toString(args)); Cache.ValueWrapper valueWrapper = cacheManager.getCache(idempotentCacheKey).get(key); //缓存为空,则认为第一次提交 if (Objects.isNull(valueWrapper)) { cacheManager.getCache(idempotentCacheKey).put(key, System.currentTimeMillis()); return false; } //缓存过期 if (System.currentTimeMillis() >= (Long) valueWrapper.get() + interval) { cacheManager.getCache(idempotentCacheKey).put(key, System.currentTimeMillis()); return false; } return true; } }
验证的方法有很多,使用缓存时一定要设置缓存的过期时间,否则会导致缓存大量的无意义数据。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。