Mapstruct笔记
官方文档:文档
简介
背景:业务场景下会涉及很多的实体模型,如 DO、DTO、PO、VO (理解) 等,不同的模型用于不同的场景,相同领域下的模型在业务代码编写中经常需要进行转换 ( Convert
转换类),由于属性很多,导致转换过程的编写通常很冗长,人工书写容易出错。
上述实体 POJO 介绍参见 文章,贴一张各个模型的场景转换图
mapstruct 就是为了解决此问题而产生,它是一个 Java 注解处理器,用于生成类型安全的模型转换。
使用时所需要做的就是定义一个模型转换器接口 (Mapper
),该接口声明任何必需的转换方法,在编译期间,mapstruct 将生成此接口的实现,属性的转换只涉及 getter/setter
方法,通常与 Lombok
一起使用
简单使用
依赖引入,自己操作时遇到一些坑,注意插件的引入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<mapstruct.version>1.4.2.Final</mapstruct.version>
<lombok.version>1.18.20</lombok.version>
</properties>
<dependencies>
<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>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.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>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>定义同一领域的的各个模型,注意保证 无参构造方法 的存在
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46// DO
public class CoolBoy {
private String name;
private Integer age;
private BigDecimal salary;
/**
* 类型
*/
private Long boyType;
/**
* 存储格式:Mary,May,....
*/
private String girlFriends;
}
// DTO
public class CoolBoyDTO {
private String name;
private Integer age;
private BigDecimal salary;
/**
* 类型,
*/
private BoyTypeEnum boyType;
/**
* 存储格式:Mary, May, ....
*/
private List<String> girlFriends;
}
// VO
public class CoolBoyVO {
private String name;
private Integer age;
private String salary;
private String boyType;
}编写转换接口,(当然也可以说抽象类)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public interface CoolBoyConvert {
CoolBoyConvert INSTANCE = Mappers.getMapper(CoolBoyConvert.class);
CoolBoyDTO coolBoy2CoolBoyDTO(CoolBoy coolBoy);
CoolBoyVO coolBoyDTO2CoolBoyVO(CoolBoyDTO coolBoyDTO);
// 指定映射关系
// 忽略目标项
// 反转
CoolBoyDTO coolBoyVO2CoolBoyDTO(CoolBoyVO coolBoyVO);
default List<String> string2ListString(String girlFriends) {
return new ArrayList<>(Arrays.asList(girlFriends.split(",")));
}
}测试类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34public class CoolBoyConvertTest {
private final CoolBoyConvert convert = CoolBoyConvert.INSTANCE;
public void coolBoy2CoolBoyDTOTest() {
CoolBoy coolBoy = CoolBoy.builder()
.name("张三")
.age(55)
.salary(new BigDecimal(2000))
.boyType(1L)
.girlFriends("李四,王五")
.build();
CoolBoyDTO coolBoyDTO = convert.coolBoy2CoolBoyDTO(coolBoy);
System.out.println(coolBoy);
System.out.println(coolBoyDTO);
}
public void coolBoyDTO2CoolBoyVOTest() {
CoolBoyDTO coolBoyDTO = CoolBoyDTO.builder()
.name("张三")
.age(55)
.salary(new BigDecimal(2000))
.boyType(BoyTypeEnum.COOL)
.girlFriends(Arrays.asList("李四", "王五"))
.build();
CoolBoyVO coolBoyVO = convert.coolBoyDTO2CoolBoyVO(coolBoyDTO);
System.out.println(coolBoyDTO);
System.out.println(coolBoyVO);
}
}
遇到一个很神奇的问题:
前面使用普通 Maven 项目搭建不知道为什么爆
java: Unknown property "xxx" in result type xxx "null"?
然后注释掉转换接口中自定映射注解
@Mapping
,转换出来的对象的所有属性均为 null1
2CoolBoy(name=张三, age=55, salary=2000, boyType=1, girlFriends=李四, 王五)
CoolBoyDTO(name=null, age=null, salary=null, boyType=null, girlFriends=null)把注释去掉,重新跑一下,又正常了
1
2CoolBoy(name=张三, age=55, salary=2000, boyType=1, girlFriends=李四, 王五)
CoolBoyDTO(name=张三, age=55, salary=2000, boyType=COOL, girlFriends=null)很迷幻,不知道是不是自身配置问题。。。。
后续直接跑在 SpringBoot 项目时直接正常运行了。。。
后续的高级用法直接参考官方文档,真香了。。。。
近期使用场景的一些补充
要是用 Spring 容器中一些 Bean 的话,有两种方式
前提需将 componentModel
模式设置为 spring
1 |
在保持原有为接口的状态下,使用工具类,并在
@Mapper
中使用uses
属性引入类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25// 工具类,注入Spring容器
public class TypeConversionWorker {
protected XxxService xxxService;
protected Xxx xxxMethod(Xxx from) {
return xxxService.xxxMethod(source);
}
}
public abstract class PermissionConvert {
XxxDO PO2DO(XxxPO xxxPO);
}升级为抽象类,将转换方法实现在抽象类中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public abstract class PermissionConvert {
protected abstract XxxDO PO2DO(XxxPO xxxPO);
protected XxxService xxxService;
protected Xxx xxxMethod(Xxx from) {
return xxxService.xxxMethod(source);
}
}