蔡昊 - 如何高效而优雅的进行对象转换

简介: 简介随着分层结构和DDD设计思想的普及,我们在后端开发过程中,会使用到VO/DO/DTO等等各种类型的模型对象,对象的转换工作也随着变得越来越多。而这种工作技术含量不高,却容易过多的出现在编码里,处理不当也会出现各种问题,那么如何更加高效而优雅的进行类型转换呢?且花几分钟了解下笔者接下来要讲的一款Java代码生成器MapStruct——创建实现Java Bean之间转换的扩展映射器!

MapStruct的优点

首先,我们了解下常见的转换对象方法:

// 1. getter+setter 这种方式会产生大量无意义工作和重复代码
// 2. BeanUtils      
这种方式适用处理简单结构的转换,遇到字段名称不对应等情况,仍需要额外的处理
BeanUtils.copyProperties(Object source,Object target)

MapStruct特点

•            简单、自动化

•            编译时生成映射,确保运行时性能

•            只需要创建接口,大大减少样板代码的编码工作

MapStruct的使用

1. 引包与配置

<properties>                
   <org.mapstruct.version>1.4.1.Final</org.mapstruct.version>
</properties>

<dependency>
   <groupId>org.mapstruct</groupId>
   <artifactId>mapstruct</artifactId>
   <version>${org.mapstruct.version}</version>
</dependency>
<dependency>
   <groupId>org.mapstruct</groupId>
   <artifactId>mapstruct-processor</artifactId>
   <version>${org.mapstruct.version}</version>
</dependency>

*最新maven版本:https://mvnrepository.com/artifact/org.mapstruct/mapstruct

2. 编码及基本使用

先看下需要转换的两个类,这里简化模型,仅仅以VODO做为案例:

@Data
publicclass UserVO{
   privateLong id;
   privateString userName;
   privateString email;
   privateInteger gender;
}

@Data
@TableName(value ="User")
publicclass User implementsSerializable{
   privatestaticfinallong serialVersionUID =1L;

   @TableId(type = IdType.AUTO)
   privateLong id;
   privateString name;
   privateString email;
   privateString createdDate;
   privateString updatedDate;
   privateInteger gender;
}

第一步:下面是新建一个转换类的接口:

/**
* UserTransfer
*
* @author CaiHao
*@since 2022/3/1011:42
*/
//
标记为映射接口,@Mapper允许接口mapstruct-processor在编译期启动
@Mapper
publicinterface UserTransfer {

   UserTransfer INSTANCE = Mappers.getMapper(UserTransfer.class);

   //
映射名称不同的字段
   @Mapping(source ="userName", target ="name")
   //
声明转换方法
   User toDo(UserVO vo);

   @Mapping(source ="name", target ="userName")
   UserVO toVo(User user);

   // list
转换
   List<User>toDo(List<UserVO> voList);

   List<UserVO>toVo(List<User> doList);
}

第二步:如何使用

// 方式一:通过INSTANCE实现访问
User user = UserTransfer.INSTANCE.toDo(tom);

或使用@Mapper(componentModel = "spring")

// 方式二:注入UserTransfer userTransfer;
User user = userTransfer.toDo(tom);

3. 拓展应用

情况一:变量为实体(嵌套bean

@Data
@Builder
@AllArgsConstructor
publicclass EmployeeVO {
   privateLong id;
   privateString empName;
   privateString gender;

   private Contact contact;
}

@Data
publicclass Contact {
   privateString address;
   privateString phone;
   privateString email;
}

@Data
@Builder
publicclass UserVO {
   privateLong id;
   privateString userName;
   privateString email;
   privateInteger gender;
   privateString address;
   privateString phone;
}

@Mapper
publicinterface UserTransfer {
   UserTransfer INSTANCE = Mappers.getMapper(UserTransfer.class);
   /**
    * UserVO
转换成EmployeeVO
    *
    * @param userVO userVO
    *@return EmployeeVO EmployeeVO
    */
   @Mapping(source ="userName", target ="empName")
   @Mapping(source ="email", target ="contact.email")
   @Mapping(source ="address", target ="contact.address")
   @Mapping(source ="phone", target ="contact.phone")
   EmployeeVO toEmployeeVO(UserVO userVO);
}

EmployeeVO employeeVO = UserTransfer.INSTANCE.toEmployeeVO(tom);

情况二: 类型转换、映射合成

publicclass User{    
   privateString updatedDate;
   privateInteger gender;
}

publicclass UserVO {
   privateDate gmtCreate;
   privateString gender;
}

@Mappings({
@Mapping(target ="gender", expression="java(java.lang.String.valueOf(user.getGender()))"),
@Mapping(source ="createdDate", target ="gmtCreate", dateFormat ="yyyy-MM-dd HH:mm")
})
UserVO toVo(User user);

mapstruct的应用场景广泛,如转换、处理第三方服务结果集,同时配合Lombok注解,可以发挥出更好的效果。

*关于更多高级属性和方法,可以查看官方文档

相关文章
|
2月前
|
存储 C# 容器
C变量数据类型深度解析:打造高效代码的基石
C变量数据类型深度解析:打造高效代码的基石
15 1
|
8月前
|
C++
有趣的动态转换
有趣的动态转换
|
6月前
|
存储 编译器
数据类型的本质分析
数据类型的本质分析
48 0
|
11月前
|
C++
优化对象变高效
没有优化过的对象,不足以看出C++的优势
|
12月前
|
前端开发 IDE Java
VS不支持C99标准变长数组的概念
VS不支持C99标准变长数组的概念
|
前端开发 程序员 C#
【C#】通过扩展对象的方式,对字符串等数据类型进行数据进一步处理
在本篇文章中,我们讲一起了解下对象扩展的使用 在实际项目开发中,对象扩展使用的场景还是挺多的,比如:需要对时间值进行再处理,或者字符串中的斜杠(/)转为反斜杠(\)
90 0
|
存储 程序员 C语言
如何进行C++动态转换
如何进行C++动态转换
如何进行C++动态转换
|
前端开发 JavaScript
4、原始数据与引用数据内存的区别
4、原始数据与引用数据内存的区别
77 0
4、原始数据与引用数据内存的区别
|
JavaScript 前端开发 算法
从规范的角度解析对象 — 原始值转换
从规范的角度解析对象 — 原始值转换
105 0
从规范的角度解析对象 — 原始值转换
|
前端开发
前端工作小结58-数组转换为对象
前端工作小结58-数组转换为对象
88 0