MapStruct最佳实践

2023-11-21  本文已影响0人  iakuil

本文将以一个中级Java开发者角度,探讨如何整合Spring Conversion Service、MapStruct Spring Extensions和Lombok三个常用框架,以最少的代码和配置,完成复杂对象转换工作。

👉你将学会:

版本限制

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

上一篇 下一篇

猜你喜欢

热点阅读