戳蓝字「TopCoder 」关注我们哦!
常见的项目开发,应用与应用之间,还有单独的应用细分模块之后,DO 一般不会让外部依赖,这时候需要在提供对外接口的模块里放 DTO 用于对象传输,也即是 DO 对象对内,DTO对象对外,DTO 可以根据业务需要变更,并不需要映射 DO 的全部属性。MapStruct 就是这样的一个属性映射工具,只需要定义一个 Mapper 接口,MapStruct 就会自动实现这个映射接口,避免了复杂繁琐的映射实现。MapStruct官网地址:https://mapstruct.org。
MapStruct是一种类型安全的bean映射类生成java注释处理器。MapStruct 可以将某种类型的对象映射为另外一种类型,如将某个 DO(业务实体对象) 对象转换为 DTO(数据传输对象),除了单个类转换之外,MapStruct还支持多个类转换成一个类。MapStruc 使用方式比较简单,定义一个映射接口,声明映射方法,配上注解,MapSturct 就会实现此接口。
引入依赖:
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>1.2.0.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.2.0.Final</version>
</dependency>
示例代码如下:
package com.github.skyline;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.mapstruct.*;
import org.mapstruct.factory.Mappers;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
/**
* @author luoxiangnan
* @date 2019-10-16
*/
public class MapStructMain {
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class PersonDO {
private Long id;
private Name name;
private Date date;
private Integer age;
private String innerImportInfo;
@Data
@AllArgsConstructor
public static class Name {
private String firstName;
private String lastName;
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class PersonDTO {
long id; // 对应PersonDO.id,由于是Long转long,所以生成后的代码会自动判断PersonDO.id是否为null
private String firstName; // 对应PersonDO.name.firstName
private String lastName; // 对应PersonDO.name.lastName
private String name; // 对应PersonDO.name字段
private Date date;
private Integer outAge;
private String dateFormat;
private String dateFormat2;
private String innerImportInfo;
@Data
@AllArgsConstructor
public static class Address {
private String address;
}
}
@Mapper
public static interface PersonConverter {
PersonConverter INSTANCE = Mappers.getMapper(PersonConverter.class);
/**
* 基本映射
*/
@Mappings({
@Mapping(target = "name", expression = "java(personDO.getName().getFirstName() + /":/" + personDO.getName().getLastName())"),
@Mapping(source = "name.firstName", target = "firstName"),
@Mapping(source = "name.lastName", target = "lastName"),
@Mapping(target = "dateFormat", expression = "java(org.apache.commons.lang3.time.DateFormatUtils.format(personDO.getDate(), /"yyyy-MM-dd HH:mm:ss/"))"),
@Mapping(source = "date", target = "dateFormat2", dateFormat = "yyyy-MM-dd HH:mm:ss"),
@Mapping(source = "age", target = "outAge"),
@Mapping(target = "innerImportInfo", ignore = true)
})
PersonDTO toPersonDTO(PersonDO personDO);
/**
* 基本映射,映射已有DTO
* @param personDO
* @param personDTO
*/
@InheritConfiguration(name = "toPersonDTO")
void toPersonDTOV2(PersonDO personDO, @MappingTarget PersonDTO personDTO);
List<PersonDTO> toPersonDTOList(List<PersonDO> personDOList);
}
@Mapper
public static interface Two2OneConverter {
Two2OneConverter INSTANCE = Mappers.getMapper(Two2OneConverter.class);
@Data
static class A {
String orderNo = "xxxx";
}
@Data
static class B {
Long skuId = 11111L;
}
@Data
static class C {
String orderNo;
Long skuId;
}
@Mappings({
@Mapping(source = "a.orderNo", target = "orderNo"),
@Mapping(source = "b.skuId", target = "skuId")
})
C toPersonDTO(A a, B b);
}
public static void main(String[] args) {
PersonDO personDO = new PersonDO(1L, new PersonDO.Name("luo", "xiangnan"),
new Date(), 26, "内部机密信息,勿外传");
System.out.println(personDO);
System.out.println(PersonConverter.INSTANCE.toPersonDTO(personDO));
PersonDTO personDTO = new PersonDTO();
PersonConverter.INSTANCE.toPersonDTOV2(personDO, personDTO);
System.out.println(personDTO);
System.out.println(PersonConverter.INSTANCE.toPersonDTOList(Arrays.asList(personDO)));
// 多个类转成单个类
Two2OneConverter.C c = Two2OneConverter.INSTANCE.toPersonDTO(new Two2OneConverter.A(), new Two2OneConverter.B());
System.out.println(c);
}
}
上述代码编译之后,生成2个转换类,如下图:
输出结果为:
MapStructMain.PersonDO(id=1, name=MapStructMain.PersonDO.Name(firstName=luo, lastName=xiangnan), date=Wed Oct 16 21:47:49 CST 2019, age=26, innerImportInfo=内部机密信息,勿外传)
MapStructMain.PersonDTO(id=1, firstName=luo, lastName=xiangnan, name=luo:xiangnan, date=Wed Oct 16 21:47:49 CST 2019, outAge=26, dateFormat=2019-10-16 21:47:49, dateFormat2=2019-10-16 21:47:49, innerImportInfo=null)
MapStructMain.PersonDTO(id=1, firstName=luo, lastName=xiangnan, name=luo:xiangnan, date=Wed Oct 16 21:47:49 CST 2019, outAge=26, dateFormat=2019-10-16 21:47:49, dateFormat2=2019-10-16 21:47:49, innerImportInfo=null)
[MapStructMain.PersonDTO(id=1, firstName=luo, lastName=xiangnan, name=luo:xiangnan, date=Wed Oct 16 21:47:49 CST 2019, outAge=26, dateFormat=2019-10-16 21:47:49, dateFormat2=2019-10-16 21:47:49, innerImportInfo=null)]
MapStructMain.Two2OneConverter.C(orderNo=xxxx, skuId=11111)
上述代码中,我们使用的是直接获取Mapper方法:
PersonConverter.INSTANCE.toPersonDTO(personDO)
除此之外,还可以和 Spring 结合,在 @Mapper 后面加入
componentModel="spring":
@Mapper
public static interface PersonConverter {
//
}
// 代码中直接使用 @Autowired private PersonConverter personConverter; 即可