DTO 与 PO的相互转换

news2024/11/26 2:50:04

目录

常见Bean映射框架

Dozer

Orika

MapStruct

ModelMapper

JMapper

测试模型

转化器

OrikaConverter

DozerConverter

MapperStructConvert

JMapperConvert

ModelMapperConverter

测试

平均时间

 吞吐量

 SingleShotTime

采集时间


DTO(Data Transfer Object,数据传输对象)

PO(Presistent Object,持久化对象)

常见Bean映射框架

推荐使用MapStruct

Dozer

Dozer 是一个映射框架,它使用递归将数据从一个对象复制到另一个对象。框架不仅能够在 bean 之间复制属性,还能够在不同类型之间自动转换。

<dependency>
    <groupId>net.sf.dozer</groupId>
    <artifactId>dozer</artifactId>
    <version>5.5.1</version>
</dependency>

更多关于 Dozer 的内容可以在官方文档中找到: Dozer - Usage ,或者你也可以阅读这篇文章:A Guide to Mapping With Dozer | Baeldung 。

Orika

Orika 是一个 bean 到 bean 的映射框架,它递归地将数据从一个对象复制到另一个对象。

Orika 的工作原理与 Dozer 相似。两者之间的主要区别是 Orika 使用字节码生成。这允许以最小的开销生成更快的映射器。

<dependency>
    <groupId>ma.glasnost.orika</groupId>
    <artifactId>orika-core</artifactId>
    <version>1.5.2</version>
</dependency>

更多关于 Orika 的内容可以在官方文档中找到:https://orika-mapper.github.io/orika-docs/,​​​​​​或者你也可以阅读这篇文章:https://www.baeldung.com/orika-mapping。

MapStruct

MapStruct 是一个自动生成 bean mapper 类的代码生成器。MapStruct 还能够在不同的数据类型之间进行转换。Github 地址:https://github.com/mapstruct/mapstruct。

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-processor</artifactId>
    <version>1.2.0.Final</version>
</dependency>

ModelMapper

ModelMapper 是一个旨在简化对象映射的框架,它根据约定确定对象之间的映射方式。它提供了类型安全的和重构安全的 API。

更多关于 ModelMapper 的内容可以在官方文档中找到:ModelMapper - Simple, Intelligent, Object Mapping. 。

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

JMapper

JMapper 是一个映射框架,旨在提供易于使用的、高性能的 Java bean 之间的映射。该框架旨在使用注释和关系映射应用 DRY 原则。该框架允许不同的配置方式:基于注释、XML 或基于 api。

更多关于 JMapper 的内容可以在官方文档中找到:https://github.com/jmapper-framework/jmapper-core/wiki。

<dependency>
    <groupId>com.googlecode.jmapper-framework</groupId>
    <artifactId>jmapper-core</artifactId>
    <version>1.6.0.1</version>
</dependency>

测试模型

简单模型如下:

public class SourceCode {
    String code;
    // getter and setter
}
public class DestinationCode {
    String code;
    // getter and setter
}

bean 示例如下:

public class SourceOrder {
    private String orderFinishDate;
    private PaymentType paymentType;
    private Discount discount;
    private DeliveryData deliveryData;
    private User orderingUser;
    private List<Product> orderedProducts;
    private Shop offeringShop;
    private int orderId;
    private OrderStatus status;
    private LocalDate orderDate;
    // standard getters and setters
}
public class Order {
    private User orderingUser;
    private List<Product> orderedProducts;
    private OrderStatus orderStatus;
    private LocalDate orderDate;
    private LocalDate orderFinishDate;
    private PaymentType paymentType;
    private Discount discount;
    private int shopId;
    private DeliveryData deliveryData;
    private Shop offeringShop;
    // standard getters and setters
}

转化器

为了简化测试设置的设计,我们创建了如下所示的转换器接口:

public interface Converter {
    Order convert(SourceOrder sourceOrder);
    DestinationCode convert(SourceCode sourceCode);
}

OrikaConverter

Orika 支持完整的 API 实现,这大大简化了 mapper 的创建:

public class OrikaConverter implements Converter{
    private MapperFacade mapperFacade;    
    public OrikaConverter() {
        MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();        
        mapperFactory.classMap(Order.class, SourceOrder.class)
          .field("orderStatus", "status").byDefault().register();
        mapperFacade = mapperFactory.getMapperFacade();
    }    @Override
    public Order convert(SourceOrder sourceOrder) {
        return mapperFacade.map(sourceOrder, Order.class);
    }    @Override
    public DestinationCode convert(SourceCode sourceCode) {
        return mapperFacade.map(sourceCode, DestinationCode.class);
    }
}

DozerConverter

Dozer 需要 XML 映射文件

<mappings xmlns="http://dozer.sourceforge.net"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://dozer.sourceforge.net
  http://dozer.sourceforge.net/schema/beanmapping.xsd">    
    <mapping>
        <class-a>com.baeldung.performancetests.model.source.SourceOrder</class-a>
        <class-b>com.baeldung.performancetests.model.destination.Order</class-b>
        <field>
            <a>status</a>
            <b>orderStatus</b>
        </field>
    </mapping>
    <mapping>
        <class-a>com.baeldung.performancetests.model.source.SourceCode</class-a>
        <class-b>com.baeldung.performancetests.model.destination.DestinationCode</class-b>
    </mapping>
</mappings>
public class DozerConverter implements Converter {
    private final Mapper mapper;    
    public DozerConverter() {
        DozerBeanMapper mapper = new DozerBeanMapper();
        mapper.addMapping(
          DozerConverter.class.getResourceAsStream("/dozer-mapping.xml"));
        this.mapper = mapper;
    }    @Override
    public Order convert(SourceOrder sourceOrder) {
        return mapper.map(sourceOrder,Order.class);
    }    @Override
    public DestinationCode convert(SourceCode sourceCode) {
        return mapper.map(sourceCode, DestinationCode.class);
    }
}

MapperStructConvert

MapStruct 结构的定义非常简单,因为它完全基于代码生成:

@Mapper
public interface MapStructConverter extends Converter {
    MapStructConverter MAPPER = Mappers.getMapper(MapStructConverter.class);            
    @Mapping(source = "status", target = "orderStatus")
    @Override
    Order convert(SourceOrder sourceOrder);    
    @Override
    DestinationCode convert(SourceCode sourceCode);
}

更复杂的属性转换,参考:

Mapstruct自定义转换规则_好奇的菜鸟的博客-CSDN博客_mapstruct自定义转换

【java】mapstruct自定义类的转换示例_王佑辉的博客-CSDN博客_mapstruct自定义转换 

JMapperConvert

public class JMapperConverter implements Converter {
    JMapper realLifeMapper;
    JMapper simpleMapper;    
    public JMapperConverter() {
        JMapperAPI api = new JMapperAPI()
          .add(JMapperAPI.mappedClass(Order.class));
        realLifeMapper = new JMapper(Order.class, SourceOrder.class, api);
        JMapperAPI simpleApi = new JMapperAPI()
          .add(JMapperAPI.mappedClass(DestinationCode.class));
        simpleMapper = new JMapper(
          DestinationCode.class, SourceCode.class, simpleApi);
    }    
    @Override
    public Order convert(SourceOrder sourceOrder) {
        return (Order) realLifeMapper.getDestination(sourceOrder);
    }    
    @Override
    public DestinationCode convert(SourceCode sourceCode) {
        return (DestinationCode) simpleMapper.getDestination(sourceCode);
    }
}

我们还需要向目标类的每个字段添加@JMap注释。此外,JMapper 不能在 enum 类型之间转换,它需要我们创建自定义映射函数:

@JMapConversion(from = "paymentType", to = "paymentType")
public PaymentType conversion(com.baeldung.performancetests.model.source.PaymentType type) {
    PaymentType paymentType = null;
    switch(type) {
        case CARD:
            paymentType = PaymentType.CARD;
            break;        case CASH:
            paymentType = PaymentType.CASH;
            break;        case TRANSFER:
            paymentType = PaymentType.TRANSFER;
            break;
    }
    return paymentType;
}

ModelMapperConverter

public class ModelMapperConverter implements Converter {
    private ModelMapper modelMapper;    
    public ModelMapperConverter() {
        modelMapper = new ModelMapper();
    }    
    @Override
    public Order convert(SourceOrder sourceOrder) {
       return modelMapper.map(sourceOrder, Order.class);
    }    
    @Override
    public DestinationCode convert(SourceCode sourceCode) {
        return modelMapper.map(sourceCode, DestinationCode.class);
    }
}

测试

平均时间

JMH 返回以下平均运行时间结果(越少越好):

 吞吐量

在这种模式下,基准测试返回每秒的操作数。我们收到以下结果(越多越好):

 SingleShotTime

这种模式允许测量单个操作从开始到结束的时间。基准给出了以下结果(越少越好):

采集时间

这种模式允许对每个操作的时间进行采样。三个不同百分位数的结果如下:

 

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

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

相关文章

Android项目Gadle统一依赖管理

一.Gradle管理依赖版本 在中大型Android项目中&#xff0c;都会有多个Module进行协同配合。这些module中可能会依赖同一个库的不同版本&#xff0c;这将导致一些问题&#xff0c;要么是代码冲突&#xff0c;要么是APK包体积增大&#xff0c;亦或是项目构建的时间变长&#xff…

在Revit里如何将普通墙与曲面墙的内壁连接

在Revit里如何将普通墙与曲面墙的内壁连接&#xff1f;创建异形建筑时&#xff0c;为了达到如图1所示的效果&#xff0c;该如何操作&#xff1b; 我们可以使用体量建模的方式来创建该类建筑&#xff0c;要点在于如将幕墙与曲面墙的内壁连接。具体方法如下&#xff1a; 一、创建…

ASP.NET Core+Element+SQL Server开发校园图书管理系统(一)

随着技术的进步&#xff0c;跨平台开发已经成为了标配&#xff0c;在此大背景下&#xff0c;ASP.NET Core也应运而生。本文主要基于ASP.NET CoreElementSql Server开发一个校园图书管理系统为例&#xff0c;简述基于MVC三层架构开发的常见知识点&#xff0c;仅供学习分享使用&a…

ubuntu20.04下出现protoc与gazebo版本问题

ubuntu20protocgazebo问题描述问题定位解决方案问题描述 今天在搞路径规划算法时&#xff0c;从git上拉下来一个算法&#xff0c;ros环境那些都有&#xff0c;但是在编译的时候出现了如下图所示的一下问题&#xff1a;&#xff08;为了方便搜索关键词&#xff09; In file incl…

锂离子电池热失控预警资料整理(三)

此前 个人搜集了一些锂电池热失控预警相关期刊、文献&#xff0c;并整理了一些个人认为重要的逻辑、知识点&#xff0c;希望通过此分享让有需要的人了解一些内容&#xff0c;如有问题欢迎同我探讨~ 锂离子电池热失控预警资料整理&#xff08;三&#xff09;九、基于数据分析的锂…

C语言基于FOC控制算法和STM32主控芯片的双路直流无刷电机控制器源码

【FOCSTM32】双路直流无刷电机矢量控制器-使用文档 &#x1f4d5; 介绍 控制器主控芯片采用STM32F405RGT6&#xff0c;控制器底层基于HAL库和FreeRTOS实时操作系统&#xff0c;预留CAN、USART、SWD、USB接口各一&#xff0c;便于通信和控制的工程应用。该控制器提供双路无刷电…

2022年艺术品和古董投资策略研究报告

第一章 行业概况 艺术品是艺术家智力劳动成果的结晶。作为一种特殊商品流通于艺术市场&#xff0c;与其他商品相同的是&#xff0c;它也具备普通商品的基本属性&#xff1a;使用价值和价值。不同的是&#xff0c;艺术品的使用价值体现在精神层面而不是物质层面上&#xff0c;它…

RabbitMQ消息队列实战(1)—— RabbitMQ的体系

RabbitMQ是一个开源的消息代理和队列服务器&#xff0c;用来在不同的应用之间共享数据。1983年&#xff0c;被认为是RabbitMQ的雏形的Teknekron创建&#xff0c;首次提出了消息总线的概念。中间经历过数个阶段的发展&#xff0c;一直到2004年&#xff0c;AMQP&#xff08;Advan…

02.指针的进阶

1.字符指针 在指针的类型中我们知道有一种指针类型为字符指针 char* ; 一般使用: int main() {char ch w;char *pc &ch;*pc w;return 0; } char * p---const char * p(因为常量字符串不能被修改) #include<stdio.h> int main() {const char * pstr "hel…

从汇编的角度了解C++原理——虚函数

文章目录1、虚函数1.1、虚函数储存结构1.2、子类重写虚函数1.3、在栈上调用虚函数1.4、在堆上调用虚函数(通过指针调用&#xff0c;多态)本文用到的反汇编工具是objconv&#xff0c;使用方法可以看我另一篇文章https://blog.csdn.net/weixin_45001971/article/details/12866064…

编译基于armV8架构的opencv,并在rock3a开发板上运行

近期在基于arm开发板做图像识别任务开发时&#xff0c;需要用到Opencv库 之前在做rknpu开发时&#xff0c;开发sdk里面已经集成了opencv 但是该opencv开发包不能实现imshow/VideoCapture等函数&#xff0c;经过调研&#xff0c;决定对opencv源代码进行编译&#xff0c;生成arm…

安科瑞能耗监测系统在新疆昌吉市政务中心项目的研究与应用

安科瑞 华楠摘要&#xff1a;大型公共建筑总面积不足城镇建筑总面积的4%&#xff0c;但总能耗却占全国城镇总耗电量的22%&#xff0c;大型公共建筑单位面积年耗电量达到70&#xff5e;300KWh&#xff0c;为普通居民住宅的10&#xff5e;20倍。公共建筑是节能大户和节能核心&…

Delphi 11.2 安装 CnWizards 组件包

官方网址&#xff1a;https://www.cnpack.org/showdetail.php?id900&langzh-cn 开源免费的组件包&#xff0c;大大提高了开发效率&#xff0c;再次感谢大佬们的无私奉献 这个组件包主要是为了实现一些delphi没有的便捷设置&#xff0c;以及能给delphi增加了一些好用的辅助…

惊艳的产品背后,是锐利的设计思维

缘起 几年前&#xff0c;我偶然用一个 叫 Zine 的小app 写了两篇文章&#xff0c;感觉非常好。 后来在网上认识 了Zine 团队的创始人 Louis&#xff0c;也喜欢上了他们的另一个 App&#xff1a;Varlens&#xff0c; 最近他们推出了记笔记的 App Lattics&#xff0c;一些功能也…

《 Unity Shader 入门精要》 第3章 Unity Shader 基础

第3章 Unity Shader 基础 3.1 Unity Shader 概述 材质与 Unity Shader 在 Unity 中我们通常需要将材质&#xff08;Material&#xff09; 和 Unity Shader 配合使用&#xff0c;常见流程如下&#xff1a; 创建一个材质创建一个 Unity Shader&#xff0c; 并将它赋给材质将材…

Android View类

布局定义了应用中的界面结构&#xff08;例如 Activity 的界面结构&#xff09;。布局中的所有元素均使用 View 和 ViewGroup 对象的层次结构进行构建。View 通常用于绘制用户可看到并与之交互的内容。ViewGroup 则是不可见的容器&#xff0c;用于定义 View 和其他 ViewGroup 对…

AppScan自定义扫描策略,扫描针对性漏洞

系列文章 AppScan介绍和安装 AppScan 扫描web应用程序 AppScan被动手动探索扫描 AppScan绕过登录验证码深入扫描 第五节-AppScan自定义扫描策略&#xff0c;扫描针对性漏洞 AppScan安全扫描往往速度是很慢的&#xff0c;有些场景下他的扫描项目又不是我们需要的&#xff0c;…

如何实现六轴机械臂的逆解计算?

1. 机械臂运动学介绍 机械臂运动学 机器人运动学就是根据末端执行器与所选参考坐标系之间的几何关系&#xff0c;确定末端执行器的空间位置和姿态与各关节变量之间的数学关系。包括正运动学&#xff08;Forward Kinematics&#xff09;和逆运动学&#xff08;Inverse Kinemati…

渔业养殖远程监控系统解决方案

传统的水产养殖依靠养殖者的经验进行观察&#xff0c;信息不准确&#xff0c;调控不及时&#xff0c;养殖规模扩大难&#xff0c;人工成本高。除此之外传统水产养殖以个户居多&#xff0c;生产管理方式粗放&#xff0c;个体生产能力不足&#xff0c;养殖产品的品质难以保障。 …

AppScan扫描报告

系列文章 AppScan介绍和安装 AppScan 扫描web应用程序 AppScan被动手动探索扫描 AppScan绕过登录验证码深入扫描 AppScan自定义扫描策略&#xff0c;扫描针对性漏洞 第六节-AppScan扫描报告 1.加载扫描结果 1.点击【打开】 2.选择之前保存过的扫描结果 3.等待加载完成 …