目录:
你是否在做项目时遇到过以下情况:
- DTO(数据传输对象)与Entity之间的转换:在Java的Web应用中,通常不会直接将数据库中的Entity实体对象返回给前端。而是会创建一个DTO对象,这个DTO对象只包含需要返回给前端的字段。此时,就需要将Entity转换为DTO。
- 复杂对象的映射:当需要映射的对象包含大量的字段,或者字段之间存在复杂的依赖关系时,手动编写映射代码不仅繁琐,而且容易出错。
1.为什么选择MapStruct
1.1.常见的属性映射方法
一般来说,不使用MapStruct框架进行属性映射,常有的方法以下两种:
- Getter/Setter方法手动映射
这种方法最朴素,手动编写代码将源对象的属性存入目标对象,需要注意实体类中嵌套属性的判空操作以防止空指针异常。
- BeanUtils.copyProperties()方法进行映射
BeanUtils
底层使用的是反射机制实现属性的映射。反射是一种在运行时动态获取类信息、调用方法或访问字段的机制,无法利用JVM的优化机制,因此通常比直接方法调用慢得多。
此外,BeanUtils
只能同属性映射,或者在属性相同的情况下,允许被映射的对象属性少;但当遇到被映射的属性数据类型被修改或者被映射的字段名被修改,则会导致映射失败。
1.2.MapStruct的优势
MapStruct是一个基于注解的Java代码生成器,它通过分析带有@Mapper注解的接口,在编译时自动生成实现该接口的映射器类。这个映射器类包含了用于执行对象之间映射的具体代码。
与常规方法相比,MapStruct具备的优势有:
-
简化代码。对于对象内属性较多的情况,使用MapStruct框架无须手动对每个属性进行get/set和属性判空操作。MapStruct可以通过注解和映射接口来定义映射规则,自动生成映射代码,从而大大简化了这种复杂对象的映射过程。
-
性能优越。相较于反射这种映射方法,MapStruct在编译期生成映射的静态代码,可以充分利用JVM的优化机制,对于企业级的项目应用来说,这种方式能大大提高数据复制的性能。
-
类型安全。由于MapStruct在编译期生成映射代码,这意味着如果源对象和目标对象的映射存在错误,那么可以在编译时就发现错误。相比之下,BeanUtils在运行时使用反射来执行属性复制,这可能会导致类型不匹配的问题在运行时才发现。
-
灵活映射。MapStruct可以轻松处理嵌套对象和集合的映射。对于嵌套对象,MapStruct可以递归地应用映射规则;对于集合,MapStruct可以自动迭代集合中的每个元素并应用相应的映射规则。
有开发者对比过两者的性能差距,如下表。这充分体现了MapStruct性能的强大。
对象转换次数
属性个数
BeanUtils耗时
MapStruct耗时
5千万次
6
14秒
1秒
5千万次
15
36秒
1秒
5千万次
25
55秒
1秒
2.MapStruct快速入门
在快速入门中,我们的任务是将dto的数据复制到实体类中。
2.1.导入Maven依赖
<!-- https://mvnrepository.com/artifact/org.mapstruct/mapstruct -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.4.2.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mapstruct/mapstruct-processor -->
<dependency>
<groupId>org.mapstruct</grou