之前安利過Mapstruct 這個神器,它可以代替BeanUtil
來進(jìn)行DTO、VO、PO之間的轉(zhuǎn)換。它使用的是Java編譯期的 annotation processor 機(jī)制,說白了它就是一個代碼生成器,代替你手工進(jìn)行類型轉(zhuǎn)換期間的取值賦值操作。
之前很多項目都使用了它,代碼清爽得很,增加了大量摸魚時間,用過的都說好。
@Mapper(componentModel = "spring")
public interface AreaMapping {
List<AreaInfoListVO> toVos(List<Area> areas);
}
就這么幾行就把一個PO的集合轉(zhuǎn)換成了對應(yīng)VO的集合。
// spring bean
@Autowired
AreaMapping areaMapping
// 轉(zhuǎn)換源 areas
List<Area> areas = ……;
// 轉(zhuǎn)換目標(biāo) vos
List<AreaInfoListVO> vos = areaMapping.toVos(areas)
換成你手寫試試,起碼得五分之一炷香的功夫。
但是這樣寫還是不太爽,每次都要掛對應(yīng)的Mapper類。
Converter
Spring framework提供了一個Converter<S,T>
接口:
@FunctionalInterface
public interface Converter<S, T> {
@Nullable
T convert(S source);
default <U> Converter<S, U> andThen(Converter<? super T, ? extends U> after) {
Assert.notNull(after, "After Converter must not be null");
return (s) -> {
T initialResult = this.convert(s);
return initialResult != null ? after.convert(initialResult) : null;
};
}
}
它的作用是將S
轉(zhuǎn)換為T
,這和Mapstruct的作用不謀而合。
Converter
會通過ConverterRegistry
這個注冊接口注冊到ConversionService
,然后你就可以通過ConversionService
的convert
方法來進(jìn)行轉(zhuǎn)換:
<T> T convert(@Nullable Object source, Class<T> targetType);
MapStruct Spring Extensions
根據(jù)上面的機(jī)制官方推出了MapStruct Spring Extensions插件, 它實現(xiàn)了一種機(jī)制,所有的Mapstruct映射接口(Mapper)只要實現(xiàn)了Converter
,都會自動注冊到ConversionService
,我們只需要通過ConversionService
就能完成任何轉(zhuǎn)換操作。
/**
* @author felord.cn
* @since 1.0.0
*/
@Mapper(componentModel = "spring")
public interface CarMapper extends Converter<Car, CarDto> {
@Mapping(target = "seats", source = "seatConfiguration")
CarDto convert(Car car);
}
調(diào)用時:
@Autowired
private ConversionService conversionService;
Car car = ……;
CarDto carDto = conversionService.convert(car,CarDto.class);
MapStruct Spring Extensions 會自動生成一個適配類處理Mapper注冊:
package org.mapstruct.extensions.spring.converter;
import cn.felord.mapstruct.entity.Car;
import cn.felord.mapstruct.entity.CarDto;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Component;
/**
* @author felord.cn
* @since 1.0.0
*/
@Component
public class ConversionServiceAdapter {
private final ConversionService conversionService;
public ConversionServiceAdapter(@Lazy final ConversionService conversionService) {
this.conversionService = conversionService;
}
public CarDto mapCarToCarDto(final Car source) {
return (CarDto)this.conversionService.convert(source, CarDto.class);
}
}
自定義
自定義適配類的包路徑和名稱
默認(rèn)情況下,生成的適配類將位于包org.mapstruct.extensions.spring.converter
中,名稱固定為ConversionServiceAdapter
。如果你希望修改包路徑或者名稱,你可以這樣:
package cn.felord.mapstruct.config;
import org.mapstruct.MapperConfig;
import org.mapstruct.extensions.spring.SpringMapperConfig;
/**
* @author felord.cn
* @since 1.0.0
*/
@MapperConfig(componentModel = "spring")
@SpringMapperConfig(conversionServiceAdapterPackage = "cn.felord.mapstruct.config",
conversionServiceAdapterClassName = "MapStructConversionServiceAdapter")
public class MapperSpringConfig {
}
不指定conversionServiceAdapterPackage
元素,生成的 Adapter 類將與注解的 Config 駐留在同一個包中,所以上面的路徑是可以省略的。
指定ConversionService
如果你的Spring IoC容器中有多個ConversionService
,你可以通過@SpringMapperConfig
注解的conversionServiceBeanName
參數(shù)指定。
package cn.felord.mapstruct.config;
import org.mapstruct.MapperConfig;
import org.mapstruct.extensions.spring.SpringMapperConfig;
/**
* @author felord.cn
* @since 1.0.0
*/
@MapperConfig(componentModel = "spring")
@SpringMapperConfig(conversionServiceAdapterPackage = "cn.felord.mapstruct.config",
conversionServiceAdapterClassName = "MapStructConversionServiceAdapter",
conversionServiceBeanName = "myConversionService")
public class MapperSpringConfig {
}
集成Spring的內(nèi)置轉(zhuǎn)換
Spring內(nèi)部提供了很多好用的Converter<S,T>
實現(xiàn),有的并不直接開放,如果你想用Mapstruct的機(jī)制使用它們,可以通過@SpringMapperConfig
注解的 externalConversions
注冊它們。
@MapperConfig(componentModel = "spring")
@SpringMapperConfig(
externalConversions = @ExternalConversion(sourceType = String.class, targetType = Locale.class))
public interface MapstructConfig {}
會在適配器中自動生成相應(yīng)的轉(zhuǎn)換:
@Component
public class ConversionServiceAdapter {
private final ConversionService conversionService;
public ConversionServiceAdapter(@Lazy final ConversionService conversionService) {
this.conversionService = conversionService;
}
public Locale mapStringToLocale(final String source) {
return conversionService.convert(source, Locale.class);
}
}
總結(jié)
mapstruct-spring-annotations 使開發(fā)人員能夠通過ConversionService
使用定義的 Mapstruct 映射器,而不必單獨導(dǎo)入每個 Mapper,從而允許 Mapper 之間的松散耦合。它本身不會影響Mapstruct的機(jī)制。
項目源碼地址
https:///felord/mapstruct-spring-extensions
微信8.0將好友放開到了一萬,小伙伴可以加我大號了,先到先得,再滿就真沒了
