MapStruct 代码优化利器

MapStruct 映射框架

使用方式

实例方式
@Mapper
public interface StorageMapper {

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

    @ToEntity
    @Mapping( target = "weightLimit", source = "maxWeight")
    ShelveEntity map(ShelveDto source);

    @ToEntity
    @Mapping( target = "label", source = "designation")
    BoxEntity map(BoxDto source);
}**

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

使用StorageMapper.INSTANCE.map方法即可。

注入spring方式
@Mapper(componentModel = "spring", imports = {StringUtils.class, ObjectUtils.class}, nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
public interface SystemMapper {
    SysUserRsp toSysUserRsp(SysUserEntity entity);
}

使用@Resource注入即可。
imports 导入引用类。
nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE 表示忽略空值

@Mapper使用场景

源字段和目标字段名不一致场景
@Mapper
public interface CarMapper {

    @Mapping(target = "manufacturer", source = "make")
    @Mapping(target = "seatCount", source = "numberOfSeats")
    CarDto carToCarDto(Car car);

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

字段一致时可以不填写。

具有多个源参数的映射方法场景
@Mapper
public interface AddressMapper {

    @Mapping(target = "description", source = "person.description")
    @Mapping(target = "houseNumber", source = "address.houseNo")
    DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Address address);
}

直接引用场景时

@Mapper
public interface AddressMapper {

    @Mapping(target = "description", source = "person.description")
    @Mapping(target = "houseNumber", source = "hn")
    DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Integer hn);
}
表达式场景

使用表达式的映射方法

@Mapper
public interface SourceTargetMapper {

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

    @Mapping(target = "timeAndFormat",
         expression = "java( new org.sample.TimeAndFormat( s.getTime(), s.getFormat() ) )")
    Target sourceToTarget(Source s);
}
```‘
声明导入

```java
imports org.sample.TimeAndFormat;

@Mapper( imports = TimeAndFormat.class )
public interface SourceTargetMapper {

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

    @Mapping(target = "timeAndFormat",
         expression = "java( new TimeAndFormat( s.getTime(), s.getFormat() ) )")
    Target sourceToTarget(Source s);
}

默认表达式
默认表达式是默认值和表达式的组合。只有当源属性为null。

适用于表达式的默认表达式的警告和限制相同。仅支持Java,并且MapStruct不会在生成时验证表达式。

下面的示例演示了当源属性不存在时,如何使用默认表达式设置值 (例如,是null):

imports java.util.UUID;

@Mapper( imports = UUID.class )
public interface SourceTargetMapper {

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

    @Mapping(target="id", source="sourceId", defaultExpression = "java( UUID.randomUUID().toString() )")
    Target sourceToTarget(Source s);
}
条件映射场景

Mapper使用自定义条件检查方法

@Mapper
public interface CarMapper {

    CarDto carToCarDto(Car car);

    @Condition
    default boolean isNotEmpty(String value) {
        return value != null && !value.isEmpty();
    }
}
// GENERATED CODE
public class CarMapperImpl implements CarMapper {

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

        CarDto carDto = new CarDto();

        if ( isNotEmpty( car.getOwner() ) ) {
            carDto.setOwner( car.getOwner() );
        }

        // Mapping of other properties

        return carDto;
    }
}

条件映射是一种源存在检查。 不同之处在于,它允许用户编写自定义条件方法,这些方法将被调用以检查是否需要映射属性。

自定义条件方法是用org.mapstruct.Condition并返回boolean。

例如,如果你只想映射一个字符串属性,当它不是 “null”,它不是空的,那么你可以做这样的事情:

更新现有bean实例场景
在这里插入代码片
@Mapper
public interface CarMapper {

    void updateCarFromDto(CarDto carDto, @MappingTarget Car car);
}

@MappingTarget Car car 指定更新的目标对象。

数据类型转换场景

从int到String的转换 numberFormat

@Mapper
public interface CarMapper {

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

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

从日期转换为字符串 dateFormat

@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);
}

映射器控制嵌套bean映射II

@Mapper
public interface FishTankMapperWithDocument {

    @Mapping(target = "fish.kind", source = "fish.type")
    @Mapping(target = "fish.name", expression = "java(\"Jaws\")")
    @Mapping(target = "plant", ignore = true )
    @Mapping(target = "ornament", ignore = true )
    @Mapping(target = "material", ignore = true)
    @Mapping(target = "quality.document", source = "quality.report")
    @Mapping(target = "quality.document.organisation.name", constant = "NoIdeaInc" )
    FishTankWithNestedDocumentDto map( FishTank source );

}

常量映射constant = “NoIdeaInc”
定义表达式映射
expression = “java(“Jaws”)”

调用其他映射器场景

手动实现的mapper类

public class DateMapper {

    public String asString(Date date) {
        return date != null ? new SimpleDateFormat( "yyyy-MM-dd" )
            .format( date ) : null;
    }

    public Date asDate(String date) {
        try {
            return date != null ? new SimpleDateFormat( "yyyy-MM-dd" )
                .parse( date ) : null;
        }
        catch ( ParseException e ) {
            throw new RuntimeException( e );
        }
    }
}

引用另一个mapper类

@Mapper(uses=DateMapper.class)
public interface CarMapper {

    CarDto carToCarDto(Car car);
}

生成实现的代码时carToCarDto()方法,MapStruct将查找一个映射Date对象转换为字符串,则在DateMapper类并生成的调用asString()用于映射manufacturingDate属性。

使用defaultValue的映射器场景

使用defaultValue的映射器

@Mapper
public interface MovieMapper {

     @Mapping( target = "category", qualifiedByName = "CategoryToString", defaultValue = "DEFAULT" )
     GermanRelease toGerman( OriginalRelease movies );

     @Named("CategoryToString")
     default String defaultValueForQualifier(Category cat) {
         // some mapping logic
     }
}

在上面的示例中,如果类别为null,则方法CategoryToString( Enum.valueOf( Category.class, “DEFAULT” ) )将被调用,结果将被设置为类别字段。
使用defaultValue和default方法的映射器。

@Mapper
public interface MovieMapper {

     @Mapping( target = "category", qualifiedByName = "CategoryToString", defaultValue = "Unknown" )
     GermanRelease toGerman( OriginalRelease movies );

     @Named("CategoryToString")
     default String defaultValueForQualifier(Category cat) {
         // some mapping logic
     }

     @Named("CategoryToString")
     default String defaultValueForQualifier(String value) {
         return value;
     }
}

映射器使用defaultExpression

@Mapper
public interface MovieMapper {

     @Mapping( target = "category", qualifiedByName = "CategoryToString", defaultExpression = "java(\"Unknown\")" )
     GermanRelease toGerman( OriginalRelease movies );

     @Named("CategoryToString")
     default String defaultValueForQualifier(Category cat) {
         // some mapping logic
     }
}
映射集合场景(list,map,set)

具有集合映射方法的Mapper

@Mapper
public interface CarMapper {

    Set<String> integerSetToStringSet(Set<Integer> integers);

    List<CarDto> carsToCarDtos(List<Car> cars);

    CarDto carToCarDto(Car car);
}

注意,映射 List集合时,要写carToCarDto映射规则,不然可能报错。
当映射bean的集合类型属性时,MapStruct将查找具有匹配参数和返回类型的集合映射方法,例如Car#passengers(类型List) 至CarDto#passengers(类型List)。

使用集合映射方法映射bean属性

//GENERATED CODE
carDto.setPassengers( personsToPersonDtos( car.getPassengers() ) );
...

map集合场景
public interface SourceTargetMapper {

    @MapMapping(valueDateFormat = "dd.MM.yyyy")
    Map<String, String> longDateMapToStringStringMap(Map<Long, Date> source);
}
//GENERATED CODE
@Override
public Map<Long, Date> stringStringMapToLongDateMap(Map<String, String> source) {
    if ( source == null ) {
        return null;
    }

    Map<Long, Date> map = new LinkedHashMap<Long, Date>();

    for ( Map.Entry<String, String> entry : source.entrySet() ) {

        Long key = Long.parseLong( entry.getKey() );
        Date value;
        try {
            value = new SimpleDateFormat( "dd.MM.yyyy" ).parse( entry.getValue() );
        }
        catch( ParseException e ) {
            throw new RuntimeException( e );
        }

        map.put( key, value );
    }

    return map;
}
Stream流场景
@Mapper
public interface CarMapper {

    Set<String> integerStreamToStringSet(Stream<Integer> integers);

    List<CarDto> carsToCarDtos(Stream<Car> cars);

    CarDto carToCarDto(Car car);
}
//GENERATED CODE
@Override
public Set<String> integerStreamToStringSet(Stream<Integer> integers) {
    if ( integers == null ) {
        return null;
    }

    return integers.map( integer -> String.valueOf( integer ) )
        .collect( Collectors.toCollection( LinkedHashSet<String>::new ) );
}

@Override
public List<CarDto> carsToCarDtos(Stream<Car> cars) {
    if ( cars == null ) {
        return null;
    }

    return cars.map( car -> carToCarDto( car ) )
        .collect( Collectors.toCollection( ArrayList<CarDto>::new ) );
}
将枚举映射到枚举类型场景

枚举映射方法

@Mapper
public interface OrderMapper {

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

    @ValueMappings({
        @ValueMapping(target = "SPECIAL", source = "EXTRA"),
        @ValueMapping(target = "DEFAULT", source = "STANDARD"),
        @ValueMapping(target = "DEFAULT", source = "NORMAL")
    })
    ExternalOrderType orderTypeToExternalOrderType(OrderType orderType);
}
// GENERATED CODE
public class OrderMapperImpl implements OrderMapper {

    @Override
    public ExternalOrderType orderTypeToExternalOrderType(OrderType orderType) {
        if ( orderType == null ) {
            return null;
        }

        ExternalOrderType externalOrderType_;

        switch ( orderType ) {
            case EXTRA: externalOrderType_ = ExternalOrderType.SPECIAL;
            break;
            case STANDARD: externalOrderType_ = ExternalOrderType.DEFAULT;
            break;
            case NORMAL: externalOrderType_ = ExternalOrderType.DEFAULT;
            break;
            case RETAIL: externalOrderType_ = ExternalOrderType.RETAIL;
            break;
            case B2B: externalOrderType_ = ExternalOrderType.B2B;
            break;
            default: throw new IllegalArgumentException( "Unexpected enum constant: " + orderType );
        }

        return externalOrderType_;
    }
}

官网链接

  • 24
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值