本文将以一个中级Java开发者角度,探讨如何整合Spring Conversion Service、MapStruct Spring Extensions和Lombok三个常用框架,以最少的代码和配置,完成复杂对象转换工作。
👉你将学会:
-
如何将对象转换逻辑从接口代码剥离;
-
如何灵活地注册Spring对象转换器;
-
如何使用MapStruct作为转换器的底层实现;
-
如何使用自己的BeanUtil实现兜底策略。
版本限制
- Java 17
- SpringBoot 3.1.x
- Lombok 1.18.x
- MapStruct 1.5.5 Final
Maven依赖配置
Lombok和MapStruct都是非常优秀的类库,能够极大提升开发效率,两者实现原理差不多,都是编译期间生成代码。
MapStruct Spring Extensions是MapStruct基于Spring框架的扩展,自动将Mapper注册为Converter。
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.5.5.Final</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>0.2.0</version>
</dependency>
<dependency>
<groupId>org.mapstruct.extensions.spring</groupId>
<artifactId>mapstruct-spring-annotations</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>
Maven插件配置
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.5.5.Final</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>0.2.0</version>
</path>
<path>
<groupId>org.mapstruct.extensions.spring</groupId>
<artifactId>mapstruct-spring-extensions</artifactId>
<version>1.1.0</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
MapStruct配置
@MapperConfig
注解可以配置一些对象转换过程中的公用配置,比如忽略目标对象中不存在的属性,需要做如下配置:
@MapperConfig(
componentModel = "spring",
unmappedTargetPolicy = ReportingPolicy.IGNORE
)
public interface DefaultConverterConfig {
}
对象转换器
以下是一个常见的数据字典转换器,实现了Entity/DTO互相转换,并自动注册为Spring Converter:
@Mapper(config = DefaultConverterConfig.class)
public interface DictDataToDictDataDtoConverter extends Converter<DictData, DictDataDto> {
@InheritInverseConfiguration
@DelegatingConverter
DictData invertConvert(DictDataDto dto);
@AfterMapping
default void postMapping(DictData entity, @MappingTarget DictDataDto dto) {
// do something
}
@AfterMapping
default void postMapping(DictDataDto dto, @MappingTarget DictData entity) {
// do something
}
}
执行编译命令后会自动生成DictDataToDictDataDtoConverter.class
和反向的DictDataDtoToDictDataConverter.class
。
当然了,你也可以根据需要自行添加XxxToXxxVoConverter或者XxxToXxxBoConverter等各种转换器。
转换方法
@Autowired
private ConversionService conversionService;
protected <T> T convert(Object source, Class<T> targetType) {
// 如果没有配置转换器则使用BeanUtil兜底
return conversionService.canConvert(source.getClass(), targetType) ? conversionService.convert(source, targetType) : BeanUtil.copyProperties((source, targetType);
}
@SuppressWarnings("unchecked")
protected <T> List<T> convertAll(@Nullable List<?> sourceList, Class<T> targetType) {
return conversionService.canConvert(sourceList.get(0).getClass(), targetType)
? (List<T>) conversionService.convert(sourceList, TypeDescriptor.forObject(sourceList), TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(targetType)))
: BeanUtil.copyToList(sourceList, targetType);
}
以上两个方法是通用的,可以根据需要,放到BaseController
或者BaseService
里面。
注意:BeanUtil来自Hutool,也可以替换成自己的工具类。
接口实例
如此一来,我们便可以愉快的调用convert()
方法,而不用关心目标对象到底是个什么O了🙂
@RestController
@RequestMapping("/dict")
public class DictDataController extends BaseController {
@Autowired
private DictDataService dictDataService;
@GetMapping
public Result<DictDataDto> doQuery(@RequestParam Long id) {
DictData entity = dictDataService.getById(id);
return Result.success(convert(entity, DictDataDto.class));
}
}
--- THE END ---
网友评论