MapStruct 超好用的Java實體映射工具

前言

MapStruct入門筆記,取代BeanUtils.copy(source,target)

官網地址:
https://mapstruct.org/

官網文檔:

https://mapstruct.org/documentation/reference-guide/
在這裏插入圖片描述選擇相應版本 HTML 或 PDF 形式文檔查看即可。

V1.2.0 HTML地址:
https://mapstruct.org/documentation/1.2/reference/html/

一、準備工作

添加maven依賴

我第一次用的是1.3.1版本,但是插件不可用,降級嘗試1.2.0,完美。

...
<properties>
    <org.mapstruct.version>1.2.0.Final</org.mapstruct.version>
</properties>
...
<dependencies>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct-jdk8</artifactId>
        <version>${org.mapstruct.version}</version>
    </dependency>
</dependencies>
...
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.5.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${org.mapstruct.version}</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>
...

二、入門,創建簡單的映射

1,先創建映射接口

官網上是:

To create a mapper simply define a Java interface with the required
mapping method(s) and annotate it with the org.mapstruct.Mapper annotation

在這裏引用官網的栗子

@Mapper
public interface CarMapper {

    @Mappings({
        @Mapping(source = "make", target = "manufacturer"),
        @Mapping(source = "numberOfSeats", target = "seatCount")
        @Mapping(target = "name", ignore = true)
    })
    CarDto carToCarDto(Car car);

    @Mapping(source = "name", target = "fullName")
    PersonDto personToPersonDto(Person person);
}

需要注意的是,

1,@Mapper 註解,表示MapStruct要會去實現該接口
1,@Mapping 有多個時,需要使用@Mappings(),否則會報錯,如下

在這裏插入圖片描述

2,如果source對象中屬性與target對象中屬性字段名一致,會自動映射對應屬性,而不需要@Mapping指定。如果不一致則需要指定。
3,如果有某個屬性不想映射,可以加 ignore=true
4,類型轉換
4.1 int 轉 String

@Mapper
public interface CarMapper {

    @Mapping(source = "price", numberFormat = "$#.00")
    CarDto carToCarDto(Car car);

    @IterableMapping(numberFormat = "$#.00")
    List<String> prices(List<Integer> prices);
}

4.2 BigDecimal 轉 String

@Mapper
public interface CarMapper {

    @Mapping(source = "power", numberFormat = "#.##E0")
    CarDto carToCarDto(Car car);

}

4.3 date 轉 String 指定格式

@Mapper
public interface CarMapper {

    @Mapping(source = "manufacturingDate", dateFormat = "dd.MM.yyyy")
    CarDto carToCarDto(Car car);

    @IterableMapping(dateFormat = "dd.MM.yyyy")
    List<String> stringListToDateList(List<Date> dates);
}

2,檢查映射是否生效

在執行程序或插件compiler後,檢查是否有自動生成的一個implement實現接口CarMapper,這個文件在target目錄下,最快的方式是全局搜索CarMapper,定位CarMapperImpl。如果此文件存在,表示映射可用。

如果在執行程序或compiler插件的過程中build failure,需要先解決問題啦。我遇到的問題以及解決方法將在下一篇筆記彙總。

官網上是:

The @Mapper annotation causes the MapStruct code generator to create
an implementation of the CarMapper interface during build-time.

自動生成的代碼如下:

public class CarMapperImpl implements CarMapper {

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

        CarDto carDto = new CarDto();

        if ( car.getFeatures() != null ) {
            carDto.setFeatures( new ArrayList<String>( car.getFeatures() ) );
        }
        carDto.setManufacturer( car.getMake() );
        carDto.setSeatCount( car.getNumberOfSeats() );
        carDto.setDriver( personToPersonDto( car.getDriver() ) );
        carDto.setPrice( String.valueOf( car.getPrice() ) );
        if ( car.getCategory() != null ) {
            carDto.setCategory( car.getCategory().toString() );
        }
        carDto.setEngine( engineTtoEngineDto( car.getEngine() ) );

        return carDto;
    }

    @Override
    public PersonDto personToPersonDto(Person person) {
        //...
    }

    private EngineDto engineToEngineDto(Engine engine) {
        if ( engine == null ) {
            return null;
        }

        EngineDto engineDto = new EngineDto();

        engineDto.setHorsePower(engine.getHorsePower());
        engineDto.setFuel(engine.getFuel());

        return engineDto;
    }
}

三、實戰

映射添加好了,接下來怎麼用呢?
繼續看文檔,文檔中提到兩種方式,一種是使用Mappers Factory(默認),一種是使用依賴注入

1. The Mappers Factory

1,聲明一個映射接口

@Mapper
public interface CarMapper {

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

    CarDto carToCarDto(Car car);
}

Or

聲明一個抽象的映射接口 (1.3.1版本支持)

@Mapper
public abstract class CarMapper {

    public static final CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );

    CarDto carToCarDto(Car car);
}

然後在service層就可以調用了

Car car = ...;
CarDto dto = CarMapper.INSTANCE.carToCarDto( car );

2.Using dependency injection

在映射接口上註解@Mapper後添加屬性componentModel,與Spring框架結合,所以我在代碼中添加@Mapper(componentModel=“spring”),下面是官網中的栗子

@Mapper(componentModel = "cdi")
public interface CarMapper {

    CarDto carToCarDto(Car car);
}

在service層,使用@Autowired就可以注入,

@Autowired
private CarMapper mapper;

在官網中,給出的栗子是這樣的:

@Inject
private CarMapper mapper;

並且啓動程序會發現,在自動生成的代碼中,也就是在接口的實現類上會自動生成註解 @Component

@Component
public class ThirlDtoMapperImpl implements ThirlDtoMapper {
	... ...
}

end

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章