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

DTO 与 PO的相互转换

目录

常见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

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

采集时间

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

 

相关文章:

  • 【Linux编译器】
  • 转换函数和运算符类
  • 【8】SCI易中期刊推荐——图像处理领域(中科院4区)
  • 聊聊模板方法模式?
  • 【学习】计算机系统硬件和数据结构
  • Vue3+Element-Plus 实现点击左侧菜单时显示不同内容组件展示在Main区域功能
  • Vuejs设计与实现11-编译优化与同构渲染
  • SAP 服务器参数文件详细解析
  • 【C语言】自定义类型
  • 【手写 Vue2.x 源码】第二十六篇 - 数组依赖收集的实现
  • 无服务器架构Serverless
  • 我的2022
  • java springboot 项目构建报错解决办法
  • Laravel文档阅读笔记-How to Build a Rest API with Laravel: A Beginners Guide①
  • M320、M601、HD1(RTU)功能对比
  • 使用Anaconda(3-5.1.0对应 python3.6.3)搭建OpenCV(3.5.1.15)环境和Jupyter Notebook
  • 系统分析师案例必备知识点汇总---2023系列文章三
  • Retrofit源码分析实践(一)【从使用入手分析源码】
  • mysql快速生成100W条测试数据(8)全球各城市人口及经济增长速度并存入mysql数据库
  • Python数学建模问题总结(3)数据可视化Cookbook指南·下