当前位置: 首页 > news >正文

MapStruct使用方法

一、用途

1.1 优势

与动态映射框架相比,MapStruct 具有以下优势:
(1)通过使用普通方法getter、setter调用,而不是反射来快速执行,效率很高。
(2)编译时类型安全:只能映射相互映射的对象和属性,不会将其余模型属性进行映射。

二、依赖

<!-- Maven 依赖 -->
<dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct</artifactId><version>1.4.2.Final</version>
</dependency>

三、使用详解-常规映射

3.1 基本映射(属性相同)

创建映射接口:

//spring: 生成的实现类上面会自动添加一个@Component注解,可以通过Spring的 @Autowired方式进行注入
//default: 这是默认的情况,mapstruct 不使用任何组件类型, 可以通过Mappers.getMapper(Class)方式获取自动生成的实例对象。
@Mapper(componentModel = "spring")
public interface UserAssembler {UserAssembler INSTANCE = Mappers.getMapper(UserAssembler.class);UserDTO toUserDTO(User user);User toUser(UserDTO userDTO);
}

注意:

上述代码中,UserAssembler INSTANCE = Mappers.getMapper(UserAssembler.class); 有什么作用?
——前面我们在Mapper接口中代码中一直有一行代码,如下所示,是MapStruct为我们提供的映射工厂,指定接口类型后自动帮我们创建接口的实现,且保证是线程安全的单例,无需自己手动创建。
例如,在以下代码中,我们创建了UserMapper的单例实例,并使用它转换两个不同的User对象:

 但是,某些时候尤其是在做项目时,我们用到了Sping,希望映射后的新实例是交给Spring管理。这时候就需要进行依赖注入了。只需要在Mapper接口中的@Mapper注解中加入componentModel = "spring"即可

UserAssembler  userAssembler = UserAssembler.INSTANCE;User user1 = new User();
user1.setId(1);
user1.setName("Alice");User user2 = new User();
user2.setId(2);
user2.setName("Bob");UserDTO userDTO1 = userAssembler.toUserDTO(user1);
UserDTO userDTO2 = userAssembler.toUserDTO(user2);

通过UserAssembler.INSTANCE获取UUserAssembler单例实例,我们可以在任何时候重复使用这个实例来转换不同的User对象。

 需要注意的是,为了能够成功生成映射代码,映射接口必须使用@Mapper注解进行标识。同时,MapStruct也支持在映射接口中定义多个映射方法,每个方法使用不同的@Mapping注解来描述源对象和目标对象之间的映射关系。

 总结来说,MapStruct中的Mappers.getMapper()方法可以获得映射接口的实例,UserAssembler INSTANCE = Mappers.getMapper(UserAssembler.class);则是创建了一个静态字段用于存储UserMapper单例实例的引用,方便在程序中反复使用。

3.2 基本映射(属性不同)

直接给方法了:

@Mappings({@Mapping(source = "id", target = "userId"),@Mapping(source = "name", target = "userName")})UserVO4 toConvertVO(User source);

3.3 表达式

	@Mappings({@Mapping(target = "createTime", expression = 	"java(com.java.mmzsblog.util.DateTransform.strToDate(source.getCreateTime()))"),})UserVO3 toConvertVO3(User source);User fromConvertEntity3(UserVO3 userVO3);

3.4 具有多个源参数的映射方法

@Mapper
public interface UserAssembler {UserAssembler INSTANCE = Mappers.getMapper(UserAssembler.class);@Mappings({@Mapping(source = "user.name", target = "fullName"),@Mapping(source = "address.street", target = "streetName"),// 更多映射关系...})UserDTO toUserDTO(User user, Address address);
}

3.5 将嵌套的 bean 属性映射到当前目标

参考3.4:

@Mapper
public interface UserAssembler {UserAssembler INSTANCE = Mappers.getMapper(UserAssembler.class);@Mapping(source = "address.street", target = "streetName")UserDTO toUserDTO(User user);AddressDTO toAddressDTO(Address address);
}

3.4 Map到Bean的映射

@Mapper
public interface UserAssembler {UserAssembler INSTANCE = Mappers.getMapper(UserAssembler.class);@Mapping(target = "name", source = "map.name")@Mapping(target = "age", source = "map.age")User mapToUser(Map<String, Object> map);
}

四、使用详解-数据类型转化

4.1 类型转换

4.1.1 使用自定义方法:

@Mapper
public interface UserAssembler {UserAssembler INSTANCE = Mappers.getMapper(UserAssembler .class);@Mapping(target = "age", source = "dto.age")User toUser(UserDTO dto);default LocalDate mapToLocalDate(String dateStr) {return LocalDate.parse(dateStr);}
}

 在上述示例中,我们定义了一个mapToLocalDate方法,该方法将接收一个String类型的参数dateStr并返回一个LocalDate类型的结果。在toUser方法中,我们使用@Mapping注解指定将dto.age映射到User对象的age属性。MapStruct会自动调用mapToLocalDate方法进行数据类型转换。

4.1.2 使用内置的转换器:

 MapStruct提供了一些内置的转换器,用于常见的类型转换。例如,String到LocalDate、String到BigDecimal等。你可以直接在映射方法上使用这些转换器,而无需编写额外的代码。

@Mapper
public interface UserAssembler{UserAssemblerINSTANCE = Mappers.getMapper(UserAssembler.class);@Mapping(target = "birthDate", source = "dto.birthDate", dateFormat = "yyyy-MM-dd")User toUser(UserDTO dto);
}

 在上述示例中,我们使用dateFormat属性指定了dto.birthDate字符串的日期格式,MapStruct会根据指定的格式将其转换为User对象的birthDate属性类型。

 这只是两种常见的方式,MapStruct还提供了更多高级的自定义转换选项,例如使用自定义的转换器类、使用注解标记转换器等。你可以根据具体的需求选择适合的方式进行数据类型转换。

 总结来说,MapStruct提供了多种方式来进行数据类型转换,包括自定义方法和使用内置的转换器。通过灵活运用这些转换选项,你可以轻松地处理不同类型之间的映射和转换。

4.2 隐式类型转化

 在MapStruct中,隐式类型转换指的是在映射过程中,不需要显式地指定数据类型转换,而是根据数据类型自动进行转换。
例如,在以下示例中,我们定义了一个User对象和一个UserDTO对象,并使用MapStruct将它们进行映射:

@Mapper
public interface UserAssembler{UserAssembler INSTANCE = Mappers.getMapper(UserAssembler.class);UserDTO toUserDTO(User user);
}

 在上述示例中,我们并没有指定具体的字段映射规则,而是通过方法名匹配来自动映射User对象和UserDTO对象的属性,这就是MapStruct中的隐式类型转换。在默认情况下,如果两个属性的名称和类型都相同,则会自动进行数据的映射。

 当然,如果属性名称或数据类型不匹配,则需要通过@Mapping注解或自定义方法来指定映射规则。例如,在以下示例中,User对象的birthDate属性类型为Date,而UserDTO对象的birthDate属性类型为String,因此我们需要指定类型转换规则:

@Mapper
public interface UserAssembler{UserAssembler INSTANCE = Mappers.getMapper(UserAssembler.class);@Mapping(target = "birthDate", source = "user.birthDate", dateFormat = "yyyy-MM-dd")UserDTO toUserDTO(User user);
}

 在上述示例中,我们使用@Mapping注解指定了将User对象的birthDate属性转换为字符串类型,并指定了日期格式为yyyy-MM-dd。

 总之,MapStruct支持隐式类型转换,可以根据属性名称和数据类型自动进行数据映射。当然,在需要进行类型转换时,你也可以通过@Mapping注解或自定义方法来指定映射规则。

4.3 从int到String的转换

@Mapper
public interface UserAssembler{UserAssembler INSTANCE = Mappers.getMapper(UserAssembler.class);@Mapping(target = "ageStr", expression = "java(String.valueOf(user.getAge()))")UserDTO toUserDTO(User user);
}

或者

@Mapper
public interface CarMapper {@Mapping(source = "price", numberFormat = "$#.00")CarDto carToCarDto(Car car);@IterableMapping(numberFormat = "$#.00")List<String> prices(List<Integer> prices);
}

4.3 从 BigDecimal 到 String 的转换

@Mapper
public interface UserAssembler{UserAssembler INSTANCE = Mappers.getMapper(UserAssembler.class);@Mapping(target = "salaryStr", expression = "java(user.getSalary().toString())")UserDTO toUserDTO(User user);
}

 在上述示例中,我们使用expression属性指定了将user.getSalary()的结果转换为String类型,并映射到UserDTO对象的salaryStr属性。

或者

@Mapper
public interface CarMapper {@Mapping(source = "power", numberFormat = "#.##E0")CarDto carToCarDto(Car car);}

4.4 从日期到字符串的转换

@Mapper
public interface UserAssembler{UserAssembler INSTANCE = Mappers.getMapper(UserAssembler.class);@Mapping(target = "birthDateStr", dateFormat = "yyyy-MM-dd")UserDTO toUserDTO(User user);
}

 在上述示例中,我们使用dateFormat属性指定了将User对象的birthDate属性转换为String类型,并指定了日期格式为yyyy-MM-dd。MapStruct会自动进行日期转换并将结果映射到UserDTO对象的birthDateStr属性。

五、使用详解-多个对象,源数据来源普通参数

@Mapper
public interface AddressAssembler {@Mapping(target = "description", source = "person.description")@Mapping(target = "houseNumber", source = "hn")DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Integer hn);
}

六、条件映射

 条件映射属于一种 源存在性检测,不同于默认的调用 XYZ 属性的 hasXYZ 方法进行存在性检测,条件映射允许自定义检测方法,来决定是否对属性进行映射。

 在方法上使用 org.mapstruct.Condition 注解并返回 boolean 类型值的方法,即为自定义的条件检测方法。

例如,您只想映射不为 null 且不是空的字符串属性时:

@Mapper
public interface CarMapper {CarDto carToCarDto(Car car);@Conditiondefault boolean isNotEmpty(String value) {return value != null && !value.isEmpty();}
}

七、限定符结合默认值

使用限定符指定生成默认值方法。

  @Mapperpublic interface MovieMapper {@Mapping( target = "category", qualifiedByName = "CategoryToString", defaultValue = "DEFAULT" )GermanRelease toGerman( OriginalRelease movies );@Named("CategoryToString")default String defaultValueForQualifier(Category cat) {// some mapping logic}}

此时 category 为空时,将使用 defaultValueForQualifier 方法生成默认值。

八、使用详解-集合映射

8.1 具有List映射方法的映射器

映射list,一般要在映射器里先定义好对应的对象映射器:

@Mapper
public interface ExampleMapper {ExampleMapper INSTANCE = Mappers.getMapper(ExampleMapper.class);TargetObject map(SourceObject sourceObject);List<TargetObject> mapList(List<SourceObject> sourceList);
}

8.2 Map集合映射

参见【3.4】

九、使用详解-值映射

9.1 将枚举映射到枚举类型

  MapStruct 中将一个枚举映射到另一个枚举类型,您可以使用 @Mapping 注解来指定枚举字段的映射规则。以下是一个示例:

@Mapper
public interface ExampleMapper {ExampleMapper INSTANCE = Mappers.getMapper(ExampleMapper.class);@Mapping(target = "targetEnum", source = "sourceEnum")TargetObject map(SourceObject sourceObject);
}

参考:
MapStruct的基础用法详解
MapStruct使用说明

相关文章:

MapStruct使用方法

一、用途 1.1 优势 与动态映射框架相比&#xff0c;MapStruct 具有以下优势&#xff1a; &#xff08;1&#xff09;通过使用普通方法getter、setter调用&#xff0c;而不是反射来快速执行&#xff0c;效率很高。 &#xff08;2&#xff09;编译时类型安全&#xff1a;只能映…...

【LeetCode】50. Pow(x, n)

1 问题 实现 pow(x, n) &#xff0c;即计算 x 的整数 n 次幂函数&#xff08;即&#xff0c; x n x^n xn &#xff09;。 示例 1&#xff1a; 输入&#xff1a;x 2.00000, n 10 输出&#xff1a;1024.00000 示例 2&#xff1a; 输入&#xff1a;x 2.10000, n 3 输出&a…...

vue2技能树(2)-模板语法、vue的工具链、渐进式框架

目录 Vue2技能树Vue 2 简单的模板语法详解插值绑定属性指令v-if 和 v-elsev-forv-on 计算属性过滤器插槽 Vue 2 生态系统详解1. Vue Router2. Vuex3. Vue CLI4. Axios5. Vue Devtools6. Element UI、Vuetify、Quasar等UI框架7. Nuxt.js8. Vue Apollo、Vue Router、Vue Fire等插…...

【Git系列教程-目录大纲】

《Git系列教程-目录大纲》 完完全全从零开始深入学习Git&#xff0c;教程配图200张&#xff0c;其中包括包括Git基本命令、命令原理、Git底层命令、分支、分支的原理、Git代码冲突原理/解决、tag标签、Git存储状态、分支合并原理、典型合并、快进合并、同轴开发、非同轴开发、…...

【高等数学】导数与微分

文章目录 1、导数的概念1.1、引例1.1.1、变速直线运动瞬时速度1.1.2、曲线的切线 1.2、导数的定义1.3、证明常用导数1.4、导数的几何意义1.5、可导与连续的关系 2、函数的求导法则2.1、函数的和、差、积、商的求导法则2.2、反函数的求导法则2.3、复合函数的求导法则2.4、基本初…...

springboot之quartz动态可控定时任务

Quartz Quartz是一个开源的任务调度框架&#xff0c;可以用来实现定时任务的调度&#xff0c;如定时发送邮件、定时备份数据等。Quartz具有很高的可靠性和灵活性&#xff0c;支持集群部署和分布式调度&#xff0c;并且提供了丰富的API和插件&#xff0c;可以轻松实现复杂的调度…...

什么是CSS的外边距重叠?

区块的上下外边距有时会合并&#xff08;折叠&#xff09;为单个边距&#xff0c;其大小为两个边距中的最大值&#xff08;或如果它们相等&#xff0c;则仅为其中一个&#xff09;&#xff0c;这种行为称为外边距折叠。注意&#xff1a;有设定浮动和绝对定位的元素不会发生外边…...

设计模式之抽象工厂模式

前言 工厂模式一般指的是简单工厂模式、工厂方法模式、抽象工厂模式&#xff0c;这是三种工厂模式的最后一篇&#xff0c;其他两种的文章链接如下&#xff1a; 设计模式之简单工厂模式-CSDN博客 设计模式之工厂方法模式-CSDN博客 建议三种模式放在一起对比学习&#xff0c;…...

Compose预处理组件大比拼:性能、应用场景和可视化对比总结

在机器学习的世界里,预处理组件就像是厨师的烹饪工具。选择合适的工具不仅可以让整个烹饪过程更加顺畅,还能确保最终的菜肴更加美味。 本文将深入探讨四种“烹饪工具”:TransformedTargetRegressor、make_column_transformer、make_column_selector和ColumnTransformer。通…...

【小米】Linux 实习生

下午不准备去图书馆自习来着&#xff0c;中午就狠狠地多睡了一个小时&#xff0c;三点起床靠在椅子上剥柚子&#xff0c;太爽了&#xff0c;这秋天的下午。“邮件&#xff1a;小米公司邀请你预约面试时间”.......... 我擦&#xff0c;投了一个月了&#xff0c;认真准备的时候…...

python一点通:coroutine (协程)是什么和重要知识点?

协程已经成为Python用于编写并发和异步代码的重要工具之一。在这篇博客文章中&#xff0c;我们将深入探讨协程是什么&#xff0c;它们的优点&#xff0c;以及它们与传统的线程和进程有何不同。 什么是协程&#xff1f; 协程是用于合作式多任务处理的子程序&#xff08;或函数…...

QCC51XX-QCC30XX系列开发教程(实战篇) 之 12.1-空间音频相关模块的概述

查看全部教程开发请点击:全网最全-QCC51xx-QCC30xx(TWS)系列从入门到精通开发教程汇总(持续更新中) ==================================================================== 版权归作者所有,未经允许,请勿转载。 ==========================================...

Servlet的生命周期

2023.10.18 WEB容器创建的Servlet对象&#xff0c;这些Servlet对象都会被放到一个集合当中&#xff08;HashMap&#xff09;&#xff0c;这个集合当中存储了Servlet对象和请求路径之间的关系 。只有放到这个HashMap集合中的Servlet才能够被WEB容器管理&#xff0c;自己new的Ser…...

2.4 如何在FlinkSQL使用DataGen(数据生成器)

1、DataGen SQL 连接器 FLinkSQL中可以使用内置的DataGen SQL 连接器来生成测试数据 官网链接&#xff1a;DataGen SQL 连接器 2、随机数数据生成器 随机数数据生成器支持随机生成 char、varchar、binary、varbinary、string 类型的数据 它是一个无界流的数据生成器 -- TO…...

Gin + Ant Design Pro JWT认证

文章目录 一&#xff1a;介绍二&#xff1a;Gin JWT 后台1. Claims 定义2. 创建和解析Token3. Gin中间件编写4. 辅助函数 三&#xff1a;Ant Design Pro JWT认证四&#xff1a;Gin中间件和使用示范 一&#xff1a;介绍 JWT现在比较流行的认证方式&#xff0c;微服务中使用特别…...

canvas实现图片标注,绘制区域

使用canvas绘制通过多边形标注区域 AI视频项目中需要分析图片&#xff0c;需要前台绘制区域&#xff0c;后端获取坐标然后识别图像&#xff0c;通过canvas 获取点然后连线绘图 HEML代码段 <div class"areaDrawing"><img src"/assets/images/snapPhotos…...

SELECT COUNT(*) 会造成全表扫描吗?

前言 SELECT COUNT(*)会不会导致全表扫描引起慢查询呢&#xff1f; SELECT COUNT(*) FROM SomeTable 网上有一种说法&#xff0c;针对无 where_clause 的 COUNT(*)&#xff0c;MySQL 是有优化的&#xff0c;优化器会选择成本最小的辅助索引查询计数&#xff0c;其实反而性能…...

python考前复习(90题)

文章目录 1.Python特性的是( )。 A. 面向对象 B. 高可移植性 C. 开源、免费 2.临时改变Python语言安装源应当使用的选项是 –index-url 3.Python脚本文件的扩展名为( ) .py 4.安装Python语言的软件包使用的命令是&#xff08; &#xff09; pip install 5 . (单选题)以下哪项是…...

根据SpringBoot Guides完成进行示例学习(详细步骤)

目录 1.打开Spring | Guides官网&#xff0c;或者直接搜索springboot都可 2.选择要学习的内容 3.根据提示的网址&#xff0c;Git到本地 4.将文件用IDEA打开&#xff0c;根据教程完成示例&#xff0c;这里不做细致讲解 5.运行项目 6.在终端查看运行结果 以Scheduling Task…...

waf、yakit和ssh免密登录

WAF安全狗 脏数据适用于所有漏洞绕过waf&#xff0c;但是前提条件垃圾信息必须放在危险信息前&#xff0c;是不能打断原有数据包的结构&#xff0c;不能影响后端对数据包的解析。 以DVWA靶场文件上传为例 新建php文件 上传文件被安全狗拦截 使用bp抓包查看 在数据包Content-…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

绕过 Xcode?使用 Appuploader和主流工具实现 iOS 上架自动化

iOS 应用的发布流程一直是开发链路中最“苹果味”的环节&#xff1a;强依赖 Xcode、必须使用 macOS、各种证书和描述文件配置……对很多跨平台开发者来说&#xff0c;这一套流程并不友好。 特别是当你的项目主要在 Windows 或 Linux 下开发&#xff08;例如 Flutter、React Na…...

云安全与网络安全:核心区别与协同作用解析

在数字化转型的浪潮中&#xff0c;云安全与网络安全作为信息安全的两大支柱&#xff0c;常被混淆但本质不同。本文将从概念、责任分工、技术手段、威胁类型等维度深入解析两者的差异&#xff0c;并探讨它们的协同作用。 一、核心区别 定义与范围 网络安全&#xff1a;聚焦于保…...

命令行关闭Windows防火墙

命令行关闭Windows防火墙 引言一、防火墙:被低估的"智能安检员"二、优先尝试!90%问题无需关闭防火墙方案1:程序白名单(解决软件误拦截)方案2:开放特定端口(解决网游/开发端口不通)三、命令行极速关闭方案方法一:PowerShell(推荐Win10/11)​方法二:CMD命令…...

网页端 js 读取发票里的二维码信息(图片和PDF格式)

起因 为了实现在报销流程中&#xff0c;发票不能重用的限制&#xff0c;发票上传后&#xff0c;希望能读出发票号&#xff0c;并记录发票号已用&#xff0c;下次不再可用于报销。 基于上面的需求&#xff0c;研究了OCR 的方式和读PDF的方式&#xff0c;实际是可行的&#xff…...