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

别再用 BeanUtils 了,这款 PO VO DTO 转换神器不香么?

老铁们是不是经常为写一些实体转换的原始代码感到头疼,尤其是实体字段特别多的时候。介绍一个开源项目 mapstruct ,可以轻松优雅的进行转换,简化你的代码。当然有的人喜欢写get set,或者用BeanUtils 进行复制,代码只是工具,本文只是提供一种思路。

先贴下官网地址吧:https://mapstruct.org

一、MapStruct 的基本概念

  • 映射器(Mapper): 在 MapStruct 中,映射器是一个 Java 接口,用于指定两个 JavaBean 之间的映射。映射器通常使用注解进行注释,以指定映射器的输入类型和输出类型。映射器定义了转换的规则和逻辑。
  • 映射器工厂(MapperFactory): 映射器工厂是 MapStruct 中的核心组件之一。它负责创建映射器实例,并维护映射器的缓存。在应用程序中,通常只需要创建一个映射器工厂实例,然后使用它来创建所有的映射器。
  • 映射器配置(MapperConfig): 映射器配置是 MapStruct 中的另一个核心组件,用于指定映射器的行为和配置。在映射器配置中,可以定义类型转换器、映射器实现类和其他映射器配置选项。
  • 映射器生命周期方法(Lifecycle Methods): 映射器生命周期方法是 MapStruct 提供的一个特性,它允许在映射器实例创建和销毁时执行自定义逻辑。映射器生命周期方法可以用来进行一些初始化和清理工作。
  • 映射器选项(Mapper Options): 映射器选项是 MapStruct 提供的另一个特性,它允许在映射器级别指定一些选项和配置。映射器选项可以用来控制映射器的行为和性能。

二、MapStruct 的使用

  1. 环境搭建

在使用 MapStruct 之前,需要先配置环境。MapStruct 的最新版本可以在官网上下载。MapStruct 是一个注解处理器,因此还需要将 MapStruct 添加到 Maven 或 Gradle 项目中。

  1. 映射器定义

定义一个映射器,需要创建一个 Java 接口,并使用 @Mapper 注解注释它。在映射器接口中,可以定义多个映射方法。每个映射方法的输入类型和输出类型必须在 @Mapper 注解中进行声明。

例如,假设有两个 JavaBean,分别为 Person 和 PersonDto,它们的属性如下:

public class Person {private Long id;private String name;private int age;// getters and setters
}public class PersonDto {private Long id;private String fullName;private int age;// getters
}

假设需要将 Person 转换为 PersonDto,可以定义一个映射器如下:

@Mapper
public interface PersonMapper {PersonMapper INSTANCE = Mappers.getMapper( PersonMapper.class );@Mapping(source = "name", target = "fullName")PersonDto personToDto(Person person);
}

在上面的代码中,@Mapper 注解指定了映射器的输入类型和输出类型。PersonMapper 接口中定义了一个映射方法 personToDto,用于将 Person 对象转换为 PersonDto 对象。@Mapping 注解指定了属性之间的映射关系。

  1. 映射器工厂创建

创建一个映射器工厂,需要使用 MapStruct 提供的工厂类 Mappers。Mappers.getMapper() 方法接受一个映射器接口的 Class 对象作为参数,并返回一个映射器实例。

例如,可以使用以下代码创建 PersonMapper 实例:

PersonMapper mapper = PersonMapper.INSTANCE;
  1. 映射器使用

使用映射器进行转换,只需要调用映射器的相应方法即可。例如,可以使用以下代码将 Person 对象转换为 PersonDto 对象:

Person person = new Person();
person.setId(1L);
person.setName("John");
person.setAge(30);PersonDto personDto = mapper.personToDto(person);

在上面的代码中,创建了一个 Person 对象,并设置了它的属性值。然后调用映射器的 personToDto 方法将 Person 对象转换为 PersonDto 对象。

  1. 映射器配置

可以使用 @MapperConfig 注解定义一个映射器配置。在映射器配置中,可以定义类型转换器、映射器实现类和其他映射器配置选项。映射器配置可以在映射器接口中进行引用,从而影响映射器的行为和性能。

例如,可以定义一个映射器配置如下:

@MapperConfig
public interface MyMapperConfig {@Mappings({@Mapping(source = "address.street", target = "street"),@Mapping(source = "address.city", target = "city"),@Mapping(source = "address.country", target = "country")})PersonDto personToDto(Person person);
}

在上面的代码中,定义了一个 MyMapperConfig 配置类,它包含一个 personToDto 映射器方法。在这个方法中,使用 @Mapping 注解指定了属性之间的映射关系。

可以在映射器接口中引用这个配置类,如下所示:

@Mapper(config = MyMapperConfig.class)
public interface PersonMapper {PersonMapper INSTANCE = Mappers.getMapper( PersonMapper.class );PersonDto personToDto(Person person);
}

在上面的代码中,@Mapper 注解中使用 config 属性引用了 MyMapperConfig 配置类。

高级特性

类型转换器

MapStruct 可以自动进行基本类型和常见类型的转换,但是如果需要转换自定义类型或者复杂类型,可以使用类型转换器。

类型转换器是一个静态方法,接受一个参数并返回一个转换后的结果。例如,可以定义一个将 LocalDate 转换为 Date 的类型转换器如下:

javaCopy codepublic class DateMapper {public static Date toDate(LocalDate localDate) {return Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());}
}

在上面的代码中,定义了一个 toDate 类型转换器,它接受一个 LocalDate 参数并返回一个转换后的 Date 对象。

然后可以在映射器接口中使用 @Mapper 的 uses 属性引用这个类型转换器,如下所示:

javaCopy code@Mapper(uses = DateMapper.class)
public interface PersonMapper {PersonDto personToDto(Person person);
}

在上面的代码中,@Mapper 注解中使用 uses 属性引用了 DateMapper 类型转换器。

注解

MapStruct 支持自定义注解,可以使用这些注解来控制映射器的行为。例如,可以定义一个 @UpperCase 注解,用于将字符串属性转换为大写。

javaCopy code@Target(ElementType.FIELD)
@Retention(RetentionPolicy.CLASS)
public @interface UpperCase {
}

在上面的代码中,定义了一个 @UpperCase 注解,它可以应用在字段上。

然后可以在映射器接口中使用 @Mapping 注解的 qualifiedBy 属性引用这个注解,如下所示:

javaCopy code@Mapper
public interface PersonMapper {@Mapping(source = "name", target = "fullName", qualifiedBy = UpperCase.class)PersonDto personToDto(Person person);
}

在上面的代码中,@Mapping 注解中使用 qualifiedBy 属性引用了 @UpperCase 注解。

最后,需要定义一个 @BeforeMapping 方法,用于在映射之前将字符串属性转换为大写,如下所示:

javaCopy code@Mapper
public interface PersonMapper {@BeforeMappingdefault void toUpperCase(@MappingTarget PersonDto personDto, @MappingSource Person person) {personDto.setFullName(personDto.getFullName().toUpperCase());}@Mapping(source = "name", target = "fullName", qualifiedBy = UpperCase.class)PersonDto personToDto(Person person);
}

在上面的代码中,定义了一个 toUpperCase 方法,在映射之前将 fullName 属性转换为大写。可以使用 @BeforeMapping 注解标记这个方法,并指定 @MappingTarget 和 @MappingSource 参数,这样 MapStruct 就可以正确地注入映射器的输入和输出对象。

相关文章:

别再用 BeanUtils 了,这款 PO VO DTO 转换神器不香么?

老铁们是不是经常为写一些实体转换的原始代码感到头疼,尤其是实体字段特别多的时候。介绍一个开源项目 mapstruct ,可以轻松优雅的进行转换,简化你的代码。当然有的人喜欢写get set,或者用BeanUtils 进行复制,代码只是…...

LeetCode算法小抄-- 最近公共祖先 和 完全二叉树的节点个数

LeetCode算法小抄-- 最近公共祖先 和 完全二叉树的节点个数 最近公共祖先[236. 二叉树的最近公共祖先](https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/)[235. 二叉搜索树的最近公共祖先](https://leetcode.cn/problems/lowest-common-ancestor-of-a-b…...

php、redis实现分布式锁的正确写法(原子操作 通用类 加讲解)

最终代码(通用类) 1 面试中、实际工作中&#xff0c;经常涉及到 redis 分布式锁&#xff0c;正确写法如下。先奉上代码&#xff0c;再讲解。 <?php namespace app\common\library; /*** 通用分布式锁(原子操作)*/ class Lock {/*** 获取redis实例* return \Redis* throws…...

Transformer在时序预测的应⽤第一弹——Autoformer

Transformer在时序预测的应⽤第一弹——Autoformer 原文地址&#xff1a;Autoformer: Decomposition Transformers with Auto-Correlation for Long-Term Series Forecasting&#xff08;NIPS 2021&#xff09; 做长时间序列的预测 Decomposition把时间序列做拆分&#xff0c…...

文章改写神器在线-AI续写文章生成器

AI续写生成器 AI续写生成器是一种利用人工智能技术的创意工具&#xff0c;能够提高写作效率&#xff0c;为营销推广带来全新的可能性。无论你是写手、广告人员还是市场营销人员&#xff0c;这个工具都能够有效地解决你在写作中遇到的难题。 在内容创作行业中&#xff0c;原创…...

一秒钟给硬盘文件做个树状结构目录

一秒钟给硬盘文件做个树状结构目录 一、背景 对于长时间坐在电脑前的打工人来说&#xff0c;若没有养成良好文件分类习惯的话&#xff0c;年终整理电脑文件绝对是件头疼的事情。 给磁盘文件做个目录&#xff0c;一目了然文件都在哪里&#xff1f;想想都是件头疼的事情。 对于…...

电脑重装系统后会怎样?

​有小伙伴的电脑系统运行缓慢卡顿&#xff0c;现在想通过重装系统来解决问题。咨询电脑重装系统会怎么样对系统有影响吗&#xff0c;现在小编就带大家看看电脑重装系统后会怎样。 方法/步骤&#xff1a; 一、电脑重装系统会怎么样 1、我们的电脑重装系统后&#xff0c;电脑…...

100种思维模型之反熵增思维模型-47

查理芒格被誉为反熵增思维模型的倡导者。本文将介绍查理芒格的反熵增思维模型&#xff0c;并分析它的实用性。 一、什么是熵增&#xff1f; 在物理学中&#xff0c;熵是衡量系统无序程度的指标。系统的熵越高&#xff0c;其无序程度越高。这个概念也可以应用到其他领域。在金融…...

【网络安全】Xss漏洞

xss漏洞 xss漏洞介绍危害防御方法xss测试语句xss攻击语句1. 反射性xss2.存储型xss3.DOM型xssdvwa靶场各等级渗透方法xss反射型&#xff08;存储型方法一致&#xff09;LowMediumHightimpossible Dom型LowMediumHight xss漏洞介绍 定义&#xff1a;XSS 攻击全称跨站脚本攻击&am…...

17.网络爬虫—Scrapy入门与实战

这里写目录标题 Scrapy基础Scrapy运行流程原理Scrapy的工作流程Scrapy的优点 Scrapy基本使用(豆瓣网为例)创建项目创建爬虫配置爬虫运行爬虫如何用python执行cmd命令数据解析打包数据打开管道pipeline使用注意点 后记 前言&#xff1a; &#x1f3d8;️&#x1f3d8;️个人简介…...

【面试题】JavaScript 中 try...catch 的使用技巧 ?

大厂面试题分享 面试题库 前后端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 web前端面试题库 VS java后端面试题库大全 作为一位 Web 前端工程师&#xff0c;JavaScript 中的 try...catch 是我们常用的特性之一。…...

Java 命名格式规范

Java 命名格式规范 概述 简洁清爽的代码风格应该是大多数开发工程师所期待的。在编码过程中笔者常常因为起名字而纠结&#xff0c;夸张点可以说是编程 5 分钟&#xff0c;命名两小时&#xff01;究竟为什么命名成为了编码中的拦路虎。 每个公司都有不同的标准&#xff0c;目…...

【C++】STL中的容器适配器 stack queue 和 priority_queue 的模拟实现

STL中的容器适配器 一、容器适配器1、什么是容器适配器2、STL标准库中的容器适配器 二、stack的模拟实现1、stack的简单介绍2、栈的模拟实现 三、queue的模拟实现1、queue的简单介绍2、queue的模拟实现 四、priority_queue的模拟实现1、priority_queue的简单介绍2、priority_qu…...

MongoDB 聚合管道中使用算术表达式运算符

算术表达式运算符主要用于实现数字之间的算术运算&#xff0c;主要包含了对加、减、乘、除、余数、截取、舍入等算术操作。 下面我们进行详细介绍&#xff1a; 一、准备数据 初始化商品数据 db.goods.insertMany([{ "_id": 1, name: "薯片", size: &q…...

代码随想录算法训练营第四十三天-动态规划5|1049. 最后一块石头的重量 II , 494. 目标和 , 474.一和零

最后一块石头重量转化为将一个集合分隔成两个集合&#xff0c;两个集合之间的差值最小&#xff0c;就是最后剩下最小的石头重量。这里可以求集合的一个平均值&#xff0c;如果正好等于平均值&#xff0c;说明可以抵消&#xff0c;这时候重量为0&#xff0c;如果不行&#xff0c…...

《淘宝网店》:计算总收益

目录 一、题目 二、思路 1、当两个年份不一样的时候 &#xff08;1&#xff09;from年剩余之后的收益 &#xff08;2&#xff09;中间年份的全部收益 &#xff08;3&#xff09;to年有的收益 2、同一个年份 三、代码 详细注释版本&#xff1a; 简化注释版本&#xff…...

2023年03月青少年软件编程C语言一级真题答案——持续更新.....

1.字符长方形 给定一个字符,用它构造一个长为4个字符,宽为3个字符的长方形,可以参考样例输出。 时间限制:1000 内存限制:65536 输入 输入只有一行, 包含一个字符。 输出 该字符构成的长方形,长4个字符,宽3个字符。 样例输入 * 样例输出 **** **** ****#include<bi…...

家用洗地机好用吗?好用的洗地机分享

洗地机是一种高效、节能、环保的清洁设备&#xff0c;广泛应用于各种场所的地面清洁工作。它不仅可以快速清洁地面&#xff0c;还可以有效去除污渍、油渍等难以清洁的污染物&#xff0c;让地面恢复光洁如新的状态。同时&#xff0c;洗地机还可以减少清洁人员的劳动强度&#xf…...

《分解因数》:质因数分解

目录 一、题目&#xff1a; 二、思路&#xff1a; 三、代码&#xff1a; 一、题目&#xff1a; 分解因数 《分解因数》题目链接 所谓因子分解&#xff0c;就是把给定的正整数a&#xff0c;分解成若干个素数的乘积&#xff0c;即 a a1 a2 a3 ... an,并且 1 < a1…...

(排序10)归并排序的外排序应用(文件排序)

TIPS 在一些文件操作函数当中&#xff0c;fputc与fgetc这两个函数都是针对字符的&#xff0c;如果说你需要往文件里面去放入整形啊等等&#xff0c;不是字符的类型&#xff0c;这时候就用fprintf&#xff0c;fscanf在参数里面数据类型控制一下就可以。但是话说回来&#xff0c…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

C++中string流知识详解和示例

一、概览与类体系 C 提供三种基于内存字符串的流&#xff0c;定义在 <sstream> 中&#xff1a; std::istringstream&#xff1a;输入流&#xff0c;从已有字符串中读取并解析。std::ostringstream&#xff1a;输出流&#xff0c;向内部缓冲区写入内容&#xff0c;最终取…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

免费PDF转图片工具

免费PDF转图片工具 一款简单易用的PDF转图片工具&#xff0c;可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件&#xff0c;也不需要在线上传文件&#xff0c;保护您的隐私。 工具截图 主要特点 &#x1f680; 快速转换&#xff1a;本地转换&#xff0c;无需等待上…...

Kafka入门-生产者

生产者 生产者发送流程&#xff1a; 延迟时间为0ms时&#xff0c;也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于&#xff1a;异步发送不需要等待结果&#xff0c;同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...

Windows安装Miniconda

一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...

Web后端基础(基础知识)

BS架构&#xff1a;Browser/Server&#xff0c;浏览器/服务器架构模式。客户端只需要浏览器&#xff0c;应用程序的逻辑和数据都存储在服务端。 优点&#xff1a;维护方便缺点&#xff1a;体验一般 CS架构&#xff1a;Client/Server&#xff0c;客户端/服务器架构模式。需要单独…...

Rust 开发环境搭建

环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行&#xff1a; rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu ​ 2、Hello World fn main() { println…...

Golang——7、包与接口详解

包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...

在 Spring Boot 项目里,MYSQL中json类型字段使用

前言&#xff1a; 因为程序特殊需求导致&#xff0c;需要mysql数据库存储json类型数据&#xff0c;因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...