栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java对比两个对象的字段值并记录输出(支持嵌套对象)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java对比两个对象的字段值并记录输出(支持嵌套对象)

java对比两个对象的字段值(支持嵌套对象)
  • 比较两个对象的字段属性值
    • 对比工具类
    • 数据载体对象
    • 注解

比较两个对象的字段属性值

equals的场景可以比较两个对象,但是不能知道具体是那个字段不一致。基于这种场景有了今天要说的这个需求。

我这里是需求是去比较新旧数据的差异,所有会去获取注解值,按照自己的需要去嵌入就可以了。

我这里需要获取获取字段的Swagger注解值去存起来,没有需求的直接把相应的代码删除就好。

参考了之前一个大佬写的,因为之前的不支持嵌套对象,就扩展了一下,去递归调用。
原文地址

对比工具类
package com.maple.springbootenv.util;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.maple.springbootenv.entity.Student;
import io.swagger.annotations.ApiModelProperty;
import org.apache.commons.lang.StringUtils;
import org.springframework.util.CollectionUtils;

import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;


public class ObjectCompareUtil {

    public static void main(String[] args) {
        Student student1 = new Student();
        Student student2 = new Student();

        List compareFields = compareFields(student1, student2, new ArrayList<>(), null);
        System.out.println(JSON.toJSONString(compareFields));

        String formatStr = format(compareFields);

        System.out.println("变更字段:" + formatStr);
    }

    
    public static List compareFields(Object obj1, Object obj2, List container, List ignoreList) {

        // 忽略字段list
        if (CollectionUtils.isEmpty(ignoreList)) {
            ignoreList = new ArrayList<>();
        }

        // 必须为同一对象
        if (obj1.getClass() != obj2.getClass()) {
            throw new RuntimeException("参数1与参数2必须为同一类型对象");
        } else if (obj1 instanceof List && obj2 instanceof List && CollectionUtil.isNotEmpty((List) obj1)) {
            // 字段为List
            for (int i = 0; i < ((List) obj1).size(); i++) {
                try {
                    compareFields(((List) obj1).get(i), ((List) obj2).get(i), container, ignoreList);
                } catch (IndexOutOfBoundsException e) {
                    logInfo("索引越界:" + " 【对象1】:" + obj1 + "; 【对象2】:" + obj2 + "; 【expMessage】:" + e);
                }
            }
            return container;
        }


        // 获取所有属性描述
        Class clazz = obj1.getClass();
        PropertyDescriptor[] propertyDescriptors = new PropertyDescriptor[0];
        try {
            propertyDescriptors = Introspector.getBeanInfo(clazz, Object.class).getPropertyDescriptors();
        } catch (IntrospectionException e) {
            e.printStackTrace();
        }

        // 遍历属性描述符
        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {

            // 当前属性在忽略字段中,忽略比较当前字段
            String fieldName = propertyDescriptor.getName();
            if (ignoreList.contains(fieldName)) {
                continue;
            }

            // 当前字段的get方法
            Method readMethod = propertyDescriptor.getReadMethod();
            // 调用get方法获取obj1当前字段值
            Object fieldValue1 = null;
            // 调用get方法获取obj2当前字段值
            Object fieldValue2 = null;
            try {
                fieldValue1 = readMethod.invoke(obj1);
                fieldValue2 = readMethod.invoke(obj2);
            } catch (IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }

            // 是否为基本数据类型(包含string)【不是基本数据类型继续比较】
            if (notBaseType(fieldValue1) && notBaseType(fieldValue2)) {
                compareFields(fieldValue1, fieldValue2, container, ignoreList);
                continue;
            }

            // 字段值不相同
            if (!Objects.equals(fieldValue1, fieldValue2)) {
                DataComparisonEntity comparisonEntity = DataComparisonEntity.builder()
                        .linkObject(clazz)
                        .filedName(fieldName)
                        .oldValue(fieldValue1)
                        .newValue(fieldValue2)
                        .swaggerNote(getSwaggerNote(clazz, fieldName))
                        .pageFieldName(getPageNote(clazz, fieldName))
                        .build();

                container.add(comparisonEntity);
            }
        }
        return container;
    }


    
    public static String format(List dataComparisonEntityList) {

        final String gap = ":";

        final String end = "; ";

        final String changeChar = " 变更为-> ";

        if (CollectionUtil.isEmpty(dataComparisonEntityList)) {
            return null;
        }

        StringBuilder sb = new StringBuilder();
        for (DataComparisonEntity dataComparisonEntity : dataComparisonEntityList) {
            String changeDescName = gainFieldDesc(dataComparisonEntity);
            sb.append("[");
            sb.append(changeDescName);
            sb.append("]");
            sb.append(gap);
            sb.append(dataComparisonEntity.getOldValue());
            sb.append(changeChar);
            sb.append(dataComparisonEntity.getNewValue());
            sb.append(end);
        }

        sb.setLength(sb.length() - 2);
        return new String(sb);
    }

    private static String gainFieldDesc(DataComparisonEntity entity) {
        String swaggerNote = entity.getSwaggerNote();
        String pageFieldName = entity.getPageFieldName();
        // 有页面注解时直接取页面注解
        if (StringUtils.isNotEmpty(pageFieldName)) {
            return pageFieldName;
        } else if (StringUtils.isNotEmpty(swaggerNote)) {
            return swaggerNote;
        } else {
            return entity.getFiledName();
        }
    }


    
    private static boolean notBaseType(Object obj) {
        if (Objects.isNull(obj)) {
            return false;
        }
        return !(obj instanceof Byte)
                && !(obj instanceof Short)
                && !(obj instanceof Integer)
                && !(obj instanceof Long)
                && !(obj instanceof Float)
                && !(obj instanceof Double)
                && !(obj instanceof Character)
                && !(obj instanceof Boolean)
                && !(obj instanceof String)
                && !(obj instanceof Date);
    }

    
    private static String handlerFieldName(String fieldName) {
        if (StringUtils.isEmpty(fieldName)) {
            return fieldName;
        }

        final char charA = 65;
        final char charZ = 90;
        char firstChar = fieldName.charAt(0);
        char secondChar = fieldName.charAt(1);
        // 第一个字符和第二个字符都是大写,存在问题
        if (firstChar >= charA && firstChar <= charZ && secondChar >= charA && secondChar <= charZ) {
            return fieldName.replace(fieldName.charAt(0), (char) (fieldName.charAt(0) + 32));
        }
        return fieldName;
    }


    
    private static Object getAnnotationValue(Class clazz, String fieldName, Class annotationClass) {
        // 处理问题字段
        fieldName = handlerFieldName(fieldName);

        try {
            Field field = clazz.getDeclaredField(fieldName);

            if (field.isAnnotationPresent(annotationClass)) {
                Annotation annotation = field.getAnnotation(annotationClass);
                try {
                    return annotation.getClass().getDeclaredMethod("value").invoke(annotation);
                } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
                    logInfo("当前注解没有value属性:" + " 【注解类型】:" + annotationClass + "; 【字段名】:" + fieldName + "; 【expMessage】:" + e);
                    return null;
                }
            }
        } catch (NoSuchFieldException e) {
            // 获取父类字段
            Class superClass = clazz.getSuperclass();
            if (superClass == Object.class) {
                logInfo("获取注解value失败:" + "; 【字段名】:" + fieldName + "; 【expMessage】:" + e);
                return null;
            }
            try {
                return getAnnotationValue(superClass, fieldName, annotationClass);
            } catch (Exception exception) {
                logInfo("获取注解value失败:" + " 【对象类型】:" + clazz + "; 【字段名】:" + fieldName + "; 【expMessage】:" + e);
                return null;
            }
        }

        return null;
    }


    
    private static String getSwaggerNote(Class clazz, String fieldName) {
        return (String) getAnnotationValue(clazz, fieldName, ApiModelProperty.class);
    }

    
    private static String getPageNote(Class clazz, String fieldName) {
        return (String) getAnnotationValue(clazz, fieldName, PageNote.class);
    }

    private static void logInfo(String info) {
        System.out.println(info);
    }
}

数据载体对象
package com.maple.springbootenv.util;

import lombok.Builder;
import lombok.Data;


@Data
@Builder
public class DataComparisonEntity {

    
    private String filedName;

    
    private String swaggerNote;

    
    private String pageFieldName;

    
    private Object oldValue;

    
    private Object newValue;

    
    private Class linkObject;
}

注解
package com.maple.springbootenv.util;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface PageNote {

    String value();
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/975469.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号