1.首先定義一個接口,接口中有兩個方法,分別是將屬性轉換成英文描述和中文描述。
其實就是將數據庫中記錄的 0? 1 ,轉換成后面的描述
這邊定義了中文轉換為默認方法,是因為有些屬性不需要進行中文轉換,或者該屬性的枚舉值中沒有中文描述,你也可以不定義為默認方法
public interface ColumnConverter {/*** 英文值*/Object enConverter(Object value);/*** 中文值*/default Object cnConverter(Object value) {return enConverter(value);}
}
2.然后我們就可以定義一個類,該類中有很多靜態類【不同的靜態類用于不同屬性的枚舉值轉換】,代碼如下
@Slf4j
public class ColumnStrategy {private final Map<Class<? extends ColumnConverter>, ColumnConverter> converterMap = new HashMap<>();private ColumnStrategy() {}/*** 獲取單例*/public static ColumnStrategy getInstance() {return INSTANCE.Instance;}public ColumnConverter getConverter(Class<? extends ColumnConverter> converterClass) {try {if (converterMap.containsKey(converterClass)) {return converterMap.get(converterClass);}Constructor<? extends ColumnConverter> constructor = converterClass.getConstructor();ColumnConverter columnConverter = constructor.newInstance();converterMap.put(converterClass, columnConverter);return columnConverter;} catch (Exception e) {log.error("構造轉換器對象異常", e);return null;}}public ColumnConverter getDefaultConverter() {ColumnConverter defaultConverter = converterMap.get(AutoConverter.class);if (defaultConverter != null) {return defaultConverter;}AutoConverter autoConverter = new AutoConverter();converterMap.put(AutoConverter.class, autoConverter);return autoConverter;}private static class INSTANCE {private static final ColumnStrategy Instance = new ColumnStrategy();}/*** 默認轉換器*/public static class AutoConverter implements ColumnConverter {@Overridepublic Object enConverter(Object value) {return value;}}public static class CarrierLevelType implements ColumnConverter {@Overridepublic Object enConverter(Object value) {return Optional.ofNullable(value).map(e -> CarrierTypeEnum.getByCode((int) e)).map(CarrierTypeEnum::getEnDesc).orElse(null);}@Overridepublic Object cnConverter(Object value) {return Optional.ofNullable(value).map(e -> CarrierTypeEnum.getByCode((int) e)).map(CarrierTypeEnum::getDescription).orElse(null);}}/*** 結果集轉換器* 將<轉換為< (前端要求)*/public static class OperationDescResultConverter implements ColumnConverter {@Overridepublic Object enConverter(Object value) {return ((String) value).replaceAll(KeyboardSpecialCharConstants.LESS, KeyboardSpecialCharConstants.LESS_ESCAPING);}}public static class BusinessStatusType implements ColumnConverter {@Overridepublic Object enConverter(Object value) {return Optional.ofNullable(value).map(e -> BusinessStatusEnum.getByCode((int) e)).map(BusinessStatusEnum::getValue).orElse(null);}@Overridepublic Object cnConverter(Object value) {return Optional.ofNullable(value).map(e -> BusinessStatusEnum.getByCode((int) e)).map(BusinessStatusEnum::getCnValue).orElse(null);}}public static class PriceCheckType implements ColumnConverter {@Overridepublic Object enConverter(Object value) {return Optional.ofNullable(value).map(e -> PriceCheckModeEnum.getEnumByCode((int) e)).map(PriceCheckModeEnum::getModeDescEn).orElse(null);}@Overridepublic Object cnConverter(Object value) {return Optional.ofNullable(value).map(e -> PriceCheckModeEnum.getEnumByCode((int) e)).map(PriceCheckModeEnum::getModeDesc).orElse(null);}}public static class RealPriceCalType implements ColumnConverter {@Overridepublic Object enConverter(Object value) {return Optional.ofNullable(value).map(e -> RealPriceCalMethodEnum.getEnumByCode((int) e)).map(RealPriceCalMethodEnum::getMethodDescEn).orElse(null);}@Overridepublic Object cnConverter(Object value) {return Optional.ofNullable(value).map(e -> RealPriceCalMethodEnum.getEnumByCode((int) e)).map(RealPriceCalMethodEnum::getMethodDesc).orElse(null);}}}
3.然后我們定義一個注解,該注解用于我們實際進行比較的類中上,具體值是否需要進行枚舉值轉換,以及字段的中英文名稱
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ColumnInfo {/*** 字段中文名*/String cnName() default "";/*** 字段英文名*/String enName() default "";/*** 值轉換器(英文)* 適用于枚舉型轉換*/Class<? extends ColumnConverter> converter() default ColumnStrategy.AutoConverter.class;/*** 是否是用戶數組*/boolean isUserList() default false;
}
4.然后我們就可以在實際需要進行比較的類上加上該注解【需要進行枚舉值轉換的屬性,我們可以在屬性上面的注解中加上converter ,然后注入對應的轉換器即可】,示例代碼如下
@Data
public class DTO {/*** 業務名稱*/@ColumnInfo(cnName = "業務名稱", enName = "Business name")private String bizCode;/*** 國別*/@ColumnInfo(cnName = "國家", enName = "Country")private String country;/*** 國別*/@ColumnInfo(cnName = "到期時間", enName = "Expire time")private String expireTime;/*** 業務狀態*/@ColumnInfo(cnName = "業務狀態", enName = "status", converter = ColumnStrategy.BusinessStatusType.class)private Integer status;/*** 是否校驗價格*/@ColumnInfo(cnName = "是否校驗價格", enName = "Is check price", converter = ColumnStrategy.PriceCheckType.class)private Integer priceCheckMode;}
5.現在就可以直接傳入修改前后的兩個對象,利用反射對其進行修改值的檢測了
//調用示例
getChangeFields(DTO.class, from, to, descCnList, descEnList); //具體方法代碼如下
private void getChangeFields(Class clazz, Object obj1, Objectobj2, ArrayList<String> cnList, ArrayList<String> enList) {try {// 解析對象1和對象2的JSONObjectJSONObject object1 = JSONUtil.parseObj(obj1);JSONObject object2 = JSONUtil.parseObj(obj2);if (object1.isEmpty() || object2.isEmpty()) {return;}// 獲取該類的所有屬性Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {// 設置屬性可訪問field.setAccessible(true);// 獲取屬性名String name = field.getName();ColumnInfo targetColumnInfo = field.getAnnotation(ColumnInfo.class);ColumnConverter columnConverter = getColumnConverter(targetColumnInfo);// 判斷對象1和對象2的屬性數量是否不為0(如果是創建則object2為null)// 判斷對象1和對象2的屬性值是否都不為空(由于有一些屬性始終為null,所以需要過濾掉,不然會空指針異常)Object o1 = object1.get(name);Object o2 = object2.get(name);// 判斷對象1和對象2的屬性值是否不相等if (ObjectUtil.equals(o1, o2)) {continue;}if (Constants.CHECK_CONVERT_FILED.contains(name)) {Object cnFrom = ObjectUtil.isNotEmpty(o1) ? columnConverter.cnConverter(o1) : StringPool.EMPTY;Object cnTo = ObjectUtil.isNotEmpty(o2) ? columnConverter.cnConverter(o2) : StringPool.EMPTY;Object enFrom = ObjectUtil.isNotEmpty(o1) ? columnConverter.enConverter(o1) : StringPool.EMPTY;Object enTo = ObjectUtil.isNotEmpty(o2) ? columnConverter.enConverter(o2) : StringPool.EMPTY;// 添加屬性名到列表中cnList.add(String.format("%s【%s】更新為【%s】", targetColumnInfo.cnName(), cnFrom, cnTo));enList.add(String.format("%s【%s】 changed to 【%s】", targetColumnInfo.enName(), enFrom, enTo));} else {o1 = ObjectUtil.isNotEmpty(o1) ? o1 : StringPool.EMPTY;o2 = ObjectUtil.isNotEmpty(o2) ? o2 : StringPool.EMPTY;if (ObjectUtil.isNotEmpty(targetColumnInfo.cnName())) {cnList.add(String.format("%s【%s】更新為【%s】", targetColumnInfo.cnName(), o1, o2));}if (ObjectUtil.isNotEmpty(targetColumnInfo.enName())) {enList.add(String.format("%s【%s】 changed to 【%s】", targetColumnInfo.enName(), o1, o2));}}}} catch (Exception e) {// 獲取異常信息詳情log.error("---Failed to check attributes---", e);}}