烦人的Bean 转换

对于代码中 JavaBean之间的转换, 一直是困扰我很久的事情。在开发的时候我看到业务代码之间有很多的 JavaBean 之间的相互转化, 非常的影响观感, 却又不得不存在。我后来想的一个办法就是通过反射, 或者自己写很多的转换器。

第一种通过反射的方法确实比较方便, 但是现在无论是 BeanUtils, BeanCopier 等在使用反射的时候都会影响到性能。虽然我们可以进行反射信息的缓存来提高性能。但是像这种的话, 需要类型和名称都一样才会进行映射, 有很多时候, 由于不同的团队之间使用的名词不一样, 还是需要很多的手动 set/get 等功能。

第二种的话就是会很浪费时间, 而且在添加新的字段的时候也要进行方法的修改。不过, 由于不需要进行反射, 其性能是很高的。

MapStruct 带来的改变

MapSturct 是一个生成 类型安全, 高性能且无依赖的 JavaBean 映射代码的注解处理器(annotation processor)。

抓一下重点:

  1. 注解处理器
  2. 可以生成 JavaBean 之间那的映射代码
  3. 类型安全, 高性能, 无依赖性

从字面的理解, 我们可以知道, 该工具可以帮我们实现 JavaBean 之间的转换, 通过注解的方式。

同时, 作为一个工具类,相比于手写, 其应该具有便捷, 不容易出错的特点。

MapStruct 入门

引入依赖

  org.mapstruct  mapstruct-jdk8  1.3.1.Final  org.mapstruct  mapstruct-processor  1.3.1.Final

我现在在对接一个系统,传过来的是支付信息PayInfo。后面数据库存的是TExpensesRecords消费记录。我需要进行bean的转换。如果我一点点的写get/set真是太烦人了,无脑的体力劳动。

甚至中间还牵涉了很多类型转换,嵌套之类的繁琐操作,而我们想要的只是建立它们之间的映射关系而已。有没有一种通用的映射工具来帮我们搞定这一切。当然有而且还不少。有人说apache的BeanUtil.copyProperties可以实现,但是性能差而且容易出异常,很多规范严禁使用这种途径。以下是对几种对象映射框架的对比,大多数情况下 MapStruct 性能最高。原理类似于lombok ,MapStruct都是在编译期进行实现,而且基于Getter、Setter,没有使用反射所以一般不存在运行时性能问题。

测试

我现在有两个类

一个是接口VO类

@Data@ApiModel("支付信息")public class PayInfo {  @ApiModelProperty("支付码")  private String payCode;  @ApiModelProperty("总金额")  private String totalMoney;  @ApiModelProperty("菜品")  private List foods;  @ApiModelProperty(value = "服务商id")  private String serviceId;  @ApiModelProperty(value = "服务商名称")  private String serviceName;  @ApiModelProperty(value = "餐厅编号")  private String restaurantCode;  @ApiModelProperty(value = "餐厅名称")  private String restaurantName;  @ApiModelProperty(value = "机器号")  private String machineCode;  @ApiModelProperty(value = "消费类型(1:食堂用餐、2:网点消费、3:自助贩卖机消费)")  private String expensesType;}

一个是数据库DO类

@Data@ApiModel(value ="TExpensesRecords", description="消费记录表")public class TExpensesRecords implements Serializable {  @ApiModelProperty(value = "")  private Integer id;  @ApiModelProperty(value = "交易流水号(随便生成唯一编号)")  private String tradeId;  @ApiModelProperty(value = "员工号")  private String userCode;  @ApiModelProperty(value = "服务商id")  private String serviceId;  @ApiModelProperty(value = "服务商名称")  private String serviceName;  @ApiModelProperty(value = "餐厅编号")  private String restaurantCode;  @ApiModelProperty(value = "餐厅名称")  private String restaurantName;  @ApiModelProperty(value = "机器号")  private String machineCode;  @ApiModelProperty(value = "消费类型(1:食堂用餐、2:网点消费、3:自助贩卖机消费)")  private String expensesType;  @ApiModelProperty(value = "消费金额")  private BigDecimal amount;  @ApiModelProperty(value = "消费时间")  private LocalDateTime expensesDate;

可以看到,他们有一些属性是同名的。

我们一步步来写。

先写一个转换接口

写一个测试类

@Testpublic void payInfo2ExpenseRecord() throws Exception {  PayInfo payInfo = new PayInfo();  payInfo.setPayCode("20200513_01471111_120_40_1589359038744");  payInfo.setTotalMoney("39.3");  payInfo.setServiceId("001");  payInfo.setServiceName("服务商A");  payInfo.setRestaurantCode("A001");  payInfo.setRestaurantName("餐厅A");  payInfo.setMachineCode("M001");  payInfo.setExpensesType("1");  TExpensesRecords tExpensesRecords =          PayInfoMapper.INSTANCE.payInfo2ExpenseRecord(payInfo);  log.info(tExpensesRecords.toString());}

可以看到,大部分相同名字的属性已经完成转换。但是名字不一致的,需要我们单独配置下。

处理不同名的属性

代码也很好理解,就是将源的payCode字段映射到目标的tradeId字段

看下测试结果

TExpensesRecords(id=null, tradeId=20200513_01471111_120_40_1589359038744, userCode=null, serviceId=001, serviceName=服务商A, restaurantCode=A001, restaurantName=餐厅A, machineCode=M001, expensesType=1, amount=39.3, expensesDate=null)

tradeId映射成功。而且totalMoney是String,映射成BigDecimal的amount也成功了

原理

原理类似于lombok ,MapStruct都是在编译期对接口进行实现,而且基于Getter、Setter,没有使用反射所以一般不存在运行时性能问题。 类型不同,会自动进行转换。

Spring 注入的方式

上面的例子是默认的方式

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

在正常的项目中,一般和spring整合使用

就是在 @Mapper 后面加入 componentModel="spring"

在用到的地方就可以使用@Autowired注入了

注解说明

@Mapper 只有在接口加上这个注解, MapStruct 才会去实现该接口  @Mapper 里有个 componentModel 属性,主要是指定实现类的类型,一般用到两个  default:默认,可以通过 Mappers.getMapper(Class) 方式获取实例对象  spring:在接口的实现类上自动添加注解 @Component,可通过 @Autowired 方式注入@Mapping:属性映射,若源对象属性与目标对象名字一致,会自动映射对应属性  source:源属性  target:目标属性  dateFormat:String 到 Date 日期之间相互转换,通过 SimpleDateFormat,该值为 SimpleDateFormat             的日期格式  ignore: 忽略这个字段@Mappings:配置多个@Mapping@MappingTarget 用于更新已有对象@InheritConfiguration 用于继承配置

高级使用

多对一

类型转换

string转换bigdecimal_使用MapStruct处理恼人的bean转换相关推荐

  1. EntityUtils MapStruct BeanCopier 数据实体类转换工具 DO BO VO DTO 附视频

    一.序言 在实际项目开发过程中,总有数据实体类互相转换的需求,DO.BO.VO.DTO等数据模型转换经常发生.今天推荐几个好用的实体类转换工具,分别是EntityUtils MapStruct Bea ...

  2. String类型日期格式从yyyy-MM-dd HH:mm:ss转换成yyyy-MM-dd‘T‘HH:mm:ss.SSSXXX

    String类型日期格式从yyyy-MM-dd HH:mm:ss转换成yyyy-MM-dd'T'HH:mm:ss.SSSXXX 最近在做一个项目,前端传入的时间格式为yyyy-MM-dd HH:mm: ...

  3. java 0x转中文_Java:转换汉字为unicode形式的字符串和转换unicode形式字符串转换成汉字...

    /* 输出 Original: 黄 彪彪 to unicode: \u9EC4\ \t\u5F6A\u5F6A from unicode: 黄 彪彪 使用命令转换: native2ascii -enc ...

  4. 转换汉字为unicode形式的字符串和转换unicode形式字符串转换成汉字

    http://www.cppblog.com/biao/archive/2013/07/04/137087.html /* 输出 Original: 黄 彪彪 to unicode: \u9EC4\ ...

  5. html进制转换js代码,JS中的进制转换以及作用

    js的进制转换, 分为2进制,8进制,10进制,16进制之间的相互转换, 我们直接利用 对象.toString()即可实现: 运行下面代码 //10进制转为16进制 (10).toString(16) ...

  6. blue html中转换,Vue/Vue中Html和Markdown互相转换/README.md · bluemoon/LearningNotes - Gitee.com...

    # Vue中Html和Markdown互相转换 ## 前言 最近想实现的一个功能,就是将系统中的博客进行导出成Markdown格式,后面经过了调研发现有两种方法能够满足需求,一个是Java后台中将HT ...

  7. java中的进制输出转换_java中进制的转换,Byte与16进制的转换

    java中对于进制的转换有很多方式,其中对于常见的基本的二进制 八进制 十进制 十六进制等的转换有对于的包装类实现,不需要通过二外的算法来进行实现,具体如下: 首先关于最简单的二进制转换的方法有: 十 ...

  8. c++字符数组整数转换中文大写金额的形式_数字大写转换烦,内置格式多缺陷, VBA函数来解难...

    观看视频更直观 在Excel中将数字转换为中文大写或小写,有两种方法,一种是设置数据格式:另一种是使用内置的隐蔽函数NumberString函数. 一.设置数据格式 在Excel中输入数字后,选中单元 ...

  9. php将abc转换成整形是什么意思,php强制转换类型的方法

    php强制转换类型的方法 发布时间:2020-07-02 15:45:14 来源:亿速云 阅读:102 作者:Leah 本篇文章为大家展示了php强制转换类型的方法,代码简明扼要并且容易理解,绝对能使 ...

最新文章

  1. 利用CNN来检测伪造图像
  2. SIM800C SIM卡唯一标识符ICCID
  3. Matlab图形绘制经典案例 (2)
  4. idea junit简单实践
  5. 通过分析 JDK 源代码研究 Hash 存储机制--转载
  6. 【Linux】一步一步学Linux——reset命令(268)
  7. 创建线程时候多参数传递方法及参数改变问题--扫雷辅助(三)
  8. windows远程桌面mstsc使用 代理
  9. python如何画图设置坐标轴_python matplotlib坐标轴设置的方法
  10. 【神仙打架】特奖答辩前10出炉,两名CS学生3篇顶会一作,有人周读3000页英文论文...
  11. JSP+JavaBean+Servlet+Oracle新增功能中对Date类型的字段的处理
  12. Rust : codewars的Sum of Pairs
  13. office 2010 安装时出错 MSXML版本6.10.1129.0终极解决方案
  14. 结构专业规范大全_监理签字用语规范大全,就是这么专业!
  15. 自然辩证法小总结思维导图
  16. u盘中毒文件为html文档,u盘中毒文件被隐藏怎么办【解决方法】
  17. git报 “The stash entry is kept in case you need it again“ 错误解析
  18. Codeforces 1247D. Power Products (logn质因数分解)
  19. jemter使用beanshell的几种方法
  20. C语言学习1——第一、二、三章学习记录

热门文章

  1. 10.12 telnet:远程登录主机
  2. LVS+Keepalived 高可用群集的介绍和搭建步骤
  3. access中如何画斜线_大神支招:如何设计access行政区划菜单
  4. python数据分析知识点_Python基础知识点总结:数据
  5. 太阳花浏览器_一道浏览器面试题,就能看出你的前端功底
  6. P1314 聪明的质监员(前缀和+二分)
  7. 7张图揭晓RocketMQ存储设计的精髓
  8. 如何利用云原生技术构建现代化应用?
  9. 网易云音乐基于 Flink + Kafka 的实时数仓建设实践
  10. 女朋友问我什么是云计算?