当前位置:网站首页>遇到MapStruct后,再也不手写PO,DTO,VO对象之间的转换了
遇到MapStruct后,再也不手写PO,DTO,VO对象之间的转换了
2022-08-04 20:20:00 【51CTO】

介绍
在工作中,我们经常要进行各种对象之间的转换。
PO:persistent object 持久对象,对应数据库中的一条记录
VO:view object 表现层对象,最终返回给前端的对象
DTO:data transfer object数据传输对象,如dubbo服务之间传输的对象
如果这些对象的属性名相同还好,可以用如下工具类赋值
Spring BeanUtils
Cglib BeanCopier
避免使用Apache BeanUtils,性能较差
如果属性名不同呢?如果是将多个PO对象合并成一个VO对象呢?好在有MapStruct神器,可以帮助我们快速转换
在pom文件中加入如下依赖即可
<
dependency
>
<
groupId
>org.mapstruct
</
groupId
>
<
artifactId
>mapstruct-jdk8
</
artifactId
>
<
version
>1.2.0.CR1
</
version
>
</
dependency
>
<
dependency
>
<
groupId
>org.mapstruct
</
groupId
>
<
artifactId
>mapstruct-processor
</
artifactId
>
<
version
>1.2.0.CR1
</
version
>
<
scope
>provided
</
scope
>
</
dependency
>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
对象互转
@Mapper
public
interface
StudentMapper {
StudentMapper
INSTANCE
=
Mappers.
getMapper(
StudentMapper.
class);
@Mappings({
@Mapping(
source
=
"name",
target
=
"studentName"),
@Mapping(
source
=
"age",
target
=
"studentAge")
})
StudentVO
po2Vo(
StudentPO
studentPO);
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 新建一个Mapper接口,上面加上@Mapper注解
- 新建一个成员变量INSTANCE
- 用@Mapping注解指定映射关系,名字相同的就不用再指定了,会自动映射
测试效果如下,名字不同且没有指定映射关系的会被设置为null
@Test
public
void
studentPo2Vo() {
StudentPO
studentPO
=
StudentPO.
builder().
id(
10).
name(
"test")
.
age(
24).
className(
"教室名").
build();
StudentVO
studentVO
=
StudentMapper.
INSTANCE.
po2Vo(
studentPO);
// StudentVO(id=10, studentName=test, studentAge=24, schoolName=null)
System.
out.
println(
studentVO);
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
List互转
@Mapper
public
interface
StudentMapper {
StudentMapper
INSTANCE
=
Mappers.
getMapper(
StudentMapper.
class);
@Mappings({
@Mapping(
source
=
"name",
target
=
"studentName"),
@Mapping(
source
=
"age",
target
=
"studentAge")
})
StudentVO
po2Vo(
StudentPO
studentPO);
List
<
StudentVO
>
poList2VoList(
List
<
StudentPO
>
studentPO);
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
List类型互转的映射规则会用单个对象的映射规则,看测试效果
@Test
public
void
poList2VoList() {
List
<
StudentPO
>
studentPOList
=
new
ArrayList
<>();
for (
int
i
=
1;
i
<=
2;
i
++) {
StudentPO
studentPO
=
StudentPO.
builder().
id(
i).
name(
String.
valueOf(
i)).
age(
i).
build();
studentPOList.
add(
studentPO);
}
List
<
StudentVO
>
studentVOList
=
StudentMapper.
INSTANCE.
poList2VoList(
studentPOList);
// [StudentVO(id=1, studentName=1, studentAge=1, schoolName=null),
// StudentVO(id=2, studentName=2, studentAge=2, schoolName=null)]
System.
out.
println(
studentVOList);
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
多个对象映射一个对象
我们用SchoolPO和StudentPO来映射SchoolStudentVO
测试例子如下
@Test
public
void
mergeVo() {
SchoolPO
schoolPO
=
SchoolPO.
builder().
name(
"学校名字").
build();
StudentPO
studentPO
=
StudentPO.
builder().
name(
"学生名字").
build();
SchoolStudentVO
schoolStudentVO
=
StudentMapper.
INSTANCE.
mergeVo(
schoolPO,
studentPO);
// SchoolStudentVO(schoolName=学校名字, studentName=学生名字)
System.
out.
println(
schoolStudentVO);
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
当然还有其他的骚操作,这里就简单介绍一个比较实用的技巧,有兴趣的可以看官方的example
https://github.com/mapstruct/mapstruct-examples
转换的时候指定方法
当我们想把PersonVO转换为PersonPO,PersonPO中的gender是一个枚举,PersonVO中的gender是一个int类型,如何把枚举转为枚举的value值呢?
在@Mapping注解中通过qualifiedByName属性指定转换的方法
@Mapper
public
interface
StudentMapper {
StudentMapper
INSTANCE
=
Mappers.
getMapper(
StudentMapper.
class);
@Mappings({
@Mapping(
source
=
"gender",
target
=
"gender",
qualifiedByName
=
"convertGender"),
})
PersonPO
vo2Po(
PersonVO
personVO);
@Named(
"convertGender")
default
Integer
convertTargetType(
GenderEnum
genderEnum) {
return
genderEnum.
getValue();
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
测试类如下
实现原理
MapStruct帮你对接口生成了一个实现类,下面就是生成的实现类,从class文件夹中可以看到
public
class
StudentMapperImpl
implements
StudentMapper {
@Override
public
StudentVO
po2Vo(
StudentPO
studentPO) {
if (
studentPO
==
null ) {
return
null;
}
StudentVO
studentVO
=
new
StudentVO();
studentVO.
setStudentAge(
studentPO.
getAge() );
studentVO.
setStudentName(
studentPO.
getName() );
studentVO.
setId(
studentPO.
getId() );
return
studentVO;
}
@Override
public
List
<
StudentVO
>
poList2VoList(
List
<
StudentPO
>
studentPO) {
if (
studentPO
==
null ) {
return
null;
}
List
<
StudentVO
>
list
=
new
ArrayList
<
StudentVO
>(
studentPO.
size() );
for (
StudentPO
studentPO1 :
studentPO ) {
list.
add(
po2Vo(
studentPO1 ) );
}
return
list;
}
@Override
public
SchoolStudentVO
mergeVo(
SchoolPO
schoolPO,
StudentPO
studentPO) {
if (
schoolPO
==
null
&&
studentPO
==
null ) {
return
null;
}
SchoolStudentVO
schoolStudentVO
=
new
SchoolStudentVO();
if (
schoolPO
!=
null ) {
schoolStudentVO.
setSchoolName(
schoolPO.
getName() );
}
if (
studentPO
!=
null ) {
schoolStudentVO.
setStudentName(
studentPO.
getName() );
}
return
schoolStudentVO;
}
@Override
public
PersonPO
vo2Po(
PersonVO
personVO) {
if (
personVO
==
null ) {
return
null;
}
PersonPO
personPO
=
new
PersonPO();
personPO.
setGender(
convertTargetType(
personVO.
getGender() ) );
personPO.
setAge(
personVO.
getAge() );
return
personPO;
}
}
- 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.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
欢迎关注

参考博客
[0]http://www.tianshouzhi.com/api/tutorials/mapstruct
[1]https://www.jianshu.com/p/3f20ca1a93b0
边栏推荐
猜你喜欢
随机推荐
The difference between Client Side Cache and Server Side Cache
六月 致 -.-- -..- -
C#的Dictionary字典集合按照key键进行升序和降序排列
Red5搭建直播平台
QT(41)-多线程-QTThread-同步QSemaphore-互斥QMutex
宏定义小方法
搭建MyCat2一主一从的MySQL读写分离
在vs code中进行本地调试和开启本地服务器
基于Nodejs的电商管理平台的设计和实现
成品升级程序
Nuxt.js的优缺点和注意事项
Latex分章节、分段落编译:input{}与include{}的区别
阿里的arthas使用,入门报错:Unable to attach to 32-bit process running under WOW64
Client Side Cache 和 Server Side Cache 的区别
二叉树是否对称
WIN10系统如何开启终端
The establishment of simple data cache layer
5 g NR notes
Qt Designer生成的图形可以自适应窗口的大小变化
Seata source code analysis: various message processing processes of seata server








