多个源参数映射
场景:由多个源参数组成一个目标对象
测试数据
源对象:
@Getter
@Setter
@AllArgsConstructor
public class User {
private Long id;
private String name;
private Integer age;
private String nickName;
}
@Getter
@Setter
public class Address {
private String province;
private String city;
private String district;
private String detail;
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Pet {
private Long id;
private String name;
private String color;
}
目标对象:
@Getter
@Setter
@ToString
public class UserDetailDTO {
private Long id;
private String name;
private Integer age;
private String nickName;
private String detail;
}
@Getter
@Setter
@ToString
public class UserDetail2DTO {
private Long id;
private String name;
private Integer age;
private String nickName;
private String detail;
private String petName;
}
应用
- 多个源对象没有相同属性,默认隐式映射多个源对象中的相同属性(对于名称不相同的可以使用@Mapping注解标记)
/**
* 多个源参数转成一个目标对象
* @param user
* @param address
* @return
*/
UserDetailDTO convert(User user, Address address);
结果
@Test
@DisplayName("多个源参数")
void testSeveralSource() {
User user = new User(222L, "小瓜", 2, "瓜瓜");
Address address = new Address();
address.setDetail("江苏省南京市");
UserDetailDTO detail = UserConverter.MAPPER.convert(user, address);
System.out.println(detail); // 结果:UserDetailDTO(id=222, name=小瓜, age=2, nickName=瓜瓜, detail=江苏省南京市)
}
- 如果多个源对象之间存在相同属性名需要被映射,必须用@Mapping指定来自于哪个源对象,例如下面示例源对象User和Pet类型中都存在相同的id,name属性,在被映射到目标对象UserDetail2DTO类型中的id,name时需要指定来自哪个源对象。
定义映射方法:
/**
* 源对象存在相同名称属性
* @param user
* @param address
* @param pet
* @return
*/
@Mapping(source = "pet.name", target = "petName")
@Mapping(source = "user.id", target = "id")
@Mapping(source = "user.name", target = "name")
UserDetail2DTO convert(User user, Address address, Pet pet);
测试结果:
@Test
@DisplayName("多个源参数:源参数存在相同属性")
void testSeveralSource2() {
User user = new User(222L, "小城", 25, "城城");
Address address = new Address();
address.setDetail("江苏省南京市");
Pet pet = new Pet(33L, "地瓜", "白色");
UserDetail2DTO detail = UserConverter.MAPPER.convert(user, address, pet);
System.out.println(detail); // 结果:UserDetail2DTO(id=222, name=小城, age=25, nickName=城城, detail=江苏省南京市, petName=地瓜)
}
- 非bean类型的源对象也可以直接被映射
定义映射方法:
/**
* 非bean对象可以直接映射
* @param user
* @param detail
* @return
*/
UserDetailDTO convert(User user, String detail);
测试结果:
@Test
@DisplayName("多个源参数:非bean类型可直接映射")
void testSeveralSource3() {
User user = new User(222L, "小城", 25, "城城");
UserDetailDTO detail = UserConverter.MAPPER.convert(user, "江苏省镇江市");
System.out.println(detail); // 结果:UserDetailDTO(id=222, name=小城, age=25, nickName=城城, detail=江苏省镇江市)
}
如果多个源对象都是null,则目标对象直接返回null。
映射嵌套源对象
场景:如果源对象是嵌套类型,不想显示地写所有映射关系,可以用 . 代替目标对象,表示从源对象映射每个属性到目标对象。
源对象:
@Getter
@Setter
public class FamilyDTO {
private User user;
private Address address;
}
映射方法:
/**
* 嵌套源对象映射
* @param dto
* @return
*/
@Mapping(target = ".", source = "dto.user")
@Mapping(target = ".", source = "dto.address")
Family convert(FamilyDTO dto);
上面代码表示将FamilyDTO类型中的user,address相同名称属性映射到目标对象中。如果user和address有相同名称则需要显示指定具体属性名称映射关系。
更新已存在的实例对象
在有些更新场景,我们不需要创建一个新的目标对象,而是更新一个已有对象,这时候需要将目标对象用注解@MappingTarget标记并作为一个入参。
示例:
/**
* 更新已存在的实例
*
* @param user
* @param dto
*/
void updateUser(UserDTO dto, @MappingTarget User user);
生成的代码:
@Override
public void updateUser(UserDTO dto, User user) {
if ( dto == null ) {
return;
}
user.setId( dto.getId() );
user.setName( dto.getName() );
user.setAge( dto.getAge() );
user.setNickName( dto.getNickName() );
}
上面代码将UserDTO 对象的值用来更新User对象,该方法返回void,也可以给方法设置一个目标对象类型的返回值,这样更新完目标对象后会将目标对象作为返回值。
/**
* 更新已存在的实例并返回目标对象
*
* @param user
* @param dto
* @return
*/
User updateUser(UserDetailDTO dto, @MappingTarget User user);
生成的代码:
}
@Override
public User updateUser(UserDetailDTO dto, User user) {
if ( dto == null ) {
return null;
}
user.setId( dto.getId() );
user.setName( dto.getName() );
user.setAge( dto.getAge() );
user.setNickName( dto.getNickName() );
return user;
}