【Mapstruct】MapStruct实战:简化Java Bean映射

虽然早就在用mapstruct了,但因为要快速原型开发,天天写builder模式,感觉太长了,不好看,(然后最近被同事说丑了 ),感觉还是做个总结,怒转mapstruct

问题背景或前提知识

在现代软件开发中,数据在不同层之间的转换是很常见的场景。这通常包括将数据实体(Entity)转换为数据传输对象(DTO),或反之。手动转换不仅效率低下,而且容易出错。MapStruct作为一种解决方案,通过自动生成映射代码,来减少手动编写的需要。
在 Java 中,除了使用 MapStruct 这样的库来自动化 bean 到 bean 的映射,还有其他几种方式可以实现相同的目标。这些方法各有利弊,适用于不同的场景:

手动映射:
最基本的方法是手动编写代码来映射对象。这意味着为每个需要映射的字段编写 get 和 set 方法调用。这种方法简单直观,但当涉及到大量字段或频繁更改时,会变得冗长且难以维护。

Apache Commons BeanUtils:
使用 BeanUtils 类可以轻松复制属性值。这个库提供了方法来动态地复制对象之间的属性,但它使用反射,可能比编译时生成的代码慢。

技术名词解释
  • DTO(Data Transfer Object): 用于应用层之间数据传输的对象。
  • Entity: 通常对应数据库中的表,用于表示数据的持久化形式。
  • MapStruct: 一种代码生成工具,它遵循约定大于配置的原则,自动化生成类型安全的Bean映射代码。

具体代码与实现方法

User 实体类
import java.time.LocalDateTime;public class User {private String name;private String email;private String password;private LocalDateTime lastLogin;private Type type;private String streetName;// 构造方法,getters 和 setters省略
}
Type 枚举
public enum Type {ADMIN,USER,GUEST;// 枚举方法省略
}
Address 类 (假设的)
public class Address {private String street;private String city;private String zipCode;// 构造方法,getters 和 setters省略
}
UserDTO 类
import java.time.LocalDate;public class UserDTO {private String name;private String email;private String userStatus;private LocalDate registrationDate;private String status;private String userType;private String addressStreet;// 构造方法,getters 和 setters省略
}

MapStruct映射接口示例

接下来,定义一个MapStruct接口UserMapper,展示如何使用@Mapping注解实现上述映射策略。

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Named;
import org.mapstruct.factory.Mappers;@Mapper
public interface UserMapper {UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);@Mapping(target = "status", defaultValue = "NEW")@Mapping(target = "registrationDate", expression = "java(java.time.LocalDate.now())")@Mapping(target = "password", ignore = true)@Mapping(target = "userStatus", source = "user", qualifiedByName = "isActiveUser")@Mapping(target = "userType", source = "type")@Mapping(target = "addressStreet", source = "streetName")UserDTO userToUserDTO(User user);@Named("isActiveUser")default String isActiveUser(User user) {return user.getLastLogin() != null && user.getLastLogin().isAfter(LocalDateTime.now().minusMonths(1)) ? "Active" : "Inactive";}// 枚举映射方法和其他自定义逻辑可以根据需要添加
}

在这个UserMapper接口中,我们使用@Mapping注解来实现了几种不同的映射策略:

  • 使用默认值:为status字段设置了默认值"NEW"。
  • 使用表达式:使用Java表达式为registrationDate字段设置当前日期。
  • 忽略字段:忽略了password字段,不将其包含在DTO中。
  • 使用条件映射:通过自定义方法isActiveUseruserStatus字段设置值,基于用户的lastLogin日期。
  • 直接映射和嵌套对象映射:将userType从枚举Type映射,并将streetName映射到addressStreet

复杂点的处理

@Mapper
public interface UserMapper {UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);// 现有的单个User到UserDTO的映射@Mapping(target = "addressStreet", source = "address.street")UserDTO userToUserDTO(User user, Address address);// 添加一个默认方法来处理列表转换default List<UserDTO> usersToUserDTOs(List<User> users, List<Address> addresses) {List<UserDTO> userDTOs = new ArrayList<>();for (int i = 0; i < users.size(); i++) {User user = users.get(i);Address address = addresses.get(i); // 假设列表是对齐的userDTOs.add(userToUserDTO(user, address));}return userDTOs;}
}
未使用@Mapping注解的字段处理:

MapStruct默认会尝试自动映射那些在源对象和目标对象中名称和类型都相同的字段。如果字段名和类型在两个类中完全一致,MapStruct会自动映射这些字段,不需要显式使用@Mapping注解。

对于名称或类型不匹配的字段,如果没有通过@Mapping注解指定映射规则,这些字段将不会被自动映射,也不会影响其他字段的映射。这意味着,如果你不处理这些字段,它们在目标对象中将保持默认值(如null、0或false等)。

原理: MapStruct在编译时生成实现映射接口的类。这个过程中,它会检查源对象和目标对象的字段,基于字段的名称和类型来自动生成映射代码。如果使用了@Mapping注解,MapStruct会根据注解提供的信息来生成相应的映射代码。这个过程完全在编译时完成,因此运行时性能很好,并且没有反射或运行时代理的开销。

总结和额外补充内容

MapStruct通过减少样板代码,提高了开发效率并降低了出错概率。它支持多种复杂的映射情况,包括但不限于默认值、常量、自定义方法以及多

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/667293.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【PLC一体机】PLC一体机中如何实现触摸屏和PC电脑的通讯

博主今天准备把之前买的PLC一体机拿出来玩一下&#xff0c;翻看以前的博文&#xff0c;发现没有记录分享PLC一体机中如何实现触摸屏程序下载的内容。 如之前博文介绍的那样&#xff0c;PLC一体机由PLC和触摸屏两部分集成的设备&#xff0c;因此设备内部已经做好了PLC和触摸屏之…

C++拷贝构造函数、赋值运算符重载

1.拷贝构造函数 拷贝构造函数的写法如图所示 调用方式如下 接下来我来说说它的特征 1.1特征 拷贝构造函数&#xff1a;只有单个形参&#xff0c;该形参是对本类类型对象的引用(一般常用const修饰)&#xff0c;在用已存在的类类型对象创建新对象时由编译器自动调用。 拷贝构造函…

【SpringBoot1】Spring Boot是如何推断你的工程类型的

我们的工程一般都是基于java的Servlet的&#xff0c;但是除此之外还有其他类型的&#xff0c; 在WebApplicationType里定义了常见的类型&#xff1a; public enum WebApplicationType {/*** The application should not run as a web application and should not start an* e…

XGB-2: Boosted Trees(提升树)简介

XGBoost代表“Extreme Gradient Boosting”&#xff0c;其中术语“Gradient Boosting”来源于Friedman的论文《Greedy Function Approximation: A Gradient Boosting Machine》。 梯度提升树已经存在一段时间&#xff0c;关于这个主题有很多资料。本部分将使用监督学习的元素&…

【Chrono Engine学习总结】1-安装配置与程序运行

本文仅用于个人安装记录。 官方安装教程 https://api.projectchrono.org/8.0.0/tutorial_install_chrono.html Windows下安装 windows下安装就按照教程好了。采用cmake-gui进行配置&#xff0c;建议首次安装只安装核心模块。然后依此configure下irrlicht&#xff0c;sensor…

6款超好用的IDEA插件,开发必备!

今天给大家介绍几款开发必备的IDEA插件&#xff1a; JRebel 热部署插件&#xff0c;让你在修改完代码后&#xff0c;不用再重新启动&#xff0c;很实用&#xff01;但是&#xff0c;不是免费的&#xff0c;需要大家继续发挥下自己的聪明才智才能happy的使用 Json Parser 厌倦…

Vivado Tri-MAC IP端口说明

Trri-mac Ethernet IP端口详细说明 序号 Signal Name Direction Description 备注 Clock&#xff0c;Reset Definition 1 gtx_clk I MAC IP全局时钟输入&#xff0c;125MHz。使用时输入125MHz全局时钟。 2 refclk I MAC IP参考时钟输入&#xff0c;200MHz&#xff0c;该时钟用…

每周AI新闻(2024年第5周)ChatGPT等多应用登陆 Vision Pro | 字节Coze国内版上线等

我是陌小北&#xff0c;一个正在研究硅基生命的、有趣儿的碳基生命。每周日20:00&#xff0c;准时解读每周AI大事件。 大厂动向 【1】ChatGPT、钉钉、Firefly AI 登陆 Vision Pro OpenAI发布了新的ChatGPT App&#xff0c;允许Apple Vision Pro用户与GPT-4 Turbo模型进行自然…

Abp 从空白的WebApplication中添加EntityFrameworkCore生成数据库

书接上文&#xff1a;Abp 从空白WebApplication开始 开发环境&#xff1a;.NET6、Volo.Abp 数据库&#xff1a;Sqlite 说明&#xff1a;纯属个人强行入门。我个人觉得按照官网的操作不舒服&#xff0c;所以自己研究着来&#xff0c;请读者根据自己的需要进行参考。我能保证的…

Ubuntu+GPU搭建Stable-Diffusion教程

【前序】已经安装anaconda 1.git拉取项目到本地 执行git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git 进入项目目录下 cd stable-diffusion-webui/ 2. 安装对应Python依赖包 首先安装pytorch和torchvision&#xff0c;若是GPU环境的用户需要安装与cu…

2024年最新幻兽帕鲁服务器搭建教程

玩转幻兽帕鲁服务器&#xff0c;阿里云推出新手0基础一键部署幻兽帕鲁服务器教程&#xff0c;傻瓜式一键部署&#xff0c;3分钟即可成功创建一台Palworld专属服务器&#xff0c;成本仅需26元&#xff0c;阿里云服务器网aliyunfuwuqi.com分享2024年新版基于阿里云搭建幻兽帕鲁服…

Day59 单调栈part02 503. 下一个更大元素 II 42. 接雨水

Day59 单调栈part02 503. 下一个更大元素 II 42. 接雨水 503. 下一个更大元素 II class Solution { public:vector<int> nextGreaterElements(vector<int>& nums) {vector<int> result(nums.size(),-1); stack<int> st;st.push(0);for(int i 1;…

深度解析源码,Spring 如何使用三级缓存解决循环依赖

目录 一. 前言 二. 基础知识 2.1. 什么是循环依赖&#xff1f; 2.2. 三级缓存 2.3. 原理执行流程 三. 源码解读 3.1. 代码入口 3.2. 第一层 3.3. 第二层 3.4. 第三层 3.5. 返回第二层 3.6. 返回第一层 四. 原理深度解读 4.1. 什么要有三级缓存&#xff1f; 4.2.…

【HarmonyOS 4.0 应用开发实战】ArkTS 快速入门

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;️…

python中[[]] * (n)和[[] for _ in range(n)]的区别

1、现象 刷leetcode207的时候碰到一个坑&#xff0c;用[[]] * (n)初始化二维数组&#xff0c;逻辑是正确的&#xff0c;但是结果始终不对。 2、原因 最后定位是初始化语句使用错误导致的&#xff0c;我使用的是[[]] * (n)&#xff0c;应该使用[[] for _ in range(n)] 3、解…

Stable Diffusion 模型下载:ReV Animated

模型介绍 该模型能够创建 2.5D 类图像生成。此模型是检查点合并&#xff0c;这意味着它是其他模型的产物&#xff0c;以创建从原始模型派生的产品。 条目内容类型大模型基础模型SD 1.5来源CIVITAI作者s6yx文件名称revAnimated_v122EOL.safetensors文件大小5.13GB 生成案例 …

redis数据库设置对象的过期时间,到期后自动删除该条数据

redis数据库设置对象的过期时间,到期后自动删除该条数据&#xff01;过期时间的事情经常发生。比如大家领到了一些购物券。这张购物券有一个过期时间。必须在某节点之前&#xff08;某年某月末日&#xff09;之前&#xff0c;使用掉&#xff0c;否则该券就会过期&#xff0c;无…

Ruby详解及安装流程

文章目录 一、Ruby详解二、Ruby安装流程三、Ruby案例四、Ruby常见问题五、Ruby优缺点六、热门文章 一、Ruby详解 Ruby是一种高级编程语言&#xff0c;具有简单易学、灵活多变、优雅美丽的语法特点。它是一种面向对象的编程语言&#xff0c;具有动态类型和解释型语言的特性。在…

Aigtek高压放大器用途是什么呢

高压放大器在电子领域中扮演着至关重要的角色&#xff0c;其主要作用是将低电压信号放大到更高的电压水平。这种类型的放大器广泛用于各种应用中&#xff0c;以下是高压放大器的用途以及其关键作用的详细介绍。 1、科学研究和实验室应用&#xff1a; 高压放大器在科学研究和实验…

【Linux】Linux权限

Hello everybody!在介绍完Linux操作系统常用的基本指令后&#xff0c;咱们就要开始权限的讲解了。如果没有看过我之前文章的宝子们可以去看看呦&#xff01;有比较系统的指令讲解&#xff01; 回到正题&#xff0c;关于权限&#xff0c;实际上没有大家想象中的那么神秘&#x…