使用AOP和註解對DTO中的欄位進行截斷——第一次使用AOP和自定義註解的心得

peterzh6發表於2024-07-05

是騷操作,但是為了應對特殊的需求,實現了透過在方法上應用@TruncateString註解,進入AOP,獲得第一個引數中的DTO,然後獲取DTO中加了@LimitStringLength註解,將欄位修改之後返回。

#AOP中要注意的點:

  1. AOP由Spring管理,所以要生效的話需要加上@Component註解
  2. 可以把註解繫結到一個方法上,然後用這個註解的時候就會呼叫相應的@Around("truncateString()")標註的方法
@Pointcut("@annotation(com.kingstar.ficc.gtms.common.core.annotation.TruncateString)")
    void truncateString() {}
  1. 對於有返回的方法,AOP中的方法需要返回return joinPoint.proceed();不然被AOP攔截的方法返回會為空

自定義註解中要注意的點

  1. public @interface定義了一個註解
  2. 註解中引數用長得像方法一樣的介面定義來接收
    int max(),然後如果沒有default值,會報錯
  3. @Retention
    -RetentionPolicy.SOURCE僅保留在原始檔中
    -RetentionPolicy.CLASS保留至Class中,但執行時被丟棄
    -RetentionPolicy.RUNTIME jvm執行時也會使用該註解
  4. @target:註解可以應用的物件,註解不可以用在入參之中,如果要用在入參之中,需要應用在方法上
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LimitStringLength {

    int max() default Integer.MAX_VALUE; // 預設擷取長度為最大值

}
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TruncateString {

}
@Aspect
@Component
@Slf4j
public class TruncateStringAOP {


    @Pointcut("@annotation(com.kingstar.ficc.gtms.common.core.annotation.TruncateString)")
    void truncateString() {}


    @Around("truncateString()")
    public static Object getSubString(ProceedingJoinPoint joinPoint) throws Throwable {
        Object arg;
        try {
            arg = joinPoint.getArgs()[0];
        } catch (Exception e) {
            log.error("Failed to get argument from joinPoint", e);
            return joinPoint.proceed();
        }

        Field[] fields;
        try {
        fields = arg.getClass().getDeclaredFields();
        log.info("Truncating strings in object of class {}", arg.getClass().getName());
    } catch (Exception e) {
        log.error("Failed to get fields from object", e);
        return joinPoint.proceed();
        }
        try {
            for (Field field : fields) {
                if (field.isAnnotationPresent(LimitStringLength.class)) {
                    field.setAccessible(true); // 允許訪問私有欄位
                    String value = (String) field.get(arg);
                    log.info("Truncating field {} with value {}", field.getName(), value);
                    if (value != null && value.length() > field.getAnnotation(LimitStringLength.class).max()) {
                        String truncatedValue = value.substring(0, field.getAnnotation(LimitStringLength.class).max());
                        field.set(arg, truncatedValue);
                        log.info("Truncated value of field {} to {}", field.getName(), truncatedValue);
                    }
                }
            }
        } catch (Exception e) {
            log.error("Failed to truncate string", e);
            return joinPoint.proceed();
        }
        return joinPoint.proceed();
    }
}

相關文章