对象拷贝(用法)

1. 对象拷贝中常用的工具类

1.1 Apache BeanUtils#copyProperties

特点:

浅拷贝,属性还是指向原本对象的引用
字段名称相同,类型不同无法进行赋值
基本类型字段和引用对象可以映射

        //对象拷贝:将第一个参数对象,拷贝到第二个参数的对象中,第三个参数表示忽略拷贝的内容
        BeanUtils.copyProperties(dishPage,dishDtoPage,"records");


1.2 SpringUtils#copyProperties

特点:

特性同Apache,效率比Apache高
参数位置同Apache不同

    //对象拷贝:将第一个参数对象,拷贝到第二个参数的对象中,第三个参数表示忽略拷贝的内容
        BeanUtils.copyProperties(dishPage,dishDtoPage,"records");

1.3 序列化(JSON)

特点:

性能较低,耗时(序列化-反序列化)
深拷贝
基本类型字段和引用对象可以映射
字段名称相同,类型不同可以赋值(如Long -> String)

1.4 MapStruct(推荐)

特点:

灵活(可自主配置字段映射关系)
可以配置多对一映射关系
效率高,准确(编译器代码生成,源码就是get、set方法)
深拷贝


如果你使用Maven的话,可以通过引入依赖安装MapStruct:

<dependencies>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>${org.mapstruct.version}</version>
    </dependency>
</dependencies>

这个依赖项会导入MapStruct的核心注释。由于MapStruct在编译时工作,并且会集成到像Maven和Gradle这样的构建工具上,我们还必须在<build中/>标签中添加一个插件maven-compiler-plugin,并在其配置中添加annotationProcessorPaths,该插件会在构建时生成对应的代码。

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.5.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${org.mapstruct.version}</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>

情况一:相同字段间的映射

我们先从一些基本的映射开始。我们会创建一个Doctor对象和一个DoctorDto。为了方便起见,它们的属性字段都使用相同的名称:

public class Doctor {
    private int id;
    private String name;
    // getters and setters or builder
}

public class DoctorDto {
    private int id;
    private String name;
    // getters and setters or builder
}

现在,为了在这两者之间进行映射,我们要创建一个DoctorMapper接口。对该接口使用@Mapper注解,MapStruct就会知道这是两个类之间的映射器。

@Mapper
public interface DoctorMapper {
    DoctorMapper INSTANCE = Mappers.getMapper(DoctorMapper.class);
    DoctorDto toDto(Doctor doctor);
}

这段代码中创建了一个DoctorMapper类型的实例INSTANCE,在生成对应的实现代码后,这就是我们调用的“入口”。

我们在接口中定义了toDto()方法,该方法接收一个Doctor实例为参数,并返回一个DoctorDto实例。这足以让MapStruct知道我们想把一个Doctor实例映射到一个DoctorDto实例。

当我们构建/编译应用程序时,MapStruct注解处理器插件会识别出DoctorMapper接口并为其生成一个实现类。

public class DoctorMapperImpl implements DoctorMapper {
    @Override
    public DoctorDto toDto(Doctor doctor) {
        if ( doctor == null ) {
            return null;
        }
        DoctorDtoBuilder doctorDto = DoctorDto.builder();

        doctorDto.id(doctor.getId());
        doctorDto.name(doctor.getName());

        return doctorDto.build();
    }
}

DoctorMapperImpl类中包含一个toDto()方法,将我们的Doctor属性值映射到DoctorDto的属性字段中。如果要将Doctor实例映射到一个DoctorDto实例,可以这样写:

DoctorDto doctorDto = DoctorMapper.INSTANCE.toDto(doctor);

情况二:不同字段间的映射

public class Doctor {
    private int id;
    private String name;
    private String specialty;
    // getters and setters or builder
}

public class DoctorDto {
    private int id;
    private String name;
    private String specialization;
    // getters and setters or builder
}

现在,我们需要让 DoctorMapper 知道这里的不一致。我们可以使用 @Mapping 注解,并设置其内部的 source 和 target 标记分别指向不一致的两个字段。

@Mapper
public interface DoctorMapper {
    DoctorMapper INSTANCE = Mappers.getMapper(DoctorMapper.class);

    @Mapping(source = "doctor.specialty", target = "specialization")
    DoctorDto toDto(Doctor doctor);
}

这个注解代码的含义是:Doctor中的specialty字段对应于DoctorDto类的 specialization 。

编译之后,会生成如下实现代码:

public class DoctorMapperImpl implements DoctorMapper {
    @Override
    public DoctorDto toDto(Doctor doctor) {
        if (doctor == null) {
            return null;
        }

        DoctorDtoBuilder doctorDto = DoctorDto.builder();

        doctorDto.specialization(doctor.getSpecialty());
        doctorDto.id(doctor.getId());
        doctorDto.name(doctor.getName());

        return doctorDto.build();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值