首页 > 其他分享 >使用MapStruct 解决对象之间转换、深拷贝问题

使用MapStruct 解决对象之间转换、深拷贝问题

时间:2022-12-03 23:33:17浏览次数:67  
标签:account 转换 MapStruct Account mapstruct accounts createAccountDTO 拷贝 amt


在日常开发中,我们会定义多种不同的Javabean,比如DTO(Data Transfer Object:数据传输对象),DO(Data Object:数据库映射对象,与数据库一一映射),VO(View Object:显示层对象,通常是 Web 向模板渲染引擎层传输的对象)等等这些对象。在这些对象与对象之间转换通常是调对象的set和get方法进行复制,这种转换通常也是很无聊的操作,如果有一个专门的工具来解决Javabean之间的转换问题,让我们从这种无聊的转换操作中解放出来。

首先梳理出来现在有哪些对象拷贝的方式:

  • 浅拷贝
  • Apache的BeanUtils:​​基于反射实现​​,BeanUtils是Apache commens组件里面的成员,由Apache提供的一套开源api,用于简化对javaBean的操作,能够对基本类型自动转换。
  • Spring的BeanUtils:​​基于反射实现​​,BeanUtils是Spring框架提供的对Java反射和自省API的包装。其主要目的是利用反射机制对JavaBean的属性进行处理。
  • BeanCopier:​​动态代理实现​​​,BeanCopier是Cglib包中的一个类,用于对象的复制。目标对象必须先实例化 而且对象必须要有setter方法。​​由于BeanCopier是动态代理实现所以性能上比前两个要好的多​​。
  • 深拷贝
  • Mapstruct:MapStruct是一个Java注释处理器,用于生成类型安全的bean映射类。MapStruct具有以下优点:
  • 速度快:使用普通的方法代替反射
  • 编译时类型安全性 : 只能映射彼此的对象和属性,不会将商品实体意外映射到用户DTO等

数据量

Apache

Spring

MapStruct

BeanCopier

100w

391ms

250ms

45ms

57ms

10w

82ms

34ms

8ms

10ms

1w

30ms

19ms

2ms

7ms

1k

15ms

6ms

1ms

5ms

100

5ms

3ms

1ms

4ms

10

2ms

1ms

1ms

4ms

根据测试结果,我们可以得出在速度方面,MapStruct是最好的,执行速度是 Apache BeanUtils 的10倍、Spring BeanUtils 的 4-5倍、和 BeanCopier 的速度差不多。
由此可以看出,在大数据量级的情况下,MapStruct 和 BeanCopier 都有着较高的性能优势,其中 MapStruct 尤为优秀。如果你仅是在日常处理少量的对象时,选取哪个其实变得并不重要,但数据量大时建议还是使用MapStruct 或 BeanCopier 的方式,提高接口性能。

 

实战示例

maven依赖引入

方式1

<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>1.3.0.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.3.0.Final</version>
<scope>provided</scope>
</dependency>

方式2

<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.4.2.Final</version>
</dependency>

<build>
<!-- 配置lombok 和mapStruct注解处理器 -->
<pluginManagement>
<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>1.4.2.Final</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>

实体对象

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Account {
// 账号
private String account;
// 金额
private Integer amt;
}
@Data
@AllArgsConstructor
public class User {
private String userName;
private List<String> addresses;
}
@Data
public class CreateAccountDTO {
private String key;
private List<Account> accounts;
}
@Data
public class CreateAccountVO {
private String visitKey;
private User user;
private List<Account> accounts;
}

转换

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;

@Mapper
public interface AccountConvertUtils {
AccountConvertUtils INSTANCE = Mappers.getMapper(AccountConvertUtils.class);

// 普通的映射
CreateAccountVO convert(CreateAccountDTO createAccountDTO);

// 类型转换的映射
@Mappings({
@Mapping(target = "visitKey", source = "key"),
})
CreateAccountVO convertWithMapping(CreateAccountDTO createAccountDTO);

// 多对一映射
@Mappings({
@Mapping(target = "visitKey", source = "createAccountDTO.key"),
})
CreateAccountVO convert(User user, CreateAccountDTO createAccountDTO);
}

测试用例

public class DemoApp {

public static void main(String[] args) {
CreateAccountDTO createAccountDTO = new CreateAccountDTO();
List<Account> accounts = new ArrayList<>();
accounts.add(new Account("ACT2021051200000001", 1000));
accounts.add(new Account("ACT2021051200000002", 5000));
createAccountDTO.setKey("326D1478E3914C8A");
createAccountDTO.setAccounts(accounts);

User user = new User("Jaemon", Lists.newArrayList("SZ", "NS"));

// 执行1
// CreateAccountVO createAccountVO = AccountConvertUtils.INSTANCE.convert(createAccountDTO);
// 执行2
// CreateAccountVO createAccountVO = AccountConvertUtils.INSTANCE.convertWithMapping(createAccountDTO);
// 执行3
CreateAccountVO createAccountVO = AccountConvertUtils.INSTANCE.convert(user, createAccountDTO);

createAccountDTO.getAccounts().add(new Account("ACT2021051200000003", 1010));

System.out.println(createAccountDTO.toString());
System.out.println(createAccountVO.toString());
}
}

运行输出

// 执行1打印
CreateAccountDTO(key=326D1478E3914C8A, accounts=[Account(account=ACT2021051200000001, amt=1000), Account(account=ACT2021051200000002, amt=5000), Account(account=ACT2021051200000003, amt=1010)])
CreateAccountVO(visitKey=null, user=null, accounts=[Account(account=ACT2021051200000001, amt=1000), Account(account=ACT2021051200000002, amt=5000)])


// 执行2打印
CreateAccountDTO(key=326D1478E3914C8A, accounts=[Account(account=ACT2021051200000001, amt=1000), Account(account=ACT2021051200000002, amt=5000), Account(account=ACT2021051200000003, amt=1010)])
CreateAccountVO(visitKey=326D1478E3914C8A, user=null, accounts=[Account(account=ACT2021051200000001, amt=1000), Account(account=ACT2021051200000002, amt=5000)])


// 执行3打印
CreateAccountDTO(key=326D1478E3914C8A, accounts=[Account(account=ACT2021051200000001, amt=1000), Account(account=ACT2021051200000002, amt=5000), Account(account=ACT2021051200000003, amt=1010)])
CreateAccountVO(visitKey=326D1478E3914C8A, user=User(userName=Jaemon, addresses=[SZ, NS]), accounts=[Account(account=ACT2021051200000001, amt=1000), Account(account=ACT2021051200000002, amt=5000)])

 

References


标签:account,转换,MapStruct,Account,mapstruct,accounts,createAccountDTO,拷贝,amt
From: https://blog.51cto.com/u_15891990/5908813

相关文章

  • (工程)坐标转换类别和方法
    目录1.绪论2.三参数法3.七参数法3.1布尔莎模型3.2代码实现3.3大角度坐标系七参数计算4.四参数+高程拟合4.1四参数4.2高程拟合4.3高程拟合方法5.一步法6.校正参......
  • 结构体的强制类型转换
    陈浩师兄03年的一篇博客《用C写有面向对象特点的程序》描述了用C语言来实现类似C++类继承的方法,这样方法的核心要点就是结构体的强制类型转换,让我来简单分析分析C语言中的......
  • c语言怎么进行强制类型转换
    在c语言中,可以通过“(新类型名称)数据或表达式”语句来进行强制类型转换;例如“(float)100”就是将数值100(默认为int类型)转换为float类型,“(int)(x+y)”就是将表达式“x+......
  • JS数据类型转换,转数值,转字符串,转布尔
    ​1.转数值number        parseInt(‘内容‘/变量名)可以强制把字符串转整数数值,隐式转换        Parsefloat(‘内容‘/变量名)可以强制把有小数的字符串......
  • 5-针对数据类型的说明和转换
    1-intfloatstrbool 1.1-intint:表示的是所有整数int(x)将x转化成一个整数1.2-floatfloat:表示所有的浮点数注:浮点......
  • c# 反射+类型转换
    方法一:typeConverter数据转换这个方法还没测试过,留作备用C#TypeConverter数据转换-顺风车-博客园(cnblogs.com)https://www.cnblogs.com/i-blog/p/3548359.html......
  • 将html字符串转换成html标签显示到页面上(转)
    转自:将html字符串转换成html标签显示到页面上当我们将html字符串放到页面上时,是无法直接显示出我们想要的内容,这时我们需要将字符串转化成为html标签(必须保证html字符串的......
  • .Net中的DataTime类型 和 time_t类型转换
    今天碰到一个问题:数据库表中一个记录时间的FIELD是用time_t类型,也就是long类型存储的,需要转换为yyyy-MM-ddHH:mm:ss格式显示到界面上。当初用time_t类型大概是为了提高存取......
  • (各种数组之间的互相转换)int 数组与List互相转换,object数组转换int数组
    Stream流之List、Integer[]、int[]相互转化一、int[]1.1、int[]转Integer[]publicstaticvoidmain(String[]args){ int[]arr={1,2,3,4,5}; List<......
  • ansible彩色输出转换为html格式
    实现目标:将在后台运行(非tty终端环境)的ansible输出结果作为日志转换为html在浏览器显示:技术背景:我司使用的运维平台,使用flask框架搭建。对各个操控主机使用ansible进行操作,......