优雅的转换Bean对象 mapstruct使用笔记详解

------------恢复内容开始------------
日常开发中,我们时长会写很多关于PO转VO的代码或者是VO转DTO相关的代码,造成我们的程序异常的臃肿。

MapStruct很优雅的帮我们解决了这个问题

一、MapStruct

官网: https://mapstruct.org/

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

为什么要用MapStruct

多层应用程序通常需要在不同的对象模型(例如实体和 DTO)之间进行映射。编写这样的映射代码是一项乏味且容易出错的任务。MapStruct 旨在通过尽可能地自动化来简化这项工作。
与其他映射框架相比,MapStruct 在编译时生成 bean 映射,这确保了高性能,允许快速的开发人员反馈和彻底的错误检查。

例如:

假设我们有一个代表汽车的类(例如一个JPA 实体)和一个伴随的数据传输对象(DTO)。

这两种类型非常相似,只是座位计数属性有不同的名称,并且 type 属性是类中的特殊枚举类型,Car但在 DTO 中是纯字符串。

二、使用mapStruct

要求jdk版本是java8或者更高

Car

public class Car {
 
    private String make;
    private int numberOfSeats;
    private CarType type;
 
    //constructor, getters, setters etc.
}

CarDto

public class CarDto {
 
    private String make;
    private int seatCount;
    private String type;
 
    //constructor, getters, setters etc.
}

要生成映射器以从对象中创建CarDto对象Car,需要定义映射器接口:
CarMapper

@Mapper 
public interface CarMapper {
 
    CarMapper INSTANCE = Mappers.getMapper( CarMapper.class ); 
 
    @Mapping(source = "numberOfSeats", target = "seatCount")
    CarDto carToCarDto(Car car); 
}

使用映射器
基于映射器接口,客户端可以以非常简单且类型安全的方式执行对象映射:

@Test
public void shouldMapCarToDto() {
    //given
    Car car = new Car( "Morris", 5, CarType.SEDAN );
 
    //when
    CarDto carDto = CarMapper.INSTANCE.carToCarDto( car );
 
    //then
    assertThat( carDto ).isNotNull();
    assertThat( carDto.getMake() ).isEqualTo( "Morris" );
    assertThat( carDto.getSeatCount() ).isEqualTo( 5 );
    assertThat( carDto.getType() ).isEqualTo( "SEDAN" );
}

要求jdk版本是java8或者更高

<properties>
    <mapstruct.version>1.3.1.Final</mapstruct.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>${mapstruct.version}</version>
    </dependency>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct-jdk8</artifactId>
        <version>${mapstruct.version}</version>
    </dependency>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct-processor</artifactId>
        <version>${mapstruct.version}</version>
    </dependency>
</dependencies>

可以看到生成的源码:

public class CarMapperImpl implements CarMapper {

    @Override
    public CarDto carToCarDto(Car car) {
        if ( car == null ) {
            return null;
        }

        CarDto carDto = new CarDto();

        carDto.setSeatCount( car.getNumberOfSeats() );
        carDto.setMake( car.getMake() );
        if ( car.getType() != null ) {
            carDto.setType( car.getType().name() );
        }

        return carDto;
    }
}

三、 常见用法

(1)两个类型属性不一致

此时CarPo的一个属性为carName,而CarVo对应的属性为name!

我们在接口上增加对应关系即可,如下所示


@Mapper( unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface CarMapper {


    CarMapper INSTANCE = Mappers.getMapper(CarMapper.class);

    @Mappings({
            @org.mapstruct.Mapping(source = "numberOfSeats", target = "seatCount")})
    CarDto carToCarDto(Car car);
    

}

(2)集合类型转换
从List转换为Lis
CarMapper

@Mapper( unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface CarMapper {
    CarMapper INSTANCE = Mappers.getMapper(CarMapper.class);
    @Mappings({
            @org.mapstruct.Mapping(source = "numberOfSeats", target = "seatCount")})
    CarDto carToCarDto(Car car);
    List<CarDto> covertTo(List<Car> videoStreams);
}

CarMapperImpl


@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2022-01-16T21:51:16+0800",
    comments = "version: 1.4.2.Final, compiler: IncrementalProcessingEnvironment from gradle-language-java-6.8.jar, environment: Java 11.0.13 (JetBrains s.r.o.)"
)
public class CarMapperImpl implements CarMapper {

    @Override
    public CarDto carToCarDto(Car car) {
        if ( car == null ) {
            return null;
        }

        CarDto carDto = new CarDto();

        carDto.setSeatCount( car.getNumberOfSeats() );
        carDto.setMake( car.getMake() );
        if ( car.getType() != null ) {
            carDto.setType( car.getType().name() );
        }

        return carDto;
    }

    @Override
    public List<CarDto> covertTo(List<Car> car) {
        if ( car == null ) {
            return null;
        }

        List<CarDto> list = new ArrayList<CarDto>( car.size() );
        for ( Car car1 : car ) {
            list.add( carToCarDto( car1 ) );
        }

        return list;
    }
}

类型不一致

------------恢复内容结束------------

上一篇:python 中enumerate函数(千年虫)


下一篇:实现一个函数判断year是不是闰年。