第一次看到 MapStruct
的时候, 我个人非常的开心。 因为其跟我内心里面的想法不谋而合。
对于代码中 JavaBean
之间的转换, 一直是困扰我很久的事情。 在开发的时候我看到业务代码之间有很多的 JavaBean
之间的相互转化, 非常的影响观感, 却又不得不存在。 我后来想的一个办法就是通过反射, 或者自己写很多的转换器。
第一种通过反射的方法确实比较方便, 但是现在无论是 BeanUtils
, BeanCopier
等在使用反射的时候都会影响到性能。 虽然我们可以进行反射信息的缓存来提高性能。 但是像这种的话, 需要类型和名称都一样才会进行映射, 有很多时候, 由于不同的团队之间使用的名词不一样, 还是需要很多的手动 set/get 等功能。
第二种的话就是会很浪费时间, 而且在添加新的字段的时候也要进行方法的修改。 不过, 由于不需要进行反射, 其性能是很高的。
MapStruct
带来的改变MapSturct
是一个生成类型安全, 高性能且无依赖的 JavaBean 映射代码的注解处理器(annotation processor)。
抓一下重点:
JavaBean
之间那的映射代码从字面的理解, 我们可以知道, 该工具可以帮我们实现 JavaBean
之间的转换, 通过注解的方式。
同时, 作为一个工具类,相比于手写, 其应该具有便捷, 不容易出错的特点。
MapStruct
入门入门很简单。 我是基于 Maven
来进行项目 jar 包管理的。
<properties>
<org.mapstruct.version>1.3.0.Final</org.mapstruct.version>
</properties>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
该类是从 github 某个订单系统里面拿下来的部分。
@Data
public class Order {
/**
*订单id
*/
private Long id;
/**
* 订单编号
*/
private String orderSn;
/**
* 收货人姓名/号码
*/
private String receiverKeyword;
/**
* 订单状态:0->待付款;1->待发货;2->已发货;3->已完成;4->已关闭;5->无效订单
*/
private Integer status;
/**
* 订单类型:0->正常订单;1->秒杀订单
*/
private Integer orderType;
/**
* 订单来源:0->PC订单;1->app订单
*/
private Integer sourceType;
}
对应的查询参数
@Data
public class OrderQueryParam {
/**
* 订单编号
*/
private String orderSn;
/**
* 收货人姓名/号码
*/
private String receiverKeyword;
/**
* 订单状态:0->待付款;1->待发货;2->已发货;3->已完成;4->已关闭;5->无效订单
*/
private Integer status;
/**
* 订单类型:0->正常订单;1->秒杀订单
*/
private Integer orderType;
/**
* 订单来源:0->PC订单;1->app订单
*/
private Integer sourceType;
}
Mapper
即映射器, 一般来说就是写 xxxMapper
接口。 当然, 不一定是以 Mapper
结尾的。 只是官方是这么写的。 在本入门例子中,对应的接口如下
import com.homejim.mapstruct.dto.OrderQueryParam;
import com.homejim.mapstruct.entity.Order;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
@Mapper
public interface OrderMapper {
OrderQueryParam entity2queryParam(Order order);
}
简单的映射(字段和类型都匹配), 只有一个要求, 在接口上写 @Mapper
注解即可。 然后方法上, 入参对应要被转化的对象, 返回值对应转化后的对象, 方法名称可任意。
写一个测试类测试一下。
@Test
public void entity2queryParam() {
Order order = new Order();
order.setId(12345L);
order.setOrderSn("orderSn");
order.setOrderType(0);
order.setReceiverKeyword("keyword");
order.setSourceType(1);
order.setStatus(2);
OrderMapper mapper = Mappers.getMapper(OrderMapper.class);
OrderQueryParam orderQueryParam = mapper.entity2queryParam(order);
assertEquals(orderQueryParam.getOrderSn(), order.getOrderSn());
assertEquals(orderQueryParam.getOrderType(), order.getOrderType());
assertEquals(orderQueryParam.getReceiverKeyword(), order.getReceiverKeyword());
assertEquals(orderQueryParam.getSourceType(), order.getSourceType());
assertEquals(orderQueryParam.getStatus(), order.getStatus());
}
测试通过, 没有任何的问题。
上面中, 我写了3个步骤来实现了从 Order
到 OrderQueryParam
的转换。
那么, 作为一个注解处理器, 通过MapStruct
生成的代码具有怎么样的优势呢?
这是相对反射来说的, 反射需要去读取字节码的内容, 花销会比较大。 而通过 MapStruct
来生成的代码, 其类似于人手写。 速度上可以得到保证。
前面例子中生成的代码可以在编译后看到。 在 target/generated-sources/annotations 里可以看到。
对应的代码
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2019-08-02T00:29:49+0800",
comments = "version: 1.3.0.Final, compiler: javac, environment: Java 11.0.2 (Oracle Corporation)"
)
public class OrderMapperImpl implements OrderMapper {
@Override
public OrderQueryParam entity2queryParam(Order order) {
if ( order == null ) {
return null;
}
OrderQueryParam orderQueryParam = new OrderQueryParam();
orderQueryParam.setOrderSn( order.getOrderSn() );
orderQueryParam.setReceiverKeyword( order.getReceiverKeyword() );
orderQueryParam.setStatus( order.getStatus() );
orderQueryParam.setOrderType( order.getOrderType() );
orderQueryParam.setSourceType( order.getSourceType() );
return orderQueryParam;
}
}
可以看到其生成了一个实现类, 而代码也类似于我们手写, 通俗易懂。
在我们生成的代码中, 我们可以轻易的进行 debug。
在使用反射的时候, 如果出现了问题, 很多时候是很难找到是什么原因的。
如果是完全映射的, 使用起来肯定没有反射简单。 用类似 BeanUtils
这些工具一条语句就搞定了。 但是,如果需要进行特殊的匹配(特殊类型转换, 多对一转换等), 其相对来说也是比较简单的。
基本上, 使用的时候, 我们只需要声明一个接口, 接口下写对应的方法, 就可以使用了。 当然, 如果有特殊情况, 是需要额外处理的。
生成的代码是对立的, 没有运行时的依赖。
入门就先到这里, 后续会讲一些高级一点的用法。
原网址: 访问
创建于: 2020-12-24 13:44:38
目录: default
标签: 无
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
java windows火焰图_mob64ca12ec8020的技术博客_51CTO博客 - 在windows下不可行,不知道作者是怎样搞的 监听SpringBoot 服务启动成功事件并打印信息_监听springboot启动完毕-CSDN博客 SpringBoot中就绪探针和存活探针_management.endpoint.health.probes.enabled-CSDN博客 u2u转换板 - 嘉立创EDA开源硬件平台 Spring Boot 项目的轻量级 HTTP 客户端 retrofit 框架,快来试试它!_Java精选-CSDN博客 手把手教你打造一套最牛的知识笔记管理系统! - 知乎 - 想法有重合-理论可参考 安宇雨 闲鱼 机械键盘 客制化 开贴记录 文本 linux 使用find命令查找包含某字符串的文件_beijihukk的博客-CSDN博客_find 查找字符串 ---- mac 也适用 安宇雨 打字音 记录集合 B站 bilibili 自行搭建 开坑 真正的客制化 安宇雨 黑苹果开坑 查找工具包maven pom 引用地 工具网站 Dantelis 介绍的玩轴入坑攻略 --- 关于轴的一些说法 --- 非官方 ---- 心得而已 --- 长期开坑更新 [本人问题][新开坑位]关于自动化测试的工具与平台应用 机械键盘 开团 网站记录 -- 能做一个收集的程序就好了 不过现在没时间 -- 信息大多是在群里发的 - 你要让垃圾佬 都去一个地方看难度也是很大的 精神支柱 [超级前台]sprinbboot maven superdesk-app 记录 [信息有用] [环境准备] [基本完成] [sebp/elk] 给已创建的Docker容器增加新的端口映射 - qq_30599553的博客 - CSDN博客 [正在研究] Elasticsearch, Logstash, Kibana (ELK) Docker image documentation elasticsearch centos 安装记录 及 启动手记 正式服务器 39 elasticsearch 问题合集 不断更新 6.1.1 | 6.5.1 两个版本 博客程序 - 测试 - bug记录 等等问题 laravel的启动过程解析 - lpfuture - 博客园 OAuth2 Server PHP 用 Laravel 搭建带 OAuth2 验证的 RESTful 服务 | Laravel China 社区 - 高品质的 Laravel 和 PHP 开发者社区 利用Laravel 搭建oauth2 API接口 附 Unauthenticated 解决办法 - 煮茶的博客 - SegmentFault 思否 使用 OAuth2-Server-php 搭建 OAuth2 Server - 午时的海 - 博客园 基于PHP构建OAuth 2.0 服务端 认证平台 - Endv - 博客园 Laravel 的 Artisan 命令行工具 Laravel 的文件系统和云存储功能集成 浅谈Chromium中的设计模式--终--Observer模式 浅谈Chromium中的设计模式--二--pre/post和Delegate模式 浅谈Chromium中的设计模式--一--Chromium中模块分层和进程模型 DeepMind 4 Hacking Yourself README.md update 20211011
Laravel China 简书 知乎 博客园 CSDN博客 开源中国 Go Further Ryan是菜鸟 | LNMP技术栈笔记 云栖社区-阿里云 Netflix技术博客 Techie Delight Linkedin技术博客 Dropbox技术博客 Facebook技术博客 淘宝中间件团队 美团技术博客 360技术博客 古巷博客 - 一个专注于分享的不正常博客 软件测试知识传播 - 测试窝 有赞技术团队 阮一峰 语雀 静觅丨崔庆才的个人博客 软件测试从业者综合能力提升 - isTester IBM Java 开发 使用开放 Java 生态系统开发现代应用程序 pengdai 一个强大的博主 HTML5资源教程 | 分享HTML5开发资源和开发教程 蘑菇博客 - 专注于技术分享的博客平台 个人博客-leapMie 流星007 CSDN博客 - 舍其小伙伴 稀土掘金 Go 技术论坛 | Golang / Go 语言中国知识社区
最新评论