应用背景:DO(业务实体对象),DTO(数据传输对象)。在一个成熟的工程中,尤其是现在的分布式系统中,应用与应用之间,还有单独的应用细分模块之后,DO一般不会让外部依赖,这时候需要在提供对外接口的模块里放 DTO 用于对象传输,也即是 DO 对象对内,DTO对象对外,DTO 可以根据业务需要变更,并不需要映射 DO 的全部属性。这种对象与对象之间的互相转换,就需要有一个专门用来解决转换问题的工具,毕竟每一个字段都 get/set 会很麻烦。MapStruct 就是这样的一个属性映射工具,只需要定义一个 Mapper 接口,MapStruct 就会自动实现这个映射接口,避免了复杂繁琐的映射实现。
结论:两个类对象属性拷贝放弃org.springframework.beans下的BeanUtils.copyProperties,采用MapStruct
MapStruct官网地址:https://mapstruct.org/
官方使用文档: https://mapstruct.org/documentation/installation/
使用mapStruct的时候需要先引入下述依赖,当前mapstruct的版本为最新版本1.5.0.Beta1:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<org.mapstruct.version>1.5.0.Beta1</org.mapstruct.version>
</properties>
<dependencies>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.6.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
业务实体对象DO:
import java.util.Date;
/**
* 实体类
*/
public class TbUser {
private Integer id;
private String name;
private Integer age;
private Date createTime;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public TbUser(Integer id, String name, Integer age, Date createTime) {
this.id = id;
this.name = name;
this.age = age;
this.createTime = createTime;
}
}
业务实体对象DTO:
public class UserVo {
private String userName;
private Integer age;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "UserVo{" +
"userName='" + userName + '\'' +
", age=" + age +
'}';
}
}
映射关联类:
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
@Mapper
public interface UserMapper {
UserMapper INSTANCE = Mappers.getMapper( UserMapper.class );
@Mapping(source = "name", target = "userName")
@Mapping(source = "age", target = "age")
UserVo toUserVo(TbUser user);
}
测试类:
import java.util.Date;
import org.junit.Test;
import org.mapstruct.example.test.TbUser;
import org.mapstruct.example.test.UserMapper;
import org.mapstruct.example.test.UserVo;
public class MapperTest {
@Test
public void contextLoads(){
TbUser user = new TbUser(2,"Morris", 5, new Date());
UserVo userVo = UserMapper.INSTANCE.toUserVo(user);
System.out.println(userVo.toString());
}
}
输出结果:
UserVo{userName='Morris', age=5}
特别提示: mapstruct与lombok进行整合的时候会报错,需慎用关联关系
与其它工具类的性能比较测试:
第一种:与spring-beans中的BeanUtils.copyProperties进行比较
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.3.12</version>
</dependency>
测试类:
import java.util.Date;
import org.junit.Test;
import org.mapstruct.example.test.TbUser;
import org.mapstruct.example.test.UserMapper;
import org.mapstruct.example.test.UserVo;
import org.springframework.beans.BeanUtils;
public class MapperTest {
@Test
public void contextLoads1(){
for(int i=1;i<10000;i++){
TbUser user = new TbUser(2,"Morris", 5, new Date());
UserVo userVo = UserMapper.INSTANCE.toUserVo(user);
System.out.println(userVo.toString());
}
}
@Test
public void contextLoads2(){
for(int i=1;i<10000;i++){
TbUser user = new TbUser(2,"Morris", 5, new Date());
UserVo userVo = new UserVo();
userVo.setUserName(user.getName());
BeanUtils.copyProperties(user,userVo);
System.out.println(userVo.toString());
}
}
}
上述测试结果为:使用MapStruct仅仅花费63ms,使用spring-beans时花费了184ms
第二种:与commons-beanutils中的BeanUtils.copyProperties进行比较
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
</dependency>
测试类:
import java.util.Date;
import org.apache.commons.beanutils.BeanUtils;
import org.junit.Test;
import org.mapstruct.example.test.TbUser;
import org.mapstruct.example.test.UserMapper;
import org.mapstruct.example.test.UserVo;
public class CustomerMapperTest {
@Test
public void contextLoads1(){
for(int i=1;i<10000;i++){
TbUser user = new TbUser(2,"Morris", 5, new Date());
UserVo userVo = UserMapper.INSTANCE.toUserVo(user);
System.out.println(userVo.toString());
}
}
@Test
public void contextLoads2() throws Exception{
for(int i=1;i<10000;i++){
TbUser user = new TbUser(2,"Morris", 5, new Date());
UserVo userVo = new UserVo();
userVo.setUserName(user.getName());
BeanUtils.copyProperties(userVo,user);
System.out.println(userVo.toString());
}
}
}
上述测试结果为:使用MapStruct仅仅花费66ms,使用spring-beans时花费了764ms