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

优雅使用 MapStruct 进行类复制

前言

在项目中,常常会遇到从数据库读取数据后不能直接返回给前端展示的情况,因为还需要对字段进行加工,比如去除时间戳记录、隐藏敏感数据等。传统的处理方式是创建一个新类,然后编写大量的 get/set 方法进行赋值,若字段很多,这无疑是一场噩梦,而且还容易出现遗漏的情况。

我们都清楚,随着工程日益成熟,模块划分会越发细致。实体类通常存放在 domain 中,但最好不要让 domain 工程被其他工程依赖。所以,当其他工程需要获取实体类数据时,就需要在各自工程中编写 model。自定义 model 能够根据自身业务需求映射相应的实体属性。如此一来,这个映射工作似乎并不简单。

这个时候,我们可以使用MapStruct
在企业级应用中,经常需要在不同类型的对象(如 DTO 和 DO、VO 和 PO 等)之间进行转换。MapStruct 通过在编译时基于接口定义生成转换代码,大大简化了这个过程。例如,从一个包含用户注册信息的 DTO 转换为一个用于业务逻辑处理的 DO 时,只需要定义一个 MapStruct 接口。

引入依赖

<properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><java.version>17</java.version><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><lombok.version>1.18.34</lombok.version><mapstruct.version>1.6.2</mapstruct.version>
</properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version></dependency><dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct</artifactId><version>${mapstruct.version}</version></dependency><dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct-processor</artifactId><version>${mapstruct.version}</version><scope>provider</scope></dependency></dependencies>

org.mapstruct:mapstruct

  • 这是MapStruct的核心库。它包含了用于定义映射接口的注解(如@Mapper@Mapping等)以及在运行时执行映射操作所需的类型和接口。
  • 开发人员在Java代码中使用这些注解来定义对象之间的映射关系。例如,在不同的领域对象(Domain Object)、数据传输对象(Data Transfer Object)、视图对象(View Object)等之间的转换映射。这个库提供了基本的框架,使得可以按照声明式的方式指定对象属性如何从一个对象映射到另一个对象。
  • 当执行映射操作时(例如,通过调用由MapStruct生成的映射器实例的映射方法),这个库中的代码会协调映射过程,根据定义的映射规则进行数据的转换。

org.mapstruct:mapstruct - processor

  • 这个依赖是MapStruct的注解处理器(Annotation Processor)。在Java编译过程中,它会查找带有MapStruct注解(来自org.mapstruct:mapstruct库)的接口或抽象类。
  • 一旦找到这样的接口或抽象类,它会根据定义的映射关系(通过@Mapper@Mapping等注解)生成具体的映射实现类。这个生成过程是在编译时进行的,生成的代码会被编译到最终的字节码中。
  • 例如,如果有一个定义了从SourceObjectTargetObject映射关系的@Mapper接口,mapstruct - processor会生成一个实现该接口的类,这个类包含了将SourceObject的属性值按照指定规则赋给TargetObject属性的具体代码。这里的<scope>provider</scope>表示该依赖是一个提供运行时环境所需的组件,主要用于在编译时提供代码生成功能。

定义实体

定义两个实体,字段上略微有些差别

import java.util.Date;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {private long id;private String name;private int age;private String password;private Date createTime;
}

import lombok.Data;@Data
public class UserVO {private Long id;private String name;private Integer age;private String code;private String hello;private String createTime;
}

定义转换的mapper

如果是spring项目,用@Mapper(componentModel = "spring"),生成的实现类上面会自动添加一个@Component注解,可以通过Spring的 @Autowired方式进行注入

package com.zxy.demo;import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;@Mapper
public interface UserMapper {public static final UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);static String hello(User user) {return "hello " + user.getName();}@Mapping(target = "createTime", source = "createTime", dateFormat = "yyyy-MM-dd HH:mm:ss")@Mapping(target = "code", expression="java(\"xx-\" + user.getId())")@Mapping(target = "hello", expression = "java(UserMapper.hello(user))")UserVO toUserVO(User user);}

如果所有的字段都一样,用@Mappings({})
不一样的用target+source,需要特殊处理的可以用expression

MapStruct 中,expression是一个强大的功能,用于在对象映射过程中执行自定义的表达式。它允许开发人员在映射规则中使用 Java 表达式来处理复杂的映射逻辑,而不仅仅是简单的属性到属性的映射。

这在源对象和目标对象的属性之间存在复杂关系,或者需要进行额外的计算、逻辑判断等情况时非常有用。

来个单测运行一下

package  com.zxy.demo;import java.util.Date;import org.junit.Assert;
import org.junit.Test;public class UserTest {@Testpublic void ok() {User u = new User();u.setId(1);u.setAge(10);u.setName("zxy");u.setPassword("123456");u.setCreateTime(new Date());Assert.assertEquals(10, u.getAge());Assert.assertEquals("zxy", u.getName());System.out.println(new User(1, "zxy", 12, "123456", new Date()));UserVO vo = UserMapper.INSTANCE.toUserVO(u);System.out.println("vo: "+vo);Assert.assertEquals("zxy", vo.getName());Assert.assertEquals("xx-1", vo.getCode());Assert.assertEquals("hello zxy", vo.getHello());}
}

简单看一下生成的代码

UserMapperImpl.java

 // Source code is unavailable, and was generated by the Fernflower decompiler.
package com.zxy.demo;import java.text.SimpleDateFormat;public class UserMapperImpl implements UserMapper {public UserVO toUserVO(User user) {if (user == null) {return null;} else {UserVO userVO = new UserVO();if (user.getCreateTime() != null) {userVO.setCreateTime((new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(user.getCreateTime()));}userVO.setId(user.getId());userVO.setName(user.getName());userVO.setAge(user.getAge());userVO.setCode("xx-" + user.getId());userVO.setHello(UserMapper.hello(user));return userVO;}}
}

相关文章:

优雅使用 MapStruct 进行类复制

前言 在项目中&#xff0c;常常会遇到从数据库读取数据后不能直接返回给前端展示的情况&#xff0c;因为还需要对字段进行加工&#xff0c;比如去除时间戳记录、隐藏敏感数据等。传统的处理方式是创建一个新类&#xff0c;然后编写大量的 get/set 方法进行赋值&#xff0c;若字…...

第19周JavaWeb编程实战-MyBatis实现OA系统 1-OA系统

办公OA系统项目开发 课程简介 本课程将通过慕课办公OA平台的开发&#xff0c;讲解实际项目开发中必须掌握的技能和设计技巧。课程分为三个主要阶段&#xff1a; 需求说明及环境准备&#xff1a; 基于RBAC的访问控制模块开发&#xff1a; 多级请假审批流程开发&#xff1a; …...

仿黑神话悟空跑动-脚下波纹特效(键盘wasd控制走动)

vue使用three.js实现仿黑神话悟空跑动-脚下波纹特效 玩家角色的正面始终朝向鼠标方向&#xff0c;且在按下 W 键时&#xff0c;玩家角色会朝着鼠标方向前进 空格建跳跃 <template><div ref"container" class"container" click"onClick"…...

`torch.utils.data`模块

在PyTorch中&#xff0c;torch.utils.data模块提供了许多有用的工具来处理和加载数据。以下是对您提到的DataLoader, Subset, BatchSampler, SubsetRandomSampler, 和 SequentialSampler的详细解释以及使用示例。 1. DataLoader DataLoader是PyTorch中用于加载数据的一个非常…...

深入理解 `strncat()` 函数:安全拼接字符串

目录&#xff1a; 前言一、 strncat() 函数的基本用法二、 示例代码三、 strncat() 与 strcat() 的区别四、 注意事项五、 实际应用场景总结 前言 在C语言中&#xff0c;字符串操作是编程中非常常见的需求。strncat() 函数是标准库中用于字符串拼接的一个重要函数&#xff0c;…...

OpenCV_自定义线性滤波(filter2D)应用详解

OpenCV filter2D将图像与内核进行卷积&#xff0c;将任意线性滤波器应用于图像。支持就地操作。当孔径部分位于图像之外时&#xff0c;该函数根据指定的边界模式插值异常像素值。 卷积核本质上是一个固定大小的系数数组&#xff0c;数组中的某个元素被作为锚点&#xff08;一般…...

设计模式之装饰模式(Decorator)

前言 这个模式带给我们有关组合跟继承非常多的思考 定义 “单一职责” 模式。动态&#xff08;组合&#xff09;的给一个对象增加一些额外的职责。就增加功能而言&#xff0c;Decorator模式比生成子类&#xff08;继承&#xff09;更为灵活&#xff08;消除重复代码 & 减少…...

大数据-146 Apache Kudu 安装运行 Dockerfile 模拟集群 启动测试

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…...

React入门准备

React是什么 React是一个用于构建用户界面的JavaScript框架&#xff0c;用于构建“可预期的”和“声明式的”Web用户界面&#xff0c;特别适合于构建那些数据会随时间改变的大型应用的用户界面。 它起源于Facebook的内部项目&#xff0c;因为对市场上所有JavaScript MVC框架都…...

robomimic基础教程(四)——开源数据集

robomimic开源了大量数据集及仿真环境&#xff0c;数据集标准格式为HDF5 目录 一、基础要求 二、使用步骤 1. 下载数据集 2. 后处理 3. 训练 4. 查看训练结果 三、HDF5数据集结构与可视化 1. 数据集结构 &#xff08;1&#xff09;根级别&#xff08;data 组 group&a…...

胤娲科技:AI界的超级充电宝——忆阻器如何让LLM告别电量焦虑

当AI遇上“记忆橡皮擦”&#xff0c;电量不再是问题&#xff01; 嘿&#xff0c;朋友们&#xff0c;你们是否曾经因为手机电量不足而焦虑得像个无头苍蝇&#xff1f;想象一下&#xff0c;如果这种“电量焦虑”也蔓延到了AI界&#xff0c; 特别是那些聪明绝顶但“耗电如喝水”的…...

前端大模型入门:使用Transformers.js手搓纯网页版RAG(二)- qwen1.5-0.5B - 纯前端不调接口

书接上文&#xff0c;本文完了RAG的后半部分&#xff0c;在浏览器运行qwen1.5-0.5B实现了增强搜索全流程。但受限于浏览器和模型性能&#xff0c;仅适合于研究、离线和高隐私场景&#xff0c;但对前端小伙伴来说大模型也不是那么遥不可及了&#xff0c;附带全部代码&#xff0c…...

K-means聚类分析对比

K-means聚类分析&#xff0c;不同K值聚类对比&#xff0c;该内容是关于K-means聚类分析的&#xff0c;主要探讨了不同K值对聚类结果的影响。K-means聚类是一种常见的数据分析方法&#xff0c;用于将数据集划分为K个不同的类别。在这个过程中&#xff0c;选择合适的K值是非常关键…...

tar命令:压缩、解压的好工具

一、命令简介 用途&#xff1a; tar​ 命令用于创建归档文件&#xff08;tarball&#xff09;&#xff0c;以及从归档文件中提取文件。 标签&#xff1a; 文件管理&#xff0c;归档。 特点&#xff1a; 归档文件可以保留原始文件和目录的层次结构&#xff0c;通常使用 .tar ​…...

Mac电脑上最简单安装Python的方式

背景 最近换了一台新的 MacBook Air 电脑&#xff0c;所有的开发软件都没有了&#xff0c;需要重新配环境&#xff0c;而我现在最常用的开发程序就是Python。这篇文章记录一下我新Mac电脑安装Python的全过程&#xff0c;也给大家一些思路上的提醒。 以下是我新电脑的配置&…...

Linux基础命令cd详解

cd&#xff08;change directory&#xff09;命令是 Linux 中用于更改当前工作目录的基础命令。它没有很多复杂的参数&#xff0c;但它的使用非常频繁。以下是 cd 命令的详细说明及示例。 基本语法 cd [选项] [路径] 常用选项 -L : 使用逻辑路径&#xff08;默认选项&…...

【大模型对话 的界面搭建-Open WebUI】

Open WebUI 前身就是 Ollama WebUI&#xff0c;为 Ollama 提供一个可视化界面&#xff0c;可以完全离线运行&#xff0c;支持 Ollama 和兼容 OpenAI 的 API。 github网址 https://github.com/open-webui/open-webui安装 第一种 docker安装 如果ollama 安装在同一台服务器上&…...

如何在算家云搭建text-generation-webui(文本生成)

一、text-generation-webui 简介 text-generation-webui 是一个流行的用于文本生成的 Gradio Web UI。支持 transformers、GPTQ、AWQ、EXL2、llama.cpp (GGUF)、Llama 模型。 它的特点如下&#xff0c; 3 种界面模式&#xff1a;default (two columns), notebook, chat支持多…...

【Java SE】初遇Java,数据类型,运算符

&#x1f525;博客主页&#x1f525;&#xff1a;【 坊钰_CSDN博客 】 欢迎各位点赞&#x1f44d;评论✍收藏⭐ 1. Java 概述 1.1 Java 是什么 Java 是一种高级计算机语言&#xff0c;是一种可以编写跨平台应用软件&#xff0c;完全面向对象的程序设计语言。Java 语言简单易学…...

XSS(内含DVWA)

目录 一.XSS的攻击方式&#xff1a; 1. 反射型 XSS&#xff08;Reflected XSS&#xff09; 2. 存储型 XSS&#xff08;Stored XSS&#xff09; 3. DOM型 XSS&#xff08;DOM-based XSS&#xff09; 总结 二..XSS的危害 三.常见的XSS方式 1.script标签 四.常见基本过滤方…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

vscode里如何用git

打开vs终端执行如下&#xff1a; 1 初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

java 实现excel文件转pdf | 无水印 | 无限制

文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心&#xff0c;JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例&#xff1a; 1. onclick - 点击事件 当元素被单击时触发&#xff08;左键点击&#xff09; button.onclick function() {alert("按钮被点击了&#xff01;&…...

Spring AI与Spring Modulith核心技术解析

Spring AI核心架构解析 Spring AI&#xff08;https://spring.io/projects/spring-ai&#xff09;作为Spring生态中的AI集成框架&#xff0c;其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似&#xff0c;但特别为多语…...

Redis:现代应用开发的高效内存数据存储利器

一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发&#xff0c;其初衷是为了满足他自己的一个项目需求&#xff0c;即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源&#xff0c;Redis凭借其简单易用、…...

mac:大模型系列测试

0 MAC 前几天经过学生优惠以及国补17K入手了mac studio,然后这两天亲自测试其模型行运用能力如何&#xff0c;是否支持微调、推理速度等能力。下面进入正文。 1 mac 与 unsloth 按照下面的进行安装以及测试&#xff0c;是可以跑通文章里面的代码。训练速度也是很快的。 注意…...

k8s从入门到放弃之HPA控制器

k8s从入门到放弃之HPA控制器 Kubernetes中的Horizontal Pod Autoscaler (HPA)控制器是一种用于自动扩展部署、副本集或复制控制器中Pod数量的机制。它可以根据观察到的CPU利用率&#xff08;或其他自定义指标&#xff09;来调整这些对象的规模&#xff0c;从而帮助应用程序在负…...

GraphQL 实战篇:Apollo Client 配置与缓存

GraphQL 实战篇&#xff1a;Apollo Client 配置与缓存 上一篇&#xff1a;GraphQL 入门篇&#xff1a;基础查询语法 依旧和上一篇的笔记一样&#xff0c;主实操&#xff0c;没啥过多的细节讲解&#xff0c;代码具体在&#xff1a; https://github.com/GoldenaArcher/graphql…...