陈昶聿
9 小时以前 2a9c68fe5130227d88b71e8eb57aced6b10d4d91
ruoyi-common/src/main/java/com/ruoyi/common/utils/reflect/ReflectUtils.java
@@ -6,7 +6,13 @@
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.poi.ss.usermodel.DateUtil;
@@ -407,4 +413,166 @@
        }
        return new RuntimeException(msg, e);
    }
    /**
     * 比较两个相同类型对象的所有字段值是否相等
     * 使用反射获取所有字段(包括父类字段),并逐个比较
     *
     * @param obj1 第一个对象
     * @param obj2 第二个对象
     * @return 如果所有字段值都相等返回true,否则返回false
     * *示例1:比较所有字段
     *      *   boolean result = ReflectUtils.equalsAllFields(user1, user2);
     */
    public static boolean equalsAllFields(Object obj1, Object obj2)
    {
        return equalsAllFields(obj1, obj2, new String[]{});
    }
    /**
     * 比较两个相同类型对象的所有字段值是否相等(可排除指定字段)
     * 使用反射获取所有字段(包括父类字段),并逐个比较
     *
     * @param obj1 第一个对象
     * @param obj2 第二个对象
     * @param excludeFields 要排除的字段名称数组
     * @return 如果所有字段值都相等返回true,否则返回false
     * // 示例2:排除分页参数
     *      *   boolean result = ReflectUtils.equalsAllFields(vo1, vo2, "pageNum", "pageSize");
     */
    public static boolean equalsAllFields(Object obj1, Object obj2, String... excludeFields)
    {
        // 两个对象都为null,认为相等
        if (obj1 == null && obj2 == null) return true;
        // 只有一个为null,不相等
        if (obj1 == null || obj2 == null) return false;
        // 如果是同一个对象引用,直接返回true
        if (obj1 == obj2) return true;
        // 类型不同,不相等
        if (!obj1.getClass().equals(obj2.getClass())) return false;
        // 将排除字段转换为Set,便于快速查找
        Set<String> excludeFieldSet = new HashSet<>(Arrays.asList(excludeFields));
        // 获取所有字段(包括父类字段)
        List<Field> allFields = getAllFields(obj1);
        // 逐个比较字段值
        for (Field field : allFields)
        {
            // 跳过排除的字段
            if (excludeFieldSet.contains(field.getName())) continue;
            // 跳过static和transient字段
            if (Modifier.isStatic(field.getModifiers()) || Modifier.isTransient(field.getModifiers()))
            {
                continue;
            }
            try{
                makeAccessible(field);
                Object value1 = field.get(obj1);
                Object value2 = field.get(obj2);
                // 使用Objects.equals进行比较,可以正确处理null值
                if (!Objects.equals(value1, value2))
                {
                    //logger.debug("字段 [{}] 的值不相等: obj1={}, obj2={}", field.getName(), value1, value2);
                    return false;
                }
            }catch (IllegalAccessException e)
            {
                //logger.error("访问字段 [{}] 时发生错误: {}", field.getName(), e.getMessage());
                return false;
            }
        }
        return true;
    }
    /**
     * 获取对象的所有字段(包括父类字段)
     *
     * @param obj 目标对象
     * @return 所有字段的列表
     */
    public static List<Field> getAllFields(Object obj)
    {
        List<Field> allFields = new ArrayList<>();
        Class<?> clazz = obj.getClass();
        // 循环向上遍历父类,获取所有字段
        while (clazz != null && clazz != Object.class)
        {
            Field[] fields = clazz.getDeclaredFields();
            allFields.addAll(Arrays.asList(fields));
            clazz = clazz.getSuperclass();
        }
        return allFields;
    }
    /**
     * 比较两个对象指定字段的值是否相等
     *
     * @param obj1 第一个对象
     * @param obj2 第二个对象
     * @param includeFields 要比较的字段名称数组
     * @return 如果指定字段值都相等返回true,否则返回false
     *
     *   // 示例3:只比较关键字段
     *   boolean result = ReflectUtils.equalsSpecifiedFields(user1, user2, "userId", "userName", "email");
     */
    public static boolean equalsSpecifiedFields(Object obj1, Object obj2, String... includeFields)
    {
        // 两个对象都为null,认为相等
        if (obj1 == null && obj2 == null) return true;
        // 只有一个为null,不相等
        if (obj1 == null || obj2 == null) return false;
        // 如果是同一个对象引用,直接返回true
        if (obj1 == obj2) return true;
        // 类型不同,不相等
        if (!obj1.getClass().equals(obj2.getClass())) return false;
        // 如果没有指定字段,返回true
        if (includeFields == null || includeFields.length == 0) return true;
        // 逐个比较指定字段的值
        for (String fieldName : includeFields)
        {
            Field field = getAccessibleField(obj1, fieldName);
            if (field == null)
            {
                //logger.warn("在 [{}] 中未找到字段 [{}]", obj1.getClass().getName(), fieldName);
                continue;
            }
            try
            {
                makeAccessible(field);
                Object value1 = field.get(obj1);
                Object value2 = field.get(obj2);
                // 使用Objects.equals进行比较,可以正确处理null值
                if (!Objects.equals(value1, value2))
                {
                    //logger.debug("字段 [{}] 的值不相等: obj1={}, obj2={}", fieldName, value1, value2);
                    return false;
                }
            }
            catch (IllegalAccessException e)
            {
                //logger.error("访问字段 [{}] 时发生错误: {}", fieldName, e.getMessage());
                return false;
            }
        }
        return true;
    }
}