MapStruct使用教程(三)

357 阅读3分钟

多个源参数映射

场景:由多个源参数组成一个目标对象

测试数据

源对象:

@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;
    }