You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从Hibernate实体类深拷贝内部对象到DTO?

解决BeanUtils.copyProperties()无法复制嵌套对象的问题

你遇到的这个情况太常见了!默认的BeanUtils.copyProperties()(不管是Spring还是Apache Commons的版本)只会自动复制属性类型完全一致的字段,像address和profile这种嵌套对象,因为AddressEntity和AddressDTO、ProfileEntity和ProfileDTO是不同的类,所以默认不会帮你转换复制。

下面给你两种可行的解决办法:

方法一:手动处理嵌套属性

最简单的方式就是先复制基础属性,再单独对嵌套对象进行转换复制,代码示例如下:

// 先复制基础属性
BeanUtils.copyProperties(studentEntity, studentDTO);

// 手动处理address的转换复制
AddressDTO addressDTO = new AddressDTO();
BeanUtils.copyProperties(studentEntity.getAddress(), addressDTO);
studentDTO.setAddress(addressDTO);

// 手动处理profile的转换复制
ProfileDTO profileDTO = new ProfileDTO();
BeanUtils.copyProperties(studentEntity.getProfile(), profileDTO);
studentDTO.setProfile(profileDTO);

这种方式适合嵌套层级少、字段不多的场景,缺点是如果嵌套对象多了,代码会显得很繁琐。

方法二:编写自定义递归复制工具类

如果你的项目里有很多这种嵌套对象转换的需求,最好写一个通用的工具类,递归处理所有嵌套属性的转换。下面是一个简单的实现示例:

import org.springframework.beans.BeanUtils;
import java.lang.reflect.Field;
import java.util.Objects;

public class CustomBeanCopier {

    public static <T> T copyProperties(Object source, Class<T> targetClass) throws IllegalAccessException, InstantiationException {
        if (source == null) {
            return null;
        }
        // 创建目标对象实例
        T target = targetClass.newInstance();
        // 复制基础属性
        BeanUtils.copyProperties(source, target);

        // 获取源对象的所有字段
        Field[] sourceFields = source.getClass().getDeclaredFields();
        for (Field sourceField : sourceFields) {
            sourceField.setAccessible(true);
            Object sourceValue = sourceField.get(source);
            if (sourceValue == null) {
                continue;
            }
            // 获取目标对象对应的字段
            try {
                Field targetField = targetClass.getDeclaredField(sourceField.getName());
                targetField.setAccessible(true);
                Class<?> targetFieldType = targetField.getType();
                // 判断源字段类型和目标字段类型是否为不同的实体/DTO类型(这里简单判断是否是自定义类,你可以根据实际情况调整)
                if (!sourceField.getType().equals(targetFieldType) && !isBasicType(sourceField.getType())) {
                    // 递归复制嵌套对象
                    Object nestedTarget = copyProperties(sourceValue, targetFieldType);
                    targetField.set(target, nestedTarget);
                }
            } catch (NoSuchFieldException e) {
                // 如果目标类没有对应的字段,跳过
                continue;
            }
        }
        return target;
    }

    // 判断是否是基本类型或包装类、String等常用基础类型
    private static boolean isBasicType(Class<?> clazz) {
        return clazz.isPrimitive() || clazz.equals(String.class) || clazz.equals(Integer.class)
                || clazz.equals(Long.class) || clazz.equals(Double.class) || clazz.equals(Float.class)
                || clazz.equals(Boolean.class) || clazz.equals(Byte.class) || clazz.equals(Short.class);
    }
}

使用这个工具类的方式也很简单:

StudentDTO studentDTO = CustomBeanCopier.copyProperties(studentEntity, StudentDTO.class);

这个工具类会自动递归处理所有嵌套的自定义对象,帮你完成Entity到DTO的转换。

另外,如果你不想自己写工具类,也可以考虑用一些成熟的对象映射框架,比如MapStruct,它可以通过注解自动生成转换代码,性能比BeanUtils更好,不过需要额外引入依赖和配置。

内容的提问来源于stack exchange,提问作者Shakthi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:53:31