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

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

采集时间

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值