点击上方“芋道源码”,选择“设为星标”

做积极的人,而不是积极废人!

源码精品专栏

  • 原创 | Java 2020 超神之路,很肝~

  • 中文详细注释的开源项目

  • RPC 框架 Dubbo 源码解析

  • 网络应用框架 Netty 源码解析

  • 消息中间件 RocketMQ 源码解析

  • 数据库中间件 Sharding-JDBC 和 MyCAT 源码解析

  • 作业调度中间件 Elastic-Job 源码解析

  • 分布式事务中间件 TCC-Transaction 源码解析

  • Eureka 和 Hystrix 源码解析

  • Java 并发源码

摘要: 原创出处 http://www.iocoder.cn/Spring-Boot/MapStruct/ 「芋道源码」欢迎转载,保留摘要,谢谢!

  • 1. 概述

  • 2. 快速入门

  • 3. 集成 Lombok

  • 4. @Mapping

  • 5. IDEA MapStruct 插件

  • 666. 彩蛋


本文在提供完整代码示例,可见 https://github.com/YunaiV/SpringBoot-Labs 的 lab-55 目录。

原创不易,给点个 Star 嘿,一起冲鸭!

1. 概述

友情提示:MapStruct 和 Spring Boot 没有直接关系,单纯放在这个系列。

为了让应用的代码更易维护,我们往往会将项目进行分层。在《阿里巴巴 Java 开发手册》中,推荐分层如下图:

应用分层

分层之后,每一层都有自己的领域模型,即不同类型的 Bean:

  • DO(Data Object):与数据库表结构一一对应,通过DAO层向上传输数据源对象。

  • DTO(Data Transfer Object):数据传输对象,Service或Manager向外传输的对象。

  • BO(Business Object):业务对象。由Service层输出的封装业务逻辑的对象。

  • 等等...

那么,进行就需要这些对象的转换。例如说:

// 从数据库中查询用户
UserDO userDO = userMapper.selectBy(id);// 对象转换
UserBO userBO = new UserBO();
userBO.setId(userDO.getId());
userBO.setUsername(userDO.getUsername());
// ... 还有其它属性

显然,手动进行对象的转换,虽然执行性能很高,但是开发效率非常低下,且可能会存在漏写的情况。因此,我们会选择借助框架或是工具来实现对象的转换,例如说:

友情提示:如果胖友对如下工具的性能对比感兴趣,可以阅读 Performance of Java Mapping Frameworks 文章。

  • Spring BeanUtils

  • Apache BeanUtils

  • Dozer

  • Orika

  • MapStruct

  • ModelMapper

  • JMapper

艿艿个人比较喜欢 MapStruct,原因是它基于 JSR 269 的 Java 注解处理器,自动生成对象的代码,使用便捷,性能优秀。例如说:

  • 通过创建一个 MapStruct Mapper 接口,并定义一个转换接口方法,后续交给 MapStruct 自动生成对象转换的代码即可。

如下是 MapStruct 的简介,胖友可以简单了解下:

MapStruct 是用于生成类型安全的 Bean 映射类的 Java 注解处理器。

你所要做的就是定义一个映射器接口,声明任何需要映射的方法。在编译过程中,MapStruct 将生成该接口的实现。此实现使用纯 Java 的方法调用源对象和目标对象之间进行映射,并非 Java 反射机制

与手工编写映射代码相比,MapStruct 通过生成冗长且容易出错的代码来节省时间。在配置方法的约定之后,MapStruct 使用了合理的默认值,但在配置或实现特殊行为时将不再适用。

与动态映射框架相比,MapStruct 具有以下优点:

  • 使用纯 Java 方法代替 Java 反射机制快速执行。

  • 编译时类型安全:只能映射彼此的对象和属性,不能映射一个 Order 实体到一个 Customer DTO 中等等。

  • 如果无法映射实体或属性,则在编译时清除错误报告。

2. 快速入门

示例代码对应仓库:lab-55-mapstruct-demo

本小节,我们来快速入门 MapStruct。新建 lab-55-mapstruct-demo 项目,作为示例项目,最终如下图所示:

项目总体结构

2.1 引入依赖

创建 pom.xml 文件,引入 MapStruct 相关依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>lab-55</artifactId><groupId>cn.iocoder.springboot.labs</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>lab-55-mapstruct-demo</artifactId><properties><java.version>1.8</java.version><mapstruct.version>1.3.1.Final</mapstruct.version></properties><dependencies><dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct</artifactId><version>${mapstruct.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>${java.version}</source><target>${java.version}</target><annotationProcessorPaths><path><groupId>org.mapstruct</groupId><artifactId>mapstruct-processor</artifactId><version>${mapstruct.version}</version></path></annotationProcessorPaths></configuration></plugin></plugins></build></project>

注意,一定要在 maven-compiler-plugin 插件中,声明 mapstruct-processor 为 JSR 269 的 Java 注解处理器。

2.2 UserDO

创建 UserDO 类,用户 DO。代码如下:

public class UserDO {/** 用户编号 **/private Integer id;/** 用户名 **/private String username;/** 密码 **/private String password;// ... 省略 setter/getter 方法
}

2.3 UserBO

创建 UserBO 类,用户 BO。代码如下:

public class UserBO {/** 用户编号 **/private Integer id;/** 用户名 **/private String username;/** 密码 **/private String password;// ... 省略 setter/getter 方法
}

2.4 UserConvert

创建 UserConvert 接口,作为 User 相关 Bean 的转换器。代码如下:

@Mapper // <1>
public interface UserConvert {UserConvert INSTANCE = Mappers.getMapper(UserConvert.class); // <2>UserBO convert(UserDO userDO);}

<1> 处,添加 @Mapper 注解,声明它是一个 MapStruct Mapper 映射器。

<2> 处,通过调用 Mappers 的 #getMapper(Class<T> clazz) 方法,获得 MapStruct 帮我们自动生成的 UserConvert 实现类的对象。

<3> 处,定义 #convert(UserDO userDO) 方法,声明 UserDO 转换成 UserBO。后续,在我们每次编译该项目时,在如下目录可以看到自动生成的 UserConvert 实现类,可以用于 Debug 调试噢:

生成代码示例

2.5 UserBOTest

创建 UserBOTest 类,进行简单测试。代码如下:

public class UserBOTest {public static void main(String[] args) {// 创建 UserDO 对象UserDO userDO = new UserDO().setId(1).setUsername("yudaoyuanma").setPassword("buzhidao");// <X> 进行转换UserBO userBO = UserConvert.INSTANCE.convert(userDO);System.out.println(userBO.getId());System.out.println(userBO.getUsername());System.out.println(userBO.getPassword());}}

核心代码在 <X> 处,通过 UserConvert 将 UserDO 对象转换成 UserBO 对象。

运行 #main(String[] args) 方法,打印如下,符合预期:

1
yudaoyuanma
buzhidao

???? 至此,我们已经完成了 MapStruct 的快速入门。

3. 集成 Lombok

示例代码对应仓库:lab-55-mapstruct-demo-lombok

在《芋道 Spring Boot 消除冗余代码 Lombok 入门》文章中,我们学习了可以通过 Lombok 帮我们自动生成相对“冗余”代码,例如说 setter、getter 等等方法。

恰好,MapStruct 自动生成的对象转换的代码,也是依赖 setter、getter 方法的,因此两者在一起使用时,需要进行相应的配置。如下图所示:

MapStruct + Lombok

下面,我们从「2. 快速入门」小节的 lab-55-mapstruct-demo 项目,复制出 lab-55-mapstruct-demo-lombok 来集成 Lombok 作为示例。

3.1 引入依赖

修改 pom.xml 文件,额外引入 Lombok 相关依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>lab-55</artifactId><groupId>cn.iocoder.springboot.labs</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>lab-55-mapstruct-demo-lombok</artifactId><properties><java.version>1.8</java.version><mapstruct.version>1.3.1.Final</mapstruct.version><lombok.version>1.18.12</lombok.version></properties><dependencies><!-- 引入 mapstruct 依赖 --><dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct</artifactId><version>${mapstruct.version}</version></dependency><!-- 引入 lombok 依赖 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version><scope>provided</scope></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>${java.version}</source><target>${java.version}</target><annotationProcessorPaths><!-- 引入 mapstruct-processor --><path><groupId>org.mapstruct</groupId><artifactId>mapstruct-processor</artifactId><version>${mapstruct.version}</version></path><!-- 引入 lombok-processor --><path><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version></path></annotationProcessorPaths></configuration></plugin></plugins></build></project>

3.2 UserDO

修改 UserDO 类,使用 Lombok @Data 注解替代 setter、getter 方法。代码如下:

@Data // 新增
@Accessors(chain = true)
public class UserDO {/** 用户编号 **/private Integer id;/** 用户名 **/private String username;/** 密码 **/private String password;// ... 删除 setter、getter 方法
}

3.3 UserBO

修改 UserBO 类,使用 Lombok @Data 注解替代 setter、getter 方法。代码如下:

@Data // 新增
@Accessors(chain = true)
public class UserDO {/** 用户编号 **/private Integer id;/** 用户名 **/private String username;/** 密码 **/private String password;// ... 删除 setter、getter 方法
}

3.4 UserBOTest

运行 UserBOTest 类的 运行 #main(String[] args) 方法,打印如下,符合预期:

1
yudaoyuanma
buzhidao

???? 至此,我们已经完成了 MapStruct 和 Lombok 的集成。

4. @Mapping

在对象转换时,我们可能会存在属性不是完全映射的情况,例如说属性名不同。此时,我们可以使用 MapStruct 提供的 @Mapping 注解,配置相应的映射关系。示例如下图:

@Mapping 映射

下面,我们直接在 「2. 快速入门」小节的 lab-55-mapstruct-demo 项目,增加 @Mapping 注解的示例。

4.1 UserDetailBO

示例代码对应仓库:lab-55-mapstruct-demo

创建 UserDetailBO 类,用户明细 BO。代码如下:

public class UserDetailBO {private Integer userId;// ... 省略 setter/getter 方法
}

4.2 UserConvert

修改 UserConvert 类,增加 @Mapping 注解的使用示例。代码如下:

// UserConvert.java@Mappings({@Mapping(source = "id", target = "userId")
})
UserDetailBO convertDetail(UserDO userDO);
  • 其中,设置注解的 source 属性为 UserDO 的 id 属性,注解的 target 属性为 UserDetailBO 的 userId 属性。

@Mapping 注解还支持多个对象转换为一个对象。示例如下图:

@Mapping 复杂示例

4.3 UserDetailBOTest

创建 UserDetailBOTest 类,进行简单测试。代码如下:

public class UserDetailBOTest {public static void main(String[] args) {// 创建 UserDO 对象UserDO userDO = new UserDO().setId(1).setUsername("yudaoyuanma").setPassword("buzhidao");// 进行转换UserDetailBO userDetailBO = UserConvert.INSTANCE.convertDetail(userDO);System.out.println(userDetailBO.getUserId());}}

核心代码在 <X> 处,通过 UserConvert 将 UserDO 对象转换成 UserDetailBO 对象。

运行 #main(String[] args) 方法,打印如下,符合预期:

1

至此,我们已经完成 MapStruct 的 @Mapping 注解的学习。@Mapping 注解还有其它属性可以设置,提供非常强大的功能,胖友可以后续自己研究下。例如说 qualifiedByName 属性,可以自定义转换方法,如下图所示:

@MappingqualifiedByName 示例

5. IDEA MapStruct 插件

MapStruct 提供了 IDEA MapStruct Support 插件,让我们在 IDEA 中,可以更愉快的使用 MapStruct,牛逼啊!

IDEA MapStruct Support

提供的具体功能,可以看下官方文档《MapStruct support for IntelliJ IDEA》,例如说:

  • Completion for Properties and Enum Constants:

  • Go To Declaration from annotation:

  • Find Usages:

666. 彩蛋

基本上,我们已经学习完了 MapStruct 的常用功能。如果想要更加深入,可以查看《MapStruct 官方文档》,真的是贼强大哈。

另外,艿艿在 https://github.com/YunaiV/onemall 开源项目中,大量使用 MapStruct 来实现对象转换。具体的,胖友可以搜 Convert 结尾的类即可。



欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢

已在知识星球更新源码解析如下:

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 20 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

芋道 Spring Boot 对象转换 MapStruct 入门相关推荐

  1. 芋道 Spring Boot 消息队列 RocketMQ 入门

    点击上方"芋道源码",选择"设为星标" 做积极的人,而不是积极废人! 源码精品专栏 原创 | Java 2020 超神之路,很肝~ 中文详细注释的开源项目 RP ...

  2. 芋道 Spring Boot 快速入门

    点击上方"芋道源码",选择"设为星标" 做积极的人,而不是积极废人! 源码精品专栏 原创 | Java 2019 超神之路,很肝~ 中文详细注释的开源项目 RP ...

  3. 芋道 Spring Boot 消除冗余代码 Lombok 入门

    点击上方"Java基基",选择"设为星标" 做积极的人,而不是积极废人! 源码精品专栏 原创 | Java 2020 超神之路,很肝~ 中文详细注释的开源项目 ...

  4. 芋道 Spring Boot JPA 入门(一)之快速入门

    点击上方"芋道源码",选择"设为星标" 做积极的人,而不是积极废人! 源码精品专栏 原创 | Java 2019 超神之路,很肝~ 中文详细注释的开源项目 RP ...

  5. 学习第三篇:【SpringBoot-Labs】芋道 Spring Boot 自动配置原理

    本周(8.21-8.27)将学习芋道 Spring Boot的以下文章: 8.21: 快速入门 8.22:Spring Boot 自动配置原理 .Jar 启动原理 8.23:调试环境. 热部署入门.消 ...

  6. 芋道 Spring Boot 自动配置原理

    转载自  芋道 Spring Boot 自动配置原理 1. 概述 友情提示:因为本文是分享 Spring Boot 自动配置的原理,所以需要胖友有使用过 Spring Boot 的经验.如果还没使用过 ...

  7. 芋道 Spring Boot 热部署入门

    点击上方"芋道源码",选择"设为星标" 做积极的人,而不是积极废人! 源码精品专栏 原创 | Java 2020 超神之路,很肝~ 中文详细注释的开源项目 RP ...

  8. spring boot 转xml格式报错解决方法_芋道 Spring Boot MyBatis 入门(一)之 MyBatis + XML...

    摘要: 原创出处 http://www.iocoder.cn/Spring-Boot/MyBatis/「芋道源码」欢迎转载,保留摘要,谢谢! 1. 概述 2. MyBatis + XML 2.1 引入 ...

  9. 芋道 Spring Boot API 接口文档 Swagger 入门

    点击上方"芋道源码",选择"设为星标" 做积极的人,而不是积极废人! 源码精品专栏 原创 | Java 2020 超神之路,很肝~ 中文详细注释的开源项目 RP ...

最新文章

  1. Visual C++ 2012编译器更新(预览版)发布
  2. 深入理解CSS计数器
  3. 从零开始入门 K8s | Kubernetes 网络模型进阶
  4. 计算机网络-思维导图(4)网络层
  5. 关于PostMessage后台发送组合键
  6. 对比let、const、var的异同
  7. java enum 变量_java枚举使用详解
  8. SpringMVC中使用作用域对象完成数据的流转
  9. calayer 与uiview
  10. iphone:解析html的第三库hpple初试
  11. bzoj 4514: [Sdoi2016]数字配对(二分图+费用最大流)
  12. flask gunicorn gevent部署
  13. rant c语言头文件,用CGIC库来开发CGI程序
  14. Java汽车销售系统
  15. 使用_beginthread创建线程
  16. 运行VS编译的程序提示“由于应用程序配置不正确,应用程序未能启动”的问题
  17. (php毕业设计)基于php校园网络报修管理系统获取
  18. Linux监控平台搭建二
  19. adobe服务器无响应,链接不到adobe服务器
  20. HTML——表单标签<form>与表单的实现

热门文章

  1. Three.js 实现点击模型改变颜色
  2. CSS图片阴影+鼠标移上图片放大、变形
  3. PHP微信小程序消息推送写法
  4. 亚马逊云主机linux密钥登陆改为密码登陆
  5. 外贸型网站,应该如何做好SEO优化?
  6. CRB开发-总体简介
  7. js常见面试题(二)
  8. 永磁同步电机PMSM直接转矩滞环控制 采用三闭环控制:转速外环采用PI调节器,转矩环和磁链环经过滞环后得到PWM脉冲
  9. 电饭煲底盘进水怎么办
  10. 4个步骤,搭建接口测试自动化框架