JAVA打怪升级-反射比较对象属性和属性值

JAVA打怪升级-反射比较对象属性和属性值

       最近开发遇到一个比较相同对象的同一字段的属性值,然后将对象的两次变化数据保存到数据库中的需求,这个对象实体字段比较多,而且包含的实体对象也很多,如果只是简单的写代码把两个对象需要的字段手动比较,那么则会有大量的冗余代码。同时,如果将记录日志写到原来的业务逻辑代码中,那么也会破坏原有的代码结构,而且也不利于后期的需求新增和代码修改。

       我这里只讲解通过工具类比较相同对象的相同属性的值,然后将数据差异展现出来,同时参数还支持特定字段比较,以及忽略某些比较字段。

PropertyModelInfo

@Getter
@NoArgsConstructor
@AllArgsConstructor
public class PropertyModelInfo implements Serializable {

    private String propertyName;

    private Object value;

    private Class<?> returnType;

}

ModifiedPropertyInfo

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class ModifiedPropertyInfo implements Serializable {

    private String propertyName;

    private Object oldValue;

    private Object newValue;

}

CompareUtil

/**
 * 对象比较工具类
 *
 * @version 0.1.0
 * @create 2020-12-09 14:32
 * @since 0.1.0
 **/
@Log4j2
public class CompareUtil {

    /**
     * 比较两个对象属性值是否相同,如果不同返回修改过的属性信息集合,包括:字段名,原始数据值,新值
     *
     * @param oldObj       原始对象
     * @param newObj       新对象
     * @param ignoreFields 忽略比较字段,如果忽略比较字段和记录比较字段中都有相同字段,则忽略比较字段优先级较高
     * @param recordFields 记录比较字段
     * @return 变化后的数据集合
     * @version 0.1.0
     * @date 2020/12/9 14:34
     * @since 0.1.0
     */
    public static <T> List<ModifiedPropertyInfo> compareProperty(
            @NonNull T oldObj,
            @NonNull T newObj,
            List<String> ignoreFields,
            List<String> recordFields
    ) {
        // 通过反射获取原始对象的属性名称、getter返回值类型、属性值等信息
        List<PropertyModelInfo> oldObjectPropertyValue = getObjectPropertyValue(oldObj, ignoreFields, recordFields);
        // 通过反射获取新对象的属性名称、getter返回值类型、属性值等信息
        List<PropertyModelInfo> newObjectPropertyValue = getObjectPropertyValue(newObj, ignoreFields, recordFields);

        // 定义修改属性值接收器集合,包括:字段名,原始数据值,新值
        List<ModifiedPropertyInfo> modifiedPropertyInfos = new ArrayList<>(oldObjectPropertyValue.size());

        // 获取新对象所有属性、属性值
        Map<String, Object> newObjectInfoMap = getObjectPropertyAndValue(newObjectPropertyValue);
        // 获取原始对象所有属性、属性值
        Map<String, Object> oldObjectInfoMap = getObjectPropertyAndValue(oldObjectPropertyValue);

        // 处理原始对象数据内容并和新对象的属性、属性值比较
        for (Map.Entry<String, Object> oldInfoMap : oldObjectInfoMap.entrySet()) {
            String oldKey = oldInfoMap.getKey();
            Object oldValue = oldInfoMap.getValue();

            // 比较原始对象和新对象之间的属性和属性值差异
            if (newObjectInfoMap.containsKey(oldKey)) {
                ModifiedPropertyInfo modifiedPropertyInfo = new ModifiedPropertyInfo();
                Object newValue = newObjectInfoMap.get(oldKey);

                if (oldValue != null && newValue != null) {
                    // 初始值和新值不为空比较值
                    if (!oldValue.equals(newValue)) {
                        modifiedPropertyInfo.setPropertyName(oldKey);
                        modifiedPropertyInfo.setOldValue(oldValue);
                        modifiedPropertyInfo.setNewValue(newValue);
                        modifiedPropertyInfos.add(modifiedPropertyInfo);
                    }
                } else if (oldValue == null && newValue == null) {
                    // 如果初始值和新值全部为空不做处理
                } else {
                    // 如果初始值和新值有一个为空
                    modifiedPropertyInfo.setPropertyName(oldKey);
                    modifiedPropertyInfo.setOldValue(oldValue);
                    modifiedPropertyInfo.setNewValue(newValue);
                    modifiedPropertyInfos.add(modifiedPropertyInfo);
                }
            }
        }
        return modifiedPropertyInfos;
    }

    /**
     * 组建对象属性和属性值信息数据
     *
     * @param objectPropertyValue 对象属性和属性值信息
     * @return 对象属性和属性值信息
     * @version 0.1.0
     * @date 2020/12/9 17:25
     * @since 0.1.0
     */
    private static Map<String, Object> getObjectPropertyAndValue(List<PropertyModelInfo> objectPropertyValue) {
        Map<String, Object> objectInfoMap = new HashMap<>(16);
        for (PropertyModelInfo propertyModelInfo : objectPropertyValue) {
            // 对象属性名称
            String propertyName = propertyModelInfo.getPropertyName();
            // 对象属性值
            Object value = propertyModelInfo.getValue();
            objectInfoMap.put(propertyName, value);
        }
        return objectInfoMap;
    }

    /**
     * 通过反射获取对象的属性名称、getter返回值类型、属性值等信息
     *
     * @param obj          对象
     * @param ignoreFields 忽略字段属性集合
     * @param recordFields 比较字段属性集合
     * @return 对象的信息
     * @version 0.1.0
     * @date 2020/12/9 16:49
     * @since 0.1.0
     */
    private static <T> List<PropertyModelInfo> getObjectPropertyValue(
            @NonNull T obj,
            List<String> ignoreFields,
            List<String> recordFields
    ) {
        Class<?> objClass = obj.getClass();
        PropertyDescriptor[] propertyDescriptors = BeanUtils.getPropertyDescriptors(objClass);
        List<PropertyModelInfo> modelInfos = new ArrayList<>(propertyDescriptors.length);

        // 遍历对象属性信息
        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
            String name = propertyDescriptor.getName();
            Method readMethod = propertyDescriptor.getReadMethod();
            // 该字段属性是否被过滤
            boolean isIgnore = ignoreFields == null || !ignoreFields.contains(name);
            // 该字段属性是否必须被比较
            boolean isRecord = recordFields == null || recordFields.contains(name);
            if (readMethod != null && isIgnore && isRecord) {
                try {
                    // 获取数据类型
                    Class<?> returnType = readMethod.getReturnType();
                    // 获取数据值
                    Object invoke = readMethod.invoke(obj);
                    modelInfos.add(new PropertyModelInfo(name, invoke, returnType));
                } catch (IllegalAccessException | InvocationTargetException e) {
                    log.error("反射获取类:" + objClass.getName() + "方法异常:", e);
                }
            }
        }
        return modelInfos;
    }

}

你可能感兴趣的:(JAVA打怪升级,java,反射)