前言
MapStruct 是一个Java 注解处理器 ,用于生成类型安全的bean映射类。
我们需要做的就是定义一个映射接口,声明映射方法。在编译期间,MapStruct 将生成此接口的实现类。此实现使用简单的 Java 方法调用(getter setter…)在源对象和目标对象之间进行属性映射,没有使用反射或类似的内容。
与手动编写属性映射代码相比,MapStruct 通过生成冗长且易于出错的代码来节省时间。按照约定优于配置,MapStruct 使用合理的默认值(用户没有自定义配置或实现特殊行为)。
与动态映射框架相比,MapStruct 具有以下优点:
- 通过使用普通方法调用而不是反射来快速执行
- 编译时类型安全性:只能映射彼此映射的对象和属性(不能将订单实体意外映射到客户DTO等)。
- 编译期错误报告:
- 映射不完整(并非所有目标属性都被映射)
- 映射不正确(找不到正确的映射方法或类型转换)
引入依赖
项目使用 Maven 构建,其他方式如 Gradle,Ant 等请查考官网 设置
1 | ... |
基本使用
基本映射
要创建映射器,只需定义一个 Java 接口,并使用 org.mapstruct.Mapper 注解:
1 | @Mapper |
该 @Mapper 注解将使用 MapStruct 的代码生成器创建 StudentMapper 接口的实现 StudentMapperImpl,在生成的方法实现中,源类型(例如Staff)的所有可读属性都将被复制到目标类型(例如Student)的相应属性中:
- 当一个属性与其目标实体对应的名称相同时,它将被隐式映射。
- 当属性在目标实体中具有不同的名称时,可以通过
@Mapping注解指定其名称。
StudentMapperImpl.class 反编译如下:
1 | public class StudentMapperImpl implements StudentMapper { |
单元测试如下:
1 | @Test |
多源参数映射
多源参数映射即多对一映射,使用 @Mapping(source = "student.studentName", target = "name") 可以将 student 的 studentName 属性 映射(复制)到 Person 的 name 上,代码如下:
1 | @Mapper |
更新现有Bean
在某些情况下,不需要创建目标类型的新实例,而是更新该类型的现有实例。可以通过为目标对象添加一个参数并将其标记为 @MappingTarget, 其中,person1的同名属性会完全覆盖(更新)person2的同名属性,如下
1 | |
使用依赖注入
这里使用 Spring 容器来介绍 MapStruct 如何使用依赖注入,我们需要通过 Mapper#componentModel 来指定DI 类型,目前支持
default:映射器不使用组件模型,实例通常通过
Mappers.getmapper(类)获取。cdi:生成的映射器是应用程序范围的
cdi bean,可以通过@Inject获取。spring:生成的映射器是一个
spring bean,可以通过@Autowired获取。jsr330:生成的映射器用`@javax.inject.named
和@singleton注释,可以通过@inject` 获取。
实例代码如下:
1 | @Mapper(componentModel = "spring") |
调用其他映射器
虽然我们可以通过 @Mapping 注解来灵活的映射不同实体的属性对应关系,但是遇到日期类型格式化为字符串类型,我们不得不复制粘贴例如 @Mapping(target = "registryDate", dateFormat = "dd.MM.yyyy") 这样的映射关系,有没有什么更为简单通用的实现呢,MapStruct 提供了 Mapper#uses ,我们可以自定义一些高级映射,例如 DateMapper,代码如下:
1 | @Component |
这样就能将 Date registryDate 通过自定义的转换方式转化为 String registryDate。
补充说明
这里补充一些 Mapping的其他用法:
- 忽略映射字段:
@Mapping(target = "gender", ignore = true) - 日期格式化:
@Mapping(target = "registryDate", dateFormat = "dd.MM.yyyy") - 数值格式化:
@Mapping(source = "price", numberFormat = "$#.00") - 表达式映射:
@Mapping(target = "timeAndFormat", expression = "java(new org.sample.TimeAndFormat( s.getTime(), s.getFormat()) - 默认表达式:
@Mapping(target="id", source="sourceId", defaultExpression = "java( UUID.randomUUID().toString() )") - …
其他用法,如有兴趣,可移步 官方文档 。