多个源类
有时,单个类不足以构建DTO,我们可能希望将多个类中的值聚合为一个DTO,供终端用户使用。这也可以通过在@Mapping
注解中设置适当的标志来完成。
我们先新建另一个对象 Education
:
public class Education {
private String degreeName;
private String institute;
private Integer yearOfPassing;
// getters and setters or builder
}
然后向 DoctorDto
中添加一个新的字段:
public class DoctorDto {
private int id;
private String name;
private String degree;
private String specialization;
// getters and setters or builder
}
接下来,将 DoctorMapper
接口更新为如下代码:
@Mapper
public interface DoctorMapper {
DoctorMapper INSTANCE = Mappers.getMapper(DoctorMapper.class);
@Mapping(source = "doctor.specialty", target = "specialization")
@Mapping(source = "education.degreeName", target = "degree")
DoctorDto toDto(Doctor doctor, Education education);
}
我们添加了另一个@Mapping
注解,并将其source
设置为Education
类的degreeName
,将target
设置为DoctorDto
类的degree
字段。
如果 Education
类和 Doctor
类包含同名的字段,我们必须让映射器知道使用哪一个,否则它会抛出一个异常。举例来说,如果两个模型都包含一个id
字段,我们就要选择将哪个类中的id
映射到DTO属性中。
子对象映射
多数情况下,POJO中不会只包含基本数据类型,其中往往会包含其它类。比如说,一个Doctor
类中会有多个患者类:
public class Patient {
private int id;
private String name;
// getters and setters or builder
}
在Doctor中添加一个患者列表List
:
public class Doctor {
private int id;
private String name;
private String specialty;
private List<Patient> patientList;
// getters and setters or builder
}
因为Patient
需要转换,为其创建一个对应的DTO:
public class PatientDto {
private int id;
private String name;
// getters and setters or builder
}
最后,在 DoctorDto
中新增一个存储 PatientDto
的列表:
public class DoctorDto {
private int id;
private String name;
private String degree;
private String specialization;
private List<PatientDto> patientDtoList;
// getters and setters or builder
}
在修改 DoctorMapper
之前,我们先创建一个支持 Patient
和 PatientDto
转换的映射器接口:
@Mapper
public interface PatientMapper {
PatientMapper INSTANCE = Mappers.getMapper(PatientMapper.class);
PatientDto toDto(Patient patient);
}
这是一个基本映射器,只会处理几个基本数据类型。
然后,我们再来修改 DoctorMapper
处理一下患者列表:
@Mapper(uses = {PatientMapper.class})
public interface DoctorMapper {
DoctorMapper INSTANCE = Mappers.getMapper(DoctorMapper.class);
@Mapping(source = "doctor.patientList", target = "patientDtoList")
@Mapping(source = "doctor.specialty", target = "specialization")
DoctorDto toDto(Doctor doctor);
}
因为我们要处理另一个需要映射的类,所以这里设置了@Mapper
注解的uses
标志,这样现在的 @Mapper
就可以使用另一个 @Mapper
映射器。我们这里只加了一个,但你想在这里添加多少class/mapper都可以。
我们已经添加了uses
标志,所以在为DoctorMapper
接口生成映射器实现时,MapStruct 也会把 Patient
模型转换成 PatientDto
——因为我们已经为这个任务注册了 PatientMapper
。
显然,除了toDto()
映射方法外,最终实现中还添加了一个新的映射方法——patientListToPatientDtoList()
。这个方法是在没有显式定义的情况下添加的,只是因为我们把PatientMapper
添加到了DoctorMapper
中。
该方法会遍历一个Patient
列表,将每个元素转换为PatientDto
,并将转换后的对象添加到DoctorDto
对象内中的列表中。