MapStruct简单使用
前言
平常开发过程中总是会有数据映射转换,比如 DO转DTO,DTO转VO,通常的做法就是get/set方法,实体字段数量很大的时候就会写大量的转换,涉及到每个字段,重复的工作量大,并且很容易在赋值的过程中写错,于是会选择一些第三方的工具类来做对应的转换,如:Spring BeanUtils / Cglib BeanCopier /Apache BeanUtils /Apache PropertyUtils /Dozer,然而这些工具类转换也并不稳妥,有时转换失败了也很难排查问题.
实体转换类选择
各种转换工具类,在实际开发中应该选择哪种?相信很多人在开发中选择Apache BeanUtils, 毕竟是Apache旗下,稳定可靠,可是这个工具类却被阿里开发公约点名了:
阿里开发公约认为该工具类性能差,还推荐了其他的工具类,最后又说是浅拷贝,啥是浅拷贝?
如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。 就是地址值的指向,也是不靠谱的.
MapStruct 简介
翻开MapStruct官网,描述很清楚:
大致意思是MapStruct是一个代码映射工具,能够保证高效率,并且能让开发人员快速定位到错误,使用了注释处理,能简单接入.
MapStruct 接入与使用
MapStruct 官网给定了接入方法,可以通过maven方式接入,也可以通过gradle方式接入还可以通过Apache Ant方式接入.
-
依赖接入
按照官网,我们选择通过gradle接入:
-
普通转换
我们定义两个简单的实体进行测试,需要将ComputerDO转换成ComputerDTO
先定义一个转换接口,再写一个转换方法(支持注解指定)@Mapper public interface ComputerConverter { ComputerConverter INSTANCE = Mappers.getMapper(ComputerConverter.class); @Mappings({ @Mapping(source = "name", target = "computerName") }) ComputerDTO do2Dto(ComputerDO computerDO); List<ComputerDTO> listDo2Dto(List<ComputerDO> computerDOList); }
上述两个实体中有一个命名不同的字段,通过@Mapping注解指定对应的转换.
测试结果:
-
list转换
实际开发中我们通常还有对应list转换的,MapStruct默认是通过for循环调用单个转换的,所以当我们做list转换时还是需要写单个实体转换,并且把不同的映射字段写好.
-
特殊转换
实际开发中通常会出现两个类型不一致的字段进行转换,这种时候一般做法就是单独进行转换后在set值,MapStruct支持这类型的转换
如上两个类型不一致,我们通过注解指定转换类型@Mappings({ @Mapping(target = "computerName",source = "name"), @Mapping(target = "time", dateFormat = "yyyy-MM-dd HH:mm:ss") }) ComputerDTO do2Dto(ComputerDO computerDO);
有时候在DO或DTO中有一个list我们期望转换后作为一个String类型,或者是更加特殊的类型,我们应该怎样做?
在转换接口中自定义一个default转换方法 用expression指定这样就可以做到特殊转换.
default方法:Java 8 引入的新的语言特性,用关键字default来标注,被default所标注的方法,需要提供实现,而子类可以选择实现或者不实现该方法
MapStruct 还支持很多特殊的转换技巧,可以通过官网例子进行学习.
MapStruct怎样做到的?
其实我们点开我们所写转换接口的实现类我们就知道这一切的原理.
如上是MapStruct在编译的时候替我们生成的代码,我们一切的注解都通过编译时生成对应的代码,所以在开发的时候可以通过该实现来查看我们所写代码是否有问题.