0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

对象转换工具:MapStruct 库

科技绿洲 来源:Java技术指北 作者:Java技术指北 2023-10-08 14:39 次阅读

在我们日常开发的程序中,为了各层之间解耦,一般会定义不同的对象用来在不同层之间传递数据,比如xxxDTO、xxxVO、xxxQO,当在不同层之间传输数据时,不可避免地经常需要将这些对象进行相互转换。

今天给大家介绍一个对象转换工具MapStruct,代码简洁安全、性能高,强烈推荐

MapStruct简介

MapStruct是一个代码生成器,它基于约定优于配置,极大地简化了JavaBean类型之间映射的实现。特点如下:

  1. 基于注解
  2. 在编译期自动生成映射转换代码
  3. 类型安全、高性能、无依赖性、易于理解阅读

MapStruct入门

1. 引入依赖

这里使用Gradle构建

dependencies{implementation'org.mapstruct:mapstruct:1.4.2.Final'annotationProcessor'org.mapstruct:mapstruct-processor:1.4.2.Final'}
2. 需要转换的对象

创建两个示例对象(e.g. 将Demo对象转换为DemoDto对象)

/** * 源对象 */@DatapublicclassDemo{privateIntegerid;privateStringname; }/** * 目标对象 */@DatapublicclassDemoDto{privateIntegerid;privateStringname; }
3. 创建转换器

只需要创建一个转换器接口类,并在类上添加 @Mapper 注解即可(官方示例推荐以 xxxMapper 格式命名转换器名称)

@MapperpublicinterfaceDemoMapper{//使用Mappers工厂获取DemoMapper实现类DemoMapper INSTANCE = Mappers.getMapper(DemoMapper.class);//定义接口方法,参数为来源对象,返回值为目标对象DemoDtotoDemoDto(Demo demo); }
4. 验证
publicstaticvoidmain(String[] args){ Demo demo =newDemo(); demo.setId(111); demo.setName("hello"); DemoDto demoDto = DemoMapper.INSTANCE.toDemoDto(demo); System.out.println("目标对象demoDto为:"+ demoDto);//输出结果:目标对象demoDto为:DemoDto(id=111, name=hello)}

测试结果如下:

目标对象demoDto为:DemoDto(id=111, name=hello)

达到了我们的预期结果。

5. 自动生成的实现类

为什么声明一个接口就可以转换对象呢?我们看一下MapStruct在编译期间自动生成的实现类:

@Generated( value ="org.mapstruct.ap.MappingProcessor", date ="2022-09-01T17:54:38+0800", comments ="version: 1.4.2.Final, compiler: IncrementalProcessingEnvironment from gradle-language-java-7.3.jar, environment: Java 1.8.0_231 (Oracle Corporation)")publicclassDemoMapperImplimplementsDemoMapper{@OverridepublicDemoDtotoDemoDto(Demo demo){if( demo ==null) {returnnull; } DemoDto demoDto =newDemoDto(); demoDto.setId( demo.getId() ); demoDto.setName( demo.getName() );returndemoDto; } }

可以看到,MapStruct帮我们将繁杂的代码自动生成了,而且实现类中用的都是最基本的get、set方法,易于阅读理解,转换速度非常快。

MapStruct进阶

上面的例子只是小试牛刀,下面开始展示MapStruct的强大之处。

(限于篇幅,这里不展示自动生成的实现类和验证结果,大家可自行测试)

场景1:属性名称不同、(基本)类型不同
  • 属性名称不同:在方法上加上@Mapping注解,用来映射属性
  • 属性基本类型不同:基本类型和String等类型会自动转换

关键字:@Mapping注解

/** * 来源对象 */@DatapublicclassDemo{privateIntegerid;privateStringname; }/** * 目标对象 */@DatapublicclassDemoDto{privateStringid;privateStringfullname; }/** * 转换器 */@MapperpublicinterfaceDemoMapper{ DemoMapper INSTANCE = Mappers.getMapper(DemoMapper.class); @Mapping(target ="fullname", source ="name") DemoDto toDemoDto(Demo demo); }
场景2:统一映射不同类型

下面例子中,time1、time2、time3都会被转换,具体说明看下面的注释:

/** * 来源对象 */@DatapublicclassDemo{privateInteger id;privateStringname;/** * time1、time2名称相同,time3转为time33 * 这里的time1、time2、time33都是Date类型 */privateDatetime1;privateDatetime2;privateDatetime3; }/** * 目标对象 */@DatapublicclassDemoDto{privateStringid;privateStringname;/** * 这里的time1、time2、time33都是String类型 */privateStringtime1;privateStringtime2;privateStringtime33; }/** * 转换器 */@MapperpublicinterfaceDemoMapper { DemoMapper INSTANCE = Mappers.getMapper(DemoMapper.class);@Mapping(target ="time33", source ="time3") DemoDto toDemoDto(Demo demo);//MapStruct会将所有匹配到的://源类型为Date、目标类型为String的属性,//按以下方法进行转换staticStringdate2String(Datedate){SimpleDateFormat simpleDateFormat =newSimpleDateFormat("yyyy-MM-dd HH:mm:ss");StringstrDate = simpleDateFormat.format(date);returnstrDate; } }
场景3:固定值、忽略某个属性、时间转字符串格式

一个例子演示三种用法,具体说明看注释,很容易理解:

关键字:ignore、constant、dateFormat

/** * 来源对象 */@DatapublicclassDemo{privateInteger id;privateStringname;privateDatetime; }/** * 目标对象 */@DatapublicclassDemoDto{privateStringid;privateStringname;privateStringtime; }/** * 转换器 */@MapperpublicinterfaceDemoMapper { DemoMapper INSTANCE = Mappers.getMapper(DemoMapper.class);//id属性不赋值@Mapping(target ="id", ignore =true)//name属性固定赋值为“hello”@Mapping(target ="name", constant ="hello")//time属性转为yyyy-MM-dd HH:mm:ss格式的字符串@Mapping(target ="time", dateFormat ="yyyy-MM-dd HH:mm:ss") DemoDto toDemoDto(Demo demo); }
场景4:为某个属性指定转换方法

场景2中,我们是按照某个转换方法,统一将一种类型转换为另外一种类型;而下面这个例子,是为某个属性指定方法:

关键字:@Named注解、qualifiedByName

/** * 来源对象 */@DatapublicclassDemo{privateInteger id;privateStringname; }/** * 目标对象 */@DatapublicclassDemoDto{privateStringid;privateStringname; }/** * 转换器 */@MapperpublicinterfaceDemoMapper { DemoMapper INSTANCE = Mappers.getMapper(DemoMapper.class);//为name属性指定@Named为convertName的方法进行转换@Mapping(target ="name", qualifiedByName ="convertName") DemoDto toDemoDto(Demo demo);@Named("convertName")staticStringaaa(Stringname){return"姓名为:"+ name; } }
场景5:多个参数合并为一个对象

如果参数为多个的话,@Mapping注解中的source就要指定是哪个参数了,用点分隔:

关键字:点(.)

/** * 来源对象 */@DatapublicclassDemo{privateIntegerid;privateStringname; }/** * 目标对象 */@DatapublicclassDemoDto{privateStringfullname;privateStringtimestamp; }/** * 转换器 */@MapperpublicinterfaceDemoMapper{ DemoMapper INSTANCE = Mappers.getMapper(DemoMapper.class);//fullname属性赋值demo对象的name属性(注意这里.的用法)//timestamp属性赋值为传入的time参数@Mapping(target ="fullname", source ="demo.name") @Mapping(target ="timestamp", source ="time") DemoDto toDemoDto(Demo demo,Stringtime); }
场景6:已有目标对象,将源对象属性覆盖到目标对象

覆盖目标对象属性时,一般null值不覆盖,所以需要在类上的@Mapper注解中添加属性:nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE代表null值不进行赋值。

关键字:@MappingTarget注解、nullValuePropertyMappingStrategy

/** * 来源对象 */@DatapublicclassDemo{privateInteger id;privateString name; }/** * 目标对象 */@DatapublicclassDemoDto{privateString id;privateString name; }/** * 转换器 */@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE, nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)publicinterfaceDemoMapper{ DemoMapper INSTANCE = Mappers.getMapper(DemoMapper.class);//将已有的目标对象当作一个参数传进来DemoDtotoDemoDto(Demo demo,@MappingTargetDemoDto dto); }
场景7:源对象两个属性合并为一个属性

这种情况可以使用@AfterMapping注解。

关键字:@AfterMapping注解、@MappingTarget注解

/** * 来源对象 */@DatapublicclassDemo{privateInteger id;privateStringfirstName;privateStringlastName; }/** * 目标对象 */@DatapublicclassDemoDto{privateStringid;privateStringname; }/** * 转换器 */@MapperpublicinterfaceDemoMapper { DemoMapper INSTANCE = Mappers.getMapper(DemoMapper.class); DemoDto toDemoDto(Demo demo);//在转换完成后执行的方法,一般用到源对象两个属性合并为一个属性的场景//需要将源对象、目标对象(@MappingTarget)都作为参数传进来,@AfterMappingstaticvoidafterToDemoDto(Demo demo,@MappingTargetDemoDto demoDto){Stringname = demo.getFirstName() + demo.getLastName(); demoDto.setName(name); } }

小结

本文介绍了对象转换工具 MapStruct 库,以安全、简洁、优雅的方式来优化我们的转换代码。

从文中的示例场景中可以看出,MapStruct 提供了大量的功能和配置,使我们可以快捷的创建出各种或简单或复杂的映射器。而这些,也只是 MapStruct 库的冰山一角,还有很多强大的功能文中没有提到,感兴趣的朋友可以自行查看官方文档。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表德赢Vwin官网 网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 对象
    +关注

    关注

    1

    文章

    38

    浏览量

    17329
  • 传输数据
    +关注

    关注

    1

    文章

    102

    浏览量

    16050
  • 代码生成器
    +关注

    关注

    0

    文章

    25

    浏览量

    9048
收藏 人收藏

    评论

    相关推荐

    原理图格式转换工具

    现在正在做一个格式 转换工具,大家有什么好的建议和思路没有呢,也就是可以protel的格式,orcad等原理图, 格式的互相 转换.
    发表于06-17 14:08

    高质量PDF转换工具

    PDF文件 转换王PDF文件 转换王V1.79绿色特别版(高质量PDF 转换工具)下载介绍:
    发表于06-10 09:24 0次下载

    TKStudio 文件捆绑转换工具

    TKStudio 文件捆绑 转换工具介绍
    发表于07-19 15:51 65次下载

    PCB图片转换工具

    德赢Vwin官网 网站提供《PCB图片 转换工具.rar》资料免费下载
    发表于06-18 16:42 32次下载

    pcb单位转换工具下载

    资料介绍说明: 软件名称 :pcb 转换工具文件大小:2.03MB 文件格式:rar 软件语言:简体中文 运行环境: win2003winxpwin2000win9x pcb单位 转换工具,pcb工程专用 工具,方便在设计过程
    发表于11-05 09:40 47次下载
    pcb单位<b class='flag-5'>转换工具</b>下载

    LCD彩色图片转换工具

    德赢Vwin官网 网站提供《LCD彩色图片 转换工具.exe》资料免费下载
    发表于06-16 15:17 2次下载

    IPTV版遥控转换工具

    IPTV版遥控 转换工具根据说明自己看,不明白的找度娘。
    发表于05-03 15:15 0次下载

    进制转换工具

    进制 转换工具
    发表于12-01 16:44 3次下载

    LCD彩色图片转换工具BMP_to_H

    LCD彩色图片 转换工具BMP_to_H
    发表于12-28 10:16 11次下载

    protel-pads转换工具

    protel-pads 转换工具
    发表于02-14 17:25 0次下载

    ASCII码转换工具下载

    数据 转换工具
    发表于06-09 15:03 6次下载

    C浮点数与字符转换工具

    C浮点数与字符 转换工具免费下载。
    发表于06-19 18:17 0次下载

    xgus转换工具

    xgus 转换工具
    发表于04-28 13:52 2次下载

    视频格式转换工具

    视频格式 转换工具
    发表于04-28 13:58 1次下载

    音频格式转换工具

    音频格式 转换工具
    发表于04-28 13:59 6次下载