自学内容网 自学内容网

JAVA 使用反射比较对象属性的变化,记录修改日志。使用注解【策略模式】,来进行不同属性枚举值到中英文描述的切换,支持前端国际化。

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 {
        @Override
        public Object enConverter(Object value) {
            return value;
        }
    }

    

    
    public static class CarrierLevelType implements ColumnConverter {
        @Override
        public Object enConverter(Object value) {
            return Optional.ofNullable(value)
                    .map(e -> CarrierTypeEnum.getByCode((int) e))
                    .map(CarrierTypeEnum::getEnDesc)
                    .orElse(null);
        }

        @Override
        public Object cnConverter(Object value) {
            return Optional.ofNullable(value)
                    .map(e -> CarrierTypeEnum.getByCode((int) e))
                    .map(CarrierTypeEnum::getDescription)
                    .orElse(null);
        }
    }


    /**
     * 结果集转换器
     * 将<转换为&lt; (前端要求)
     */
    public static class OperationDescResultConverter implements ColumnConverter {
        @Override
        public Object enConverter(Object value) {
            return ((String) value).replaceAll(KeyboardSpecialCharConstants.LESS, KeyboardSpecialCharConstants.LESS_ESCAPING);
        }
    }


    public static class BusinessStatusType implements ColumnConverter {
        @Override
        public Object enConverter(Object value) {
            return Optional.ofNullable(value)
                    .map(e -> BusinessStatusEnum.getByCode((int) e))
                    .map(BusinessStatusEnum::getValue)
                    .orElse(null);
        }

        @Override
        public 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 {
        @Override
        public Object enConverter(Object value) {
            return Optional.ofNullable(value)
                    .map(e -> PriceCheckModeEnum.getEnumByCode((int) e))
                    .map(PriceCheckModeEnum::getModeDescEn)
                    .orElse(null);
        }

        @Override
        public 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 {
        @Override
        public Object enConverter(Object value) {
            return Optional.ofNullable(value)
                    .map(e -> RealPriceCalMethodEnum.getEnumByCode((int) e))
                    .map(RealPriceCalMethodEnum::getMethodDescEn)
                    .orElse(null);
        }

        @Override
        public 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, Object
            obj2, ArrayList<String> cnList, ArrayList<String> enList) {
        try {
            // 解析对象1和对象2的JSONObject
            JSONObject 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);
        }
    }


原文地址:https://blog.csdn.net/IKonwNothing/article/details/145278320

免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!