MapStruct对象转换
第一次看到 MapStruct 的时候, 我个人非常的开心。因为其跟我内心里面的想法不谋而合。
1 MapStruct 是什么?
1.1 JavaBean 的困扰
对于代码中 之间的转换, 一直是困扰我很久的事情。JavaBean
在开发的时候我看到业务代码之间有很多的 之间的相互转化, 非常的影响观感, 却又不得不存在。我后来想的一个办法就是通过反射, 或者自己写很多的转换器。JavaBean
第一种通过反射的方法确实比较方便, 但是现在无论是 BeanUtils, BeanCopier 等在使用反射的时候都会影响到性能。虽然我们可以进行反射信息的缓存来提高性能。
但是像这种的话, 需要类型和名称都一样才会进行映射, 有很多时候, 由于不同的团队之间使用的名词不一样, 还是需要很多的手动 set/get 等功能。
第二种的话就是会很浪费时间, 而且在添加新的字段的时候也要进行方法的修改。不过, 由于不需要进行反射, 其性能是很高的。
1.2 MapStruct 带来的改变
MapSturct 是一个生成类型安全, 高性能且无依赖的 JavaBean 映射代码的注解处理器(annotation processor)。
抓一下重点:
注解处理器
可以生成
JavaBean之间那的映射代码类型安全, 高性能, 无依赖性
从字面的理解, 我们可以知道, 该工具可以帮我们实现 之间的转换, 通过注解的方式。JavaBean
同时, 作为一个工具类,相比于手写, 其应该具有便捷, 不容易出错的特点。
2 MapStruct 入门
入门很简单。我是基于 Maven 来进行项目 jar 包管理的。
2.1 引入依赖
<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>
2.2 创建entity和dto对象
该类是从 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;
}
2.3 写 Mapper
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 注解即可。
然后方法上, 入参对应要被转化的对象, 返回值对应转化后的对象, 方法名称可任意。
2.4 测试
写一个测试类测试一下。
@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 MapStruct 分析
上面中, 我写了3个步骤来实现了从 Order 到 OrderQueryParam 的转换。
那么, 作为一个注解处理器, 通过MapStruct 生成的代码具有怎么样的优势呢?
3.1 高性能
这是相对反射来说的, 反射需要去读取字节码的内容, 花销会比较大。
而通过 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;
}
}
可以看到其生成了一个实现类, 而代码也类似于我们手写, 通俗易懂。
3.2 易于 debug
在我们生成的代码中, 我们可以轻易的进行 debug。
在使用反射的时候, 如果出现了问题, 很多时候是很难找到是什么原因的。
3.3 使用相对简单
如果是完全映射的, 使用起来肯定没有反射简单。用类似 BeanUtils 这些工具一条语句就搞定了。但是,如果需要进行特殊的匹配(特殊类型转换, 多对一转换等), 其相对来说也是比较简单的。
基本上, 使用的时候, 我们只需要声明一个接口, 接口下写对应的方法, 就可以使用了。当然, 如果有特殊情况, 是需要额外处理的。
3.4 代码独立
生成的代码是对立的, 没有运行时的依赖。
MapStruct对象转换的更多相关文章
- 优雅的对象转换解决方案-MapStruct使用进阶(二)
在前面, 介绍了 MapStruct 及其入门. 本文则是进一步的进阶. 在 MapStruct 生成对应的实现类的时候, 有如下的几个情景. 1 属性名称相同,则进行转化 在实现类的时候, 如果属性 ...
- mapstruct解放Java对象转换
摘要 当前web后端开发,都是使用多层工程结构,需要在VO,BO,DTO,DO等各种数据结构中相互转换.这些转换代码都是些比较简单的字段映射,类型转换,重复性工作比较高,可以使用一些工具解放我们的双手 ...
- 对象转换工具 MapStruct 介绍
前言 在我们日常开发的分层结构的应用程序中,为了各层之间互相解耦,一般都会定义不同的对象用来在不同层之间传递数据,因此,就有了各种 XXXDTO.XXXVO.XXXBO 等基于数据库对象派生出来的对象 ...
- java对象转换
对象转换: 对象的分层涉及到各个层级之间的对象转换(Entity2DTO , DTO2VO, VO2DTO,DTO2Entity等),传统的采用set/get 方法硬编码实现写的代码比较多:或者采用B ...
- 我写了个IDEA开源插件,vo2dto 一键生成对象转换
让人头疼的对象转换 头炸,po2vo.vo2do.do2dto,一堆对象属性,取出来塞进来.要不是为了 DDD 架构下的各个分层防腐,真想一竿子怼下去. 那上 BeanUtils.copyProper ...
- 采用Lambda表达式快速实现实体模型对象转换到DTO
在项目中,采用code first时建立的模型对象不能直接用于数据传输,需要从新根据需求建立Dto对象 为什么需要建立Dto对象呢? DTO即数据传输对象.之前不明白有些框架中为什么要专门定义DTO来 ...
- Newtonsoft.Json 把对象转换成json字符串
var resultJson = new { records = rowCount, page = pageindex, //总页数=(总页数+页大小-1)/页大小 total = (rowCount ...
- python class对象转换成json/字典
# -*- encoding: UTF-8 -*- class Student: name = '' age = 0 def __init__(self, name, age): self.name ...
- 前台 JSON对象转换成字符串 相互转换 的几种方式
在最近的工作中,使用到JSON进行数据的传递,特别是从前端传递到后台,前台可以直接采用ajax的data函数,按json格式传递,后台Request即可,但有的时候,需要传递多个参数,后台使用requ ...
随机推荐
- SpringCloud微服务实战——搭建企业级开发框架(十四):集成Sentinel高可用流量管理框架【限流】
Sentinel 是面向分布式服务架构的高可用流量防护组件,主要以流量为切入点,从限流.流量整形.熔断降级.系统负载保护.热点防护等多个维度来帮助开发者保障微服务的稳定性. Sentinel 具有 ...
- Java测试开发--Comparable和Comparator接口(五)
Comparable 简介Comparable 是排序接口.若一个类实现了Comparable接口,就意味着"该类支持排序".此外,"实现Comparable接口的类的对 ...
- JS中如何将yyyy-MM-dd HH:mm:ss格式的字符串转成Date类型
var deadline = '2019-04-11 13:11:00'; var result = new Date(deadline.replace(/-/g, '/'));
- Python 爬取 猫眼
1. import requests import re import pymongo MONGO_URL='localhost'#建立连接 MONGO_DB='Maoyan'#创建数据库 clien ...
- [luogu5423]Valleys
先考虑不要求有洞,那么可以将所有权值排序,然后不断插入,那么一个连通块就是一个答案,加上连通块大小即可考虑并查集如何判断是否有洞,可以发现对于任意一个无洞的直角多边形,都有$90度内角-90度外角=4 ...
- SpringCloud升级之路2020.0.x版-41. SpringCloudGateway 基本流程讲解(3)
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 我们继续分析上一节提到的 WebHandler.加入 Spring Cloud Sleut ...
- vue的常用指令
https://www.bootcdn.cn/ 前端资源库 <!-- 常用内置指令 v:text : 更新元素的 textContent v-html : 更新元素的 innerHTML v-i ...
- 部署vue项目到Linux服务器
案例一 vue-cli构建vue3项目,将项目上传到Linux服务器,服务器安装node,并启动vue项目 首先本地有一个vue项目,启动后可正常访问 本地打包后,也可直接访问 若打包后的index. ...
- Codeforces 917D - Stranger Trees(矩阵树定理/推式子+组合意义)
Codeforces 题目传送门 & 洛谷题目传送门 刚好看到 wjz 在做这题,心想这题之前好像省选前做过,当时觉得是道挺不错的题,为啥没写题解呢?于是就过来补了,由此可见我真是个大鸽子(( ...
- MongoDB 安装/启动/基本操作命令
1.MongoDB简介 MongoDB是一个基于分布式文件存储的数据库,由C++语言编写,旨在为WEB应用提供可扩展的高性能数据存储解决方案. MongoDB是一个介于关系型数据库和非关系数据库之间的 ...