使用 註解+AOP+redis 實現冪等介面
阿新 • • 發佈:2021-07-26
由於業務需要,會根據入參DTO中的某幾個屬性實現冪等介面,特此記錄.
1.增加註解
ApiIdempotent
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) @Documented public @interface ApiIdempotent { //冪等 /* * 單位 秒 */ long time() default 1; /* * 是否丟擲異常 */ boolean throwEx() default true; }
增加註解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Documented
public @interface ApiIdempotentField {
}
AOP部分邏輯
words to live by !@Aspect @Component @Slf4j public class ApiIdempotentInterceptor { private RedisService redisService; @Pointcut("@annotation(com.sky.common.base.annotation.ApiIdempotent)") public void apiIdempotentPoint() {} @Around(value = "apiIdempotentPoint() && @annotation(apiIdempotent)") public Object methodAround(ProceedingJoinPoint jp,ApiIdempotent apiIdempotent) throws Throwable,IllegalAccessException { Object[] pointArgs = jp.getArgs(); List<Object> logArgs = streamOf(pointArgs) .filter(arg -> (!(arg instanceof HttpServletRequest) && !(arg instanceof HttpServletResponse) && !(arg instanceof MultipartFile))) .collect(Collectors.toList()); String parameter = logArgs.stream().map(o -> { Class<?> declaringClass = o.getClass(); Field[] declaredFields = declaringClass.getDeclaredFields(); String reduce = Arrays.stream(declaredFields).filter(field -> field.isAnnotationPresent(ApiIdempotentField.class)).map(field -> { String value = ""; if (!field.isAccessible()) { field.setAccessible(true); } try { value = String.valueOf(field.get(o)); } catch (Exception e) { log.error("ApiIdempotentInterceptor.methodAround", e); } return field.getName() + " : " + value; }).collect(Collectors.joining(",")); if (StringUtils.isBlank(reduce)) { return JSON.toJSONString(o); } return reduce; }).collect(Collectors.joining(",")); String md5 = Md5Utils.getMD5(parameter); if (!this.redisService.setIfAbsent(md5, 1, apiIdempotent.time())) { if (apiIdempotent.throwEx()) { throw new SkyException("重複操作"); } return ResultMessage.success(); } else { return jp.proceed(); } } public ApiIdempotentInterceptor(RedisService redisService) { this.redisService = redisService; } private static <T> Stream<T> streamOf(T[] array) { return ArrayUtils.isEmpty(array) ? Stream.empty() : Arrays.stream(array); } }