前言
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