背景
在现在流行的系统设计中,一般会将对象模型划分为多个层次,例如 VO、DTO、PO、BO 等等。这同时也产生了一个问题,经常需要进行不同层级的模型之间相互转换。
针对这种问题,目前常会采用三种方案:
- 调用每个字段的 getter/setter 进行赋值。这个过程,枯燥且乏味,容易出错的同时,极易容易造成代码行数迅速膨胀,可阅读性差。
- apache-commons、Spring 等提供的
BeanUtil
工具类,这种工具类使用非常方便,一行代码即可实现映射。但其内部采用反射的方式来实现映射,性能低下,出现问题时,调试困难,当需要个性化转换时,配置麻烦,非常不建议使用,特别是对于性能要求比较高的程序中。 - mapstruct:这个框架是基于 Java 注释处理器,定义一个转换接口,在编译的时候,会根据接口类和方法相关的注解,自动生成转换实现类。生成的转换逻辑,是基于 getter/setter 方法的,所以不会像
BeanUtil
等消耗其性能。
上面的三种方法中,最优秀的莫属 mapstruct 了,当然,美中不足的就是,当系统较为复杂,对象较多且结构复杂,又或者有的项目设计中会定义多层对象模型(如 DDD 领域设计),需要定义较多的转换接口和转换方法,这也是一些开发者放弃 Mapstruct 的主要原因。
这里,就要给大家介绍一个 Mapstruct 的增强包 —— Mapstruct Plus,一个注解,可以生成两个类之间的转换接口,使 Java 类型转换更加便捷、优雅,彻底抛弃 BeanUtils。
快速开始
下面演示如何使用 MapStruct Plus 来映射两个对象。
假设有两个类 UserDto
和 User
,分别表示数据层对象和业务层对象:
UserDto
public class UserDto {
private String username;
private int age;
private boolean young;
// getter、setter、toString、equals、hashCode
}
User
public class User {
private String username;
private int age;
private boolean young;
// getter、setter、toString、equals、hashCode
}
添加依赖
引入 mapstruct-plus-spring-boot-starter
依赖:
<properties>
<mapstruct-plus.version>1.1.3</mapstruct-plus.version>
</properties>
<dependencies>
<dependency>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-spring-boot-starter</artifactId>
<version>${mapstruct-plus.version}</version>
</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>
<annotationProcessorPaths>
<path>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-processor</artifactId>
<version>${mapstruct-plus.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
指定对象映射关系
在 User
或者 UserDto
上面增加注解 —— @AutoMapper
,并设置 targetType
为对方类。
例如:
@AutoMapper(target = UserDto.class)
public class User {
// ...
}
测试
@SpringBootTest
public class QuickStartTest {
@Autowired
private Converter converter;
@Test
public void test() {
User user = new User();
user.setUsername("jack");
user.setAge(23);
user.setYoung(false);
UserDto userDto = converter.convert(user, UserDto.class);
System.out.println(userDto); // UserDto{username='jack', age=23, young=false}
assert user.getUsername().equals(userDto.getUsername());
assert user.getAge() == userDto.getAge();
assert user.isYoung() == userDto.isYoung();
User newUser = converter.convert(userDto, User.class);
System.out.println(newUser); // User{username='jack', age=23, young=false}
assert user.getUsername().equals(newUser.getUsername());
assert user.getAge() == newUser.getAge();
assert user.isYoung() == newUser.isYoung();
}
}
小结
引入依赖后,使用 Mapstruct Plus 步骤非常简单。
- 给需要转换的类添加
AutoMapper
注解 - 获取
Converter
实例,调用convert
方法即可
特性
完全兼容 Mapstruct
Mapst实现了增强操作,如果之前已经使用了 Mapst