链接
简介
首先要编写一个接口, 然后在接口中定义方法, 再在方法上放一些注解, 就可以让 MapStruct 生成一个实现类, 就可以用了.
由于是编译时生成了一个实现类, 所以很快.
- [ 优点 ] 执行快; 自动处理一些东西 ( 字段同名自动映射, 简单类型自动转换 )
- [ 缺点 ] 没找着中文文档;
- [ 场景 ] 一或多个对象生成一个新对象; 将字段拷贝到已有对象中; 深拷贝
依赖
- 与 Lombok 一起用时, 应保证 Lombok 在 MapStruct 之前引入
- 官方文档上有别的处理方案 Reference Guide
<properties>
<mapstruct.version>1.5.5.Final</mapstruct.version>
</properties>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</dependency>
@Mapping 中的一些字段
- target, [ str ] 指定 返回值 中的字段, 可以用
.
代指自己
赋值方式
- constant, [ str ] 用常量赋值
- source, [ str ] 用参数中的字段赋值, 多个参数时可以
参数名.字段
- expression, [ str ] 用表达式赋值, 一般需要套一个
Java()
不常用的东西
- dateFormat, [ str ] 日期格式化字符串, 在此贴上常用值
yyyy-MM-dd HH:mm:ss
- numberFormat, [ str ] 数字格式化字符串, 比如限制两位小数
#.##
, 更多去看 这一节 - ignore, [ bool ] 是否忽略此字段
注入方式
// 方式一, 用工厂创建一个实例对象
MyMapping INSTANCE = Mappers.getMapper(MyMapping.class);
// 方式二, 开启控制反转配置 ( 也就是 @Autowired )
@Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
示例
自定义接口
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
// 注入方式二, 适配 spring 的控制反转
@Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
public interface MyMapping {
// 注入方式一, 用工厂创建一个实例对象
MyMapping INSTANCE = Mappers.getMapper(MyMapping.class);
// 一般不用写 @Mapping, 字段同名则自动映射
Target convert(Source s);
}
在代码中使用刚刚定义的接口
public class Test {
public static void main(String[] args) {
Target t = MyMapping.INSTANCE.convert(new Source("a"));
System.out.println(t); // Target(val=a)
}
}
MapStruct 生成的接口的实现类
import javax.annotation.Generated;
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2024-01-30T16:37:59+0800",
comments = "version: 1.5.5.Final, compiler: javac, environment: Java 11.0.20.1 (Amazon.com Inc.)"
)
public class MyMappingImpl implements MyMapping {
@Override
public Target convert(Source s) {
if ( s == null ) {
return null;
}
Target target = new Target();
target.setVal( s.getVal() );
return target;
}
}
比较奇妙的用法
// 映射到一个已存在的对象上 ( 字段原值会被覆盖 )
// 用 @MappingTarget 指定 target
void convert(Source s, @MappingTarget Target t);
// 深拷贝 ( @Mapping 也支持该方式 )
@Mapper(mappingControl = DeepClone.class)
// 子类型映射 ( 方法返回的是父类型, 使用 @SubclassMapping 指定返回具体哪一个子类型 )
@SubclassMapping( source = AppleDto.class, target = Apple.class )
同层级映射
- 比如, 在 source 向 target 映射时, 想将 source 中的字段 aDTO 转换成 target 中的字段 aVO, 可以单独定义一个 aDTO 到 aVO 的映射, 然后 MapStruct 就会自动识别并使用这个映射
// 不同字段映射
@Mapping(source = "x", target = "y")
// 多参数, 不同字段映射
@Mapping(target = "bId", source = "b.id")
@Mapping(target = "cName", source = "c.name")
A convert(B b, C c);
// 字符串转列表
@Mapping(target = "idList", expression="java(source.getIds().split(\",\"))")
跨层映射
// 将 source 的一个 field 映射到整个 target
@Mapping( target=".", source="source.field" )
// 将整个 source 映射到 target 的一个 field
@Mapping( target="field", source="source" )