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

实体与DTO如何转换

下面是一些常用的转换库:

  1. Dozer

    该项目目前不活跃,并且很可能在未来被弃用。

  2. ModelMapper

    一个智能对象映射库,可自动将对象相互映射。它采用基于约定的方法,同时提供简单、重构安全的应用程序接口(API)来处理特定用例。

  3. MapStruct

    它是一个代码生成器,它基于约定优于配置的方法,极大地简化了 Java Bean 类型之间的映射实现。生成的映射代码使用简单的方法调用,因此执行速度快、类型安全且易于理解。

  4. Orika

    是一个 Java Bean 映射框架,它(除其他功能外)可以递归地将数据从一个对象复制到另一个对象。它在开发多层应用程序时非常有用。

  5. Selma

    它一方面是一个注解处理器,能够在编译时生成处理字段到字段映射的 Java 代码;另一方面,它是一个运行时库,用于实例化和调用生成的映射器。

ModelMapper的使用。

<dependency><groupId>org.modelmapper</groupId><artifactId>modelmapper</artifactId><version>3.2.1</version>
</dependency>

在Spring环境下,建议配置如下的Bean以方便我们进行转换。

@Configuration
public class ModelMapperConfig {@Beanpublic ModelMapper modelMapper() {return new ModelMapper() ;}
}

如果你不是在Spring环境,那么你可以在使用的时候直接new创建即可。

2.2 准备实体类&DTO

订单实体类

public class Order {private String orderNumber ;private double orderAmount ;private double tax ;private Customer customer ;private Address shippingAddress ;// getter and setter
}
public class Customer {private String userId ;private String firstName ;private String lastName ;private String email ;// getter and setter
}
public class Address {private String addressLine1 ;private String street ;private String city ;private String postalCode ;// getter and setter
}

下面是我们希望进行转换的DTO对象。

public class OrderDto { public  String orderNumber ;private double orderAmount ;private double tax ; private Customer customer ;private Address shippingAddress ;// getters and setters
}

接下来,我们将围绕上面定义的类进行讲解。

再写个静态的Service


@Service
public class OrderService {public Order queryOrder() {Order order = new Order() ;order.setOrderAmount(266.6D) ;order.setTax(1.5D) ;order.setOrderNumber("PACK-00001") ;Customer customer = new Customer("U00001", "Pack", "AKF", "66666@qq.com") ; order.setCustomer(customer) ;Address address = new Address("XJ0001", "HTYJ", "WLMQ", "830000") ;order.setShippingAddress(address) ;return order ;}
}

该Service用来模拟查询Order对象。

2.3 定义门面Facade

在本示例中,我将使用 Facade 层来简化服务层,如下定义:


@Component
public class OrderFacade {private final ModelMapper modelMapper;public OrderFacade(ModelMapper modelMapper) {this.modelMapper = modelMapper ;}public OrderDto convert(Order order) {return convertToOrderDto(order) ;}private OrderDto convertToOrderDto(Order order) {OrderDto orderDto = this.modelMapper.map(order, OrderDto.class);return orderDto;}
}

该Facade非常简单就是调用ModelMapper方法进行数据类型的转换。

2.4 定义Controller

@RestController
@RequestMapping("/orders")
public class OrderController {private final OrderFacade orderFacade;private final OrderService orderService ;public OrderController(OrderFacade orderFacade, OrderService orderService) {this.orderFacade = orderFacade;this.orderService = orderService ;}@GetMapping(value = "/{id}")public ResponseEntity<OrderDto> getOrder(@PathVariable("id") String id) {Order order = this.orderService.queryOrder() ;OrderDto orderDto = this.orderFacade.convert(order) ;return ResponseEntity.status(HttpStatus.OK.value()).body(orderDto) ;}
}

3. ModelMapper更多用法

3.1 自定义映射

首先,修改DTO属性如下:


public class OrderDto {public String number;// ...
}

这里我们希望的是number字段能对应到Order中的orderNumber属性,是否能自动匹配呢?执行如下代码


OrderDto dto = mapper.map(order, OrderDto.class) ;
System.out.println(dto) ;

输出结果

OrderDto2 [number=PACK-00001, orderAmount=266.6, tax=1.5, ...]

能够正确的映射。但是如果两个字段完全没有相似会如何呢?修改DTO如下:


public class OrderDto2 {private double money ;// ...
}

 我们期望的是该money对应到Order中的orderAmount上,运行上面代码:

OrderDto2 [number=PACK-00001, money=0.0,...]

在这种完全没有相似的情况下,就需要我们自定义映射

ModelMapper mapper = new ModelMapper() ;
mapper.typeMap(Order.class, OrderDto.class).addMappings(mapping -> {mapping.map(src -> src.getOrderAmount(), OrderDto::setMoney) ;
}) ;

这里添加了Order到OrderDto转换的映射,将Order中的orderAmount映射到OrderDto中的money。

我们继续修改OrderDto添加如下属性: 我们希望将Customer中的firstName映射到这里的name,可以如下添加映射: 

public class OrderDto {private String name ;// ...
}

我们希望将Customer中的firstName映射到这里的name,可以如下添加映射:


typeMap.addMapping(order -> order.getCustomer().getFirstName(), OrderDto::setName
) ;

 

这就告知在映射时将Customer中的firstName映射到DTO的name属性上。

3.2 跳过属性

如果你希望某些属性不进行映射,你可以如下操作

typeMap.addMappings(mapping -> mapping.skip(OrderDto::setTax));

映射时将忽略DTO中的tax属性。

3.3 属性值转换

转换器允许在映射源属性到目标属性时进行自定义转换,如下示例:


Converter<String, String> toUpperCase = ctx -> ctx.getSource() == null ? null : ctx.getSource().toUpperCase() ;
typeMap.addMappings(mapping -> mapping.using(toUpperCase).map(Order::getOrderNumber, OrderDto::setNumber)
) ;

如上我们将Order中的orderNumber值转换为大写后映射到DTO的number属性。

3.4 条件映射

目标属性的映射可以有条件地进行,方法是在映射的同时提供一个条件,如下示例:


Condition<String, String> condition = ctx -> !"Pack-00001".equals(ctx.getSource());
typeMap.addMappings(mapping -> mapping.when(condition).map(Order::getOrderNumber, OrderDto2::setNumber)) ;

这里添加条件,只有Order中的orderNumber属性值不为 "Pack-00001"时才进行映射。

相关文章:

实体与DTO如何转换

下面是一些常用的转换库&#xff1a; Dozer 该项目目前不活跃&#xff0c;并且很可能在未来被弃用。 ModelMapper 一个智能对象映射库&#xff0c;可自动将对象相互映射。它采用基于约定的方法&#xff0c;同时提供简单、重构安全的应用程序接口&#xff08;API&#xff09;来…...

Docker 安装Postgres和PostGIS,并制作镜像

1. 查找postgres和postgis现有的镜像和版本号 镜像搜索网站&#xff1a;https://docker.aityp.com/ 测试使用的是postgres:15.4 和 postgis:15-3.4 2、镜像拉取 docker pull postgres:15.4docker pull postgis/postgis:15-3.4镜像下载完成&#xff0c;docker images 查看如…...

ES6:let和const命令解读以及变量的解构赋值

有时候&#xff0c;我们需要的不是答案&#xff0c;而是一双倾听的耳朵 文章目录 let和const命令变量的解构赋值 let和const命令 let和const命令都是声明变量的关键字&#xff0c;类同varlet特点 用来声明变量&#xff0c;不能再次定义&#xff0c;但是值可以改变存在块级作用…...

java-collection集合整理0.9.4

java-集合整理0.9.0 基本结构基本概念实例化举例遍历获取指定值 2024年10月17日09:43:16–0.9.0 2024年10月18日11:00:59—0.9.4 基本结构 Collection 是最顶级的接口。分为 List 和 Set 两大类。List 分为&#xff1a;ArrayList、LinkedList、Vector。Set 分为&#xff1a;Ha…...

ParallelsDesktop20最新版本虚拟机 一键切换系统 游戏娱乐两不误

让工作生活更高效&#xff1a;Parallels Desktop 20最新版本虚拟机的神奇之处 大家好&#xff01;&#x1f44b; 今天我要跟大家安利一款让我工作效率飞升的神器——Parallels Desktop 20最新版本虚拟机。作为一个日常需要在不同操作系统间来回穿梭的人&#xff0c;这款软件简直…...

现代C语言:C23标准重大更新

虽然没有固定标准&#xff0c;但一般将C99之后的C语言标准称为“现代C语言”&#xff0c;目前的最新标准为C23。C语言的演化包括标准C89、C90、C99、C11、C17和C23&#xff0c;C23是C语言标准的一次重大修订&#xff0c;截至2024年3月&#xff0c;最新版本的gcc和 clang实现了C…...

Maven进阶——坐标、依赖、仓库

目录 1.pomxml文件 2. 坐标 2.1 坐标的概念 2.2 坐标的意义 2.3 坐标的含义 2.4 自己项目的坐标 2.5 第三方项目坐标 3. 依赖 3.1 依赖的意义 3.2 依赖的使用 3.3 第三方依赖的查找方法 3.4 依赖范围 3.5 依赖传递和可选依赖 3.5.1 依赖传递 3.5.2 依赖范围对传…...

Android中的内存泄漏及其检测方式

Android中的内存泄漏及其检测方式 一、Android内存泄漏概述 在Android开发中&#xff0c;内存泄漏是一个常见且严重的问题。内存泄漏指的是在应用程序中&#xff0c;由于某些原因&#xff0c;已经不再使用的对象仍然被引用&#xff0c;导致垃圾回收器&#xff08;Garbage Col…...

【雷电模拟器命令合集操作大全】官方文档整理贴

此贴是官方的帮助整理文档在这里插入代码片 一起来看看几个主要命令&#xff0c;大部分命令读者可以自己试试~ 1、launch 支持2种启动雷电模拟器的方式 –name顾名思义&#xff0c;应该是模拟器的标题栏的名字&#xff0c;本人经过验证果然如此! –index mnq_idx&#xff0c;模…...

redis的配置文件解析

我的后端学习大纲 我的Redis学习大纲 1.1.Redis的配置文件&#xff1a; 1.Redis的配置文件名称是&#xff1a;redis.conf 2.在vim这个配置文件的时候&#xff0c;默认是不显示行号的&#xff0c;可以编辑下面这个文件&#xff0c;末尾加上set nu&#xff0c;就会显示行号: 1.…...

Python中的元组和列表

‌Python 列表 Python有6个序列的内置类型&#xff0c;但最常见的是列表和元组。 列表是最常用的Python数据类型&#xff0c;它可以作为一个方括号内的逗号分隔值出现。 列表的数据项不需要具有相同的类型 创建一个列表&#xff0c;只要把逗号分隔的不同的数据项使用方括号…...

【AI战略思考7】粮草筹集完毕和我的朋友分类

注明&#xff1a;这是我昨晚12点多发布在朋友圈的&#xff0c;更新加工后的版本 粮草筹集完毕 统计完成 昨晚从7点半到晚上11点&#xff0c;借款的意向统计完成了&#xff0c;刚好凑够6个月&#x1f604;&#xff0c;我觉得应该够了&#xff0c;我乐观估计是3个月内找到工作&…...

科大讯飞AI开发者大赛颁奖典礼,万码优才荣获前三甲!

在近日揭晓的科大讯飞AI开发者大赛中&#xff0c;万码优才APP凭借其卓越的技术实力、创新的应用方案以及深厚的行业洞察力&#xff0c;在上百个参赛队伍中脱颖而出&#xff0c;在AI Agent助力行业应用升级赛道荣获三甲排名&#xff01;再次证明了其在人工智能领域的领先地位与无…...

Redis 哨兵机制

哨兵机制 哨兵机制的介绍 哨兵 (Sentinel) 先来看一下Redis Sentinel 相关名词解释&#xff1a; 在之前的主从复制中&#xff0c;存在一个问题&#xff0c;那就是当主节点挂了后&#xff0c;通过人工干预的方式来解决是比较繁琐且不那么靠谱的。 在实际开发中&#xff0c;对…...

linux-磁盘io情况、性能排查

命令安装 iostat属于sysstat软件包。可以直接安装。 yum install sysstat操作命令解析 iostat %user&#xff1a;CPU处在用户模式下的时间百分比。%nice&#xff1a;CPU处在带NICE值的用户模式下的时间百分比。%system&#xff1a;CPU处在系统模式下的时间百分比。%iowait&a…...

NC 单据模板自定义项 设置参照,比如部门参照、自定义参照等

NC 单据模板自定义项 设置参照&#xff08;自定义参照&#xff09; 一、如图下图&#xff0c;NC 单据模板自定义项 设置自定义参照&#xff1a; 1、选择需要设置参照的自定义字段&#xff0c;选择高级属性页签&#xff0c;在类型设置中&#xff0c;数据类型选择参照信息&#…...

table-cascade 使用

stable-cascade 使用教程 English 中文 1.安装最新版本的 Comyfui 2.将 https://huggingface.co/stabilityai/stable-cascade/tree/main 下面的 stage_b 和 stage_c 模型放到 ComfyUI/models/unet 下面 3.将 https://huggingface.co/stabilityai/stable-cascade/tree/main …...

Android SELinux——策略文件配置结构(八)

在 Android 系统中,SELinux 主要是通过一系列配置文件来进行管理和配置的。这些配置文件涵盖了策略定义、标签映射、签名信息等多个方面。 一、SeLinux文件体系 之前提到 Android 架构中大致包含 AOSP、厂商、Vendor 等部分。在 Android 8 以上的系统中,AOSP 和厂商、供应商…...

【数据结构与算法】队列——数据世界中的“有序使者”

大家好&#xff0c;我是小卡皮巴拉 文章目录 目录 引言 一.队列的基本概念 1.1 队列的定义 1.2 队列的特性 1.3 队列的基本操作 二.队列的实现方式 2.1 基于链表的队列 2.2 基于数组的队列 三.基于链表的队列实现 定义链表队列的结构 初始化 入队列——向队列中插…...

yolov11 部署 TensorRT,预处理和后处理用 C++ cuda 加速,速度快到飞起

之前搞过不少部署&#xff0c;也玩过tensorRT部署模型&#xff08;但都是模型推理用gpu&#xff0c;后处理还是用cpu进行&#xff09;&#xff0c;有网友问能出一篇tensorRT用gpu对模型后处理进行加速的。由于之前用的都是非cuda支持的边缘芯片&#xff0c;没有写过cuda代码&am…...

基于算法竞赛的c++编程(28)结构体的进阶应用

结构体的嵌套与复杂数据组织 在C中&#xff0c;结构体可以嵌套使用&#xff0c;形成更复杂的数据结构。例如&#xff0c;可以通过嵌套结构体描述多层级数据关系&#xff1a; struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06&#xff08;十亿美元&#xff09;。漏洞扫描服务市场行业预计将从 2024 年的 3.48&#xff08;十亿美元&#xff09;增长到 2032 年的 9.54&#xff08;十亿美元&#xff09;。预测期内漏洞扫描服务市场 CAGR&#xff08;增长率&…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

linux 错误码总结

1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)

1.获取 authorizationCode&#xff1a; 2.利用 authorizationCode 获取 accessToken&#xff1a;文档中心 3.获取手机&#xff1a;文档中心 4.获取昵称头像&#xff1a;文档中心 首先创建 request 若要获取手机号&#xff0c;scope必填 phone&#xff0c;permissions 必填 …...