判断两个对象字段内容值工具类

 1.首先创建两个注解来判断字段父子级,因为字段可能会有实体类或者集合

@ChangeParent:父级注解

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

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ChangeParent {
}

@Change:子级注解

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

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Change {

}

2.变更工具类


import cn.hutool.core.collection.CollectionUtil;
import org.springframework.util.CollectionUtils;

import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.*;
import java.util.*;

public class ChangeUtil {

    /**
     * 比较两个相同对象字段值,返回一个差异对象list
     *
     * @param obj1       进行属性比较的对象1
     * @param obj2       进行属性比较的对象2
     * @param ignoreList 选择要比较的属性数组
     * @return {@link List<DataComparisonEntity>}
     */
    public static List<DataComparisonEntity> compareFields(Object obj1, Object obj2, List<DataComparisonEntity> container, List<String> 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) {
                    System.out.println("索引越界:" + " 【对象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)
                        .build();
                container.add(comparisonEntity);
            }
        }
        return container;
    }



    /**
     * 是否不为基本数据类型(包含String);不是基本数据类型返回true
     *
     * @param obj object
     * @return boolean
     */
    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);
    }

    /**
     * 获取要产生变更记录的字段
     * @param clazz 类名
     * @return 字段集合
     */
    public static List<String> checkNoIgnore(Class<?> clazz) {
        // 获取该类所有的公共(public)的字段。
        Field[] fields = clazz.getDeclaredFields();
        // 获取父类
        Class<?> clazzParent = clazz.getSuperclass();
        // 获取父类所有的公共(public)的字段。
        Field[] fieldsParent = clazzParent.getDeclaredFields();
        // 数组转换List
        List<Field> list = new ArrayList<>(Arrays.asList(fields));
        // 将父子类所有字段放置一个集合中
        list.addAll(Arrays.asList(fieldsParent));
        // 比较区别并返回变更记录
        return checkChangeParent(list);
    }

    /**
     * 比较字段集合的变更区别,产生变更记录
     * @param fields 字段
     * @return 变更记录
     */
    public static List<String> checkChangeParent(List<Field> fields) {
        // 创建接收变更字段的集合
        List<String> changeString = new ArrayList<>();
        // 遍历字段
        for (Field field : fields) {
            // 获取每个字段的@ChangeParent注解
            ChangeParent changeParent = field.getAnnotation(ChangeParent.class);
            if (changeParent != null) {
                // 如果该字段有该注解,则添加到changeString中
                changeString.add(field.getName());
                // 获取该字段的类型
                Class<?> clazz = field.getType();
                //若为List对象,获取List的数据类型
                if ("List".equals(clazz.getSimpleName())) {
                    // getGenericType()方法会获取到泛型中的类型 例如获取 "List<String>" 中的 "String"
                    Type type = field.getGenericType();
                    // 如果该类型属于泛型
                    if (type instanceof ParameterizedType) {
                        // 获取该泛型的类型
                        ParameterizedType parameterizedType = (ParameterizedType) type;
                        Type[] typeArgs = parameterizedType.getActualTypeArguments();
                        Class<?> aClass = (Class<?>) typeArgs[0];
                        // 获取泛型中的所有字段,并判断该字段是否为最终字段
                        checkChangeOrChangeParent(changeString, aClass);
                    }
                } else {
                    // 若不为集合则直接获取泛型中的所有字段,并判断该字段是否为最终字段
                    checkChangeOrChangeParent(changeString, clazz);
                }
            }
        }
        return changeString;
    }

    /**
     * 获取泛型中的所有字段,并判断该字段是否为最终字段
     * @param changeString 字段集合
     * @param clazz 类型
     */
    private static void checkChangeOrChangeParent(List<String> changeString, Class<?> clazz) {
        Field[] fields1 = clazz.getDeclaredFields();
        for (Field field1 : fields1) {
            Change change = field1.getAnnotation(Change.class);
            ChangeParent changeParent1 = field1.getAnnotation(ChangeParent.class);
            if (change != null) {
                changeString.add(field1.getName());
            } else if (changeParent1 != null) {
                checkChangeParent(Arrays.asList(field1.getType().getDeclaredFields()));
            }
        }
    }

}

注意:工具类中需引入两个注解的包!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值