mapstrct是一个很好注释处理的框架,解决繁琐domain之间值的转换,节约开发的时间,同时相对应copyProperty的好处是没有使用反射技术,使性能更优。mapstrut一共两个主要的包,org.mapstruct.mapstruct包含里面常用的注释,org.mapstruct.mapstruct-processor处理注释的实现。
文档传送门
<!-- 指定版本 -->
<properties>
<org.mapstruct.version>1.3.0.Final</org.mapstruct.version>
</properties>
<!-- 引入依赖 -->
<dependencies>
<!--mapstruct主键-->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<!-- mapstruct插件 可以直接点击查看mapstruct的实现类 -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>${org.mapstruct.version}</version>
<dependency>
<!-- mapstruct实现类执行器 -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
<scope>private</scope>
</dependency>
</dependencies>
@Mapper
@Mapping(target="",source="")、
@Mappings({@Mapping(target="",source=""),@Mapping(target="",source="")})
ps:如果target和source字段名相同则无需使用注解,mapstruct会自动为我们copy值的
3. @BeanMapping(ignoreByDefault=true)
忽略自动注解功能
4. 例子
@Data
@NoArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
@AllArgsConstructor
public class Item {
Long itemId;
String title;
}
@Data
@NoArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
@AllArgsConstructor
public class Sku {
Long skuId;
String code;
Integer price;
}
@Data
@NoArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
@AllArgsConstructor
public class SkuDTO {
Long skuId;
String skuCode;
Integer skuPrice;
Long itemId;
String itemName;
}
@Mapper
public interface ItemConvert {
ItemConvert INSTANCE = Mappers.getMapper(ItemConvert.class);
@BeanMapping(ignoreByDefault = true)
@Mappings({
@Mapping(source = "sku.code", target = "skuCode"),
@Mapping(source = "sku.price", target = "skuPrice"),
@Mapping(source = "item.title", target = "itemName")
})
SkuDTO domain2Dto(Sku sku, Item item);
}
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2019-07-30T18:14:08+0800",
comments = "version: 1.3.0.Final, compiler: javac, environment: Java 1.8.0_101 (Oracle Corporation)"
)
public class ItemConvertImpl implements ItemConvert {
@Override
public SkuDTO domain2Dto(Sku sku, Item item) {
if ( sku == null && item == null ) {
return null;
}
SkuDTO skuDTO = new SkuDTO();
if ( sku != null ) {
skuDTO.setSkuPrice( sku.getPrice() );
skuDTO.setSkuCode( sku.getCode() );
}
if ( item != null ) {
skuDTO.setItemName( item.getTitle() );
}
return skuDTO;
}
}
@BeanMapping
,所有只有我们需要转换的才会转换,但是如果去掉BeanMapping,那么他的实现就是这样的@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2019-07-30T18:17:19+0800",
comments = "version: 1.3.0.Final, compiler: javac, environment: Java 1.8.0_101 (Oracle Corporation)"
)
public class ItemConvertImpl implements ItemConvert {
@Override
public SkuDTO domain2Dto(Sku sku, Item item) {
if ( sku == null && item == null ) {
return null;
}
SkuDTO skuDTO = new SkuDTO();
if ( sku != null ) {
skuDTO.setSkuPrice( sku.getPrice() );
skuDTO.setSkuCode( sku.getCode() );
skuDTO.setSkuId( sku.getSkuId() );
}
if ( item != null ) {
skuDTO.setItemName( item.getTitle() );
skuDTO.setItemId( item.getItemId() );
}
return skuDTO;
}
}
mapstruct支持多个参数的,如果名字一样则会自动映射,不同则需要使用@Mapping,如果多个参数的都有target的属性名需要制定是哪个source的属性名,否则会报错
@Mapper
public interface CarAssertApiMapper {
CarAssertApiMapper INSTANCE = Mappers.getMapper(CarAssertApiMapper.class);
/**
* 两个do转成一个dto
*
* @param purchaseBillItemDO 采购明细单
* @param carManageDO 车型
* @return 目的dto
*/
@Mappings({
@Mapping(target = "modelCode", source = "carManageDO.modelCode"),
@Mapping(target = "modelName", source = "carManageDO.modelName"),
@Mapping(target = "modelColor", source = "carManageDO.modelColor"),
@Mapping(target = "modelColorCode", source = "carManageDO.modelColorCode"),
@Mapping(target = "interiorColor", source = "carManageDO.interiorColor"),
@Mapping(target = "interiorColorCode", source = "carManageDO.interiorColorCode"),
@Mapping(target = "purchaseBillItemId", source = "purchaseBillItemDO.billItemId")
})
PurchaseCreateDTO doToDto(PurchaseBillItemDO purchaseBillItemDO, CarManageDO carManageDO);
}
车型信息,purchaseBillItemDO和carManageDO都有这个字段,所以需要具体制定到是哪个实体类的字段,否则mapstruct不知道是用哪个
mapstruct可以直接将一个基本类型的字段直接映射对应的bean字段
@Mapper
public interface CarMapper {
CarMapper INSTANCE = Mappers.getMapper(CarMapper.class);
/**
* 多个参数转换为targetDTO
*
* @param carDO source car DO
* @param warehouseDO source warehouse DO
* @param userName 操作人 这个会直接映射到目标bean的相同字段属性上,
* 若是属性名不一致,则需要使用@Mapping
* @return target DTO
* ps:多个mapping可能使用Mappings更方便
* @Mappings({
* @Mapping(source = "warehouseDO.plate_cities", target = "plateCities")
* })
*/
@Mapping(source = "warehouseDO.plate_cities", target = "plateCities")
CarDTO severalSourceToDTo(CarDO carDO, WarehouseDO warehouseDO, String userName);
}
mapstruct不仅仅可以create instance, 也可以更新instance,使用@MappingTarget
@Mapper
public interface CarMapper {
CarMapper INSTANCE = Mappers.getMapper(CarMapper.class);
/**
* 更新DTO里的值
*
* @param carDTO target update instance
* @param inventoryDO source do
*/
void updateCarDTO(@MappingTarget CarDTO carDTO, InventoryDO inventoryDO);
}