美文网首页
MapStruct最佳实践

MapStruct最佳实践

作者: iakuil | 来源:发表于2023-11-21 17:19 被阅读0次

本文将以一个中级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 ---

相关文章

网友评论

      本文标题:MapStruct最佳实践

      本文链接:https://www.haomeiwen.com/subject/drobwdtx.html