先上效果:
在开发过程中,根据枚举值设置中文描述的情景非常常见并且重复性极高、代码可读性差(换个人用老实体写新代码可能就要问一遍枚举对应策略),所以想通过自定义注解来实现自动注入。
只需在属性上加入注解@EnumValueAutoAnnotation(enumClass = TipsStatusEnum.class)
,即可省去重复的set枚举值代码块,一次抒写多次复用。
1 2 3 4 5 6 7 8 9 10
| public class TipsInfoVo implements Serializable { @ApiModelProperty(value = "状态;(0:未提醒,1:已提醒)") @EnumValueAutoAnnotation(enumClass = TipsStatusEnum.class) private Integer status;
@ApiModelProperty(value = "状态-中文描述") private String statusName; ... }
|
1. 自定义注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| import com.tips.ai.domain.enums.EnumValueFieldsConstant; import java.lang.annotation.*;
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(value = {ElementType.FIELD}) public @interface EnumValueAutoAnnotation {
Class<? extends Enum> enumClass();
String fillFieldName() default Strings.EMPTY;
EnumValueFieldsConstant autoValueField() default EnumValueFieldsConstant.desc;
}
|
常量类
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import com.tips.ai.config.annotation.EnumValueAutoAnnotation;
public enum EnumValueFieldsConstant {
code, desc, descText;
}
|
2. aop切面+反射自动填充枚举描述到字段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
| import com.ruoyi.common.utils.StringUtils; import com.tips.ai.config.annotation.EnumValueAutoAnnotation; import com.tips.ai.domain.enums.EnumValueFieldsConstant; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.exception.ExceptionUtils; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component;
import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collection; import java.util.Optional;
@Aspect @Component @Slf4j @SuppressWarnings("all") public class EnumValueAutofillAspect {
@Pointcut("execution(* com.tips.ai.service.*.select*(..)) || execution(* com.tips.ai.service.*.query*(..))") public void handlePlaceholder() { }
@AfterReturning(returning = "returnObject", pointcut = "handlePlaceholder()") public void doAfterReturning(JoinPoint joinPoint, Object returnObject) throws Throwable { if (returnObject == null) { return; } if (returnObject instanceof Collection) { Collection ListValue = (Collection) returnObject; for (Object v : ListValue) { fillEnumNameField(v); } } else { fillEnumNameField(returnObject); } }
private void fillEnumNameField(Object object) { if (object == null) { return; } Field[] fields = object.getClass().getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); try { Object value = field.get(object); if (value instanceof Collection) { try { Collection collection = (Collection) value; collection.forEach(s -> fillEnumNameField(s)); } catch (SecurityException e) { log.error("(Collection) value error: {}", ExceptionUtils.getFullStackTrace(e)); } } if (field.getAnnotations().length < 1 || value == null) { continue; } EnumValueAutoAnnotation enumValueAutoAnnotation = field.getDeclaredAnnotation(EnumValueAutoAnnotation.class); if (enumValueAutoAnnotation == null) { continue; } log.debug("开始自动填充枚举值 field: {}.{}", object.getClass(), field.getName()); reflectFindAndFillEnumName(object, field, enumValueAutoAnnotation); } catch (Exception e) { log.error("enum name auto fill error: {}", ExceptionUtils.getFullStackTrace(e)); } } }
private void reflectFindAndFillEnumName(Object object, Field field, EnumValueAutoAnnotation enumValueAutoAnnotation) throws Exception { Object value = field.get(object); Class<? extends Enum> enumClass = enumValueAutoAnnotation.enumClass(); Method valuesMethod = enumClass.getMethod("values"); Object[] enums = (Object[]) valuesMethod.invoke(null); for (Object e : enums) { Field codeField = e.getClass().getDeclaredField(EnumValueFieldsConstant.code.name()); codeField.setAccessible(true); if (codeField.get(e).equals(value)) { Field descTextField = e.getClass().getDeclaredField(enumValueAutoAnnotation.autoValueField().name()); descTextField.setAccessible(true); Object descTextValue = descTextField.get(e); String fillFieldName = StringUtils.isNotBlank(enumValueAutoAnnotation.fillFieldName()) ? enumValueAutoAnnotation.fillFieldName() : field.getName() + "Name"; Optional<Field> fieldOptional = Arrays.stream(object.getClass().getDeclaredFields()) .filter(s -> StringUtils.equals(s.getName(), fillFieldName)) .findFirst(); if (!fieldOptional.isPresent()) { log.error("枚举值填充属性{}不存在", fillFieldName); continue; } Field enumNameField = object.getClass().getDeclaredField(fillFieldName); enumNameField.setAccessible(true); if (!descTextValue.getClass().equals(enumNameField.getType())) { log.warn("枚举值填充属性{}类型{}无法转换到枚举类型{},请更改为枚举类型一致的类型", fillFieldName, descTextValue.getClass().getSimpleName(), enumNameField.getType().getSimpleName()); continue; } if (enumNameField.get(object) == null) { enumNameField.set(object, descTextValue); } } } }
}
|
3. 在方法返回实体类的属性加上自定义注解
3.1 简约使用方法
1 2 3 4 5 6 7 8 9 10
| public class TipsInfoVo implements Serializable { @ApiModelProperty(value = "状态;(0:未提醒,1:已提醒)") @EnumValueAutoAnnotation(enumClass = TipsStatusEnum.class) private Integer status;
@ApiModelProperty(value = "状态-中文描述") private String statusName; ... }
|
3.2 指定填充字段
1 2 3 4 5 6 7 8 9 10
| public class TipsInfoVo implements Serializable { @ApiModelProperty(value = "提醒级别-中文描述") @EnumValueAutoAnnotation(enumClass = TipsLevelEnum.class, fillFieldName = "tipsLevelStr") private Integer tipsLevel;
@ApiModelProperty(value = "提醒级别;(0:正常,1:重要,2:紧急)") private String tipsLevelStr; ... }
|