DTO 与 PO的相互转换

目录

常见Bean映射框架

Dozer

Orika

MapStruct

ModelMapper

JMapper

测试模型

转化器

OrikaConverter

DozerConverter

MapperStructConvert

JMapperConvert

ModelMapperConverter

测试

平均时间

 吞吐量

 SingleShotTime

采集时间


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

PO(Presistent Object,持久化对象)

DTO 与 PO的相互转换_第1张图片

常见Bean映射框架

推荐使用MapStruct

Dozer

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


    net.sf.dozer
    dozer
    5.5.1

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

Orika

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

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


    ma.glasnost.orika
    orika-core
    1.5.2

更多关于 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。


    org.mapstruct
    mapstruct-processor
    1.2.0.Final

ModelMapper

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

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


  org.modelmapper
  modelmapper
  1.1.0

JMapper

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

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


    com.googlecode.jmapper-framework
    jmapper-core
    1.6.0.1

测试模型

简单模型如下:

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 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 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 映射文件

    
    
        com.baeldung.performancetests.model.source.SourceOrder
        com.baeldung.performancetests.model.destination.Order
        
            status
            orderStatus
        
    
    
        com.baeldung.performancetests.model.source.SourceCode
        com.baeldung.performancetests.model.destination.DestinationCode
    
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 返回以下平均运行时间结果(越少越好):

DTO 与 PO的相互转换_第2张图片

 吞吐量

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

DTO 与 PO的相互转换_第3张图片

 SingleShotTime

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

DTO 与 PO的相互转换_第4张图片

采集时间

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

DTO 与 PO的相互转换_第5张图片

 

你可能感兴趣的:(框架使用,java,后端)