You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mapstruct实现Road到两类Dto转换时如何避免重复逻辑符合DRY原则

Mapstruct 多Dto场景下复用转换逻辑的可行方案

方案一:抽离公共业务逻辑,拆分筛选与转换步骤(推荐)

你原有代码中重复的核心是从Road中筛选符合条件的Point的逻辑,把这部分抽成公共方法即可完全复用,仅保留不同Dto的转换逻辑:

@Mapper(componentModel = "spring")
public interface MyMapper {

    @Mapping(target = "lPlace", source = "road", qualifiedByName = "PointToLPlace")
    @Mapping(target = "uPlace", source = "road", qualifiedByName = "PointToUPlace")
    RoadWithloUnPlaceDto map(Road road);

    @Mapping(target = "loadingPlace", source = "road", qualifiedByName = "PointToLPlaceSmall")
    @Mapping(target = "uPlace", source = "road", qualifiedByName = "PointToUPlaceSmall")
    RoadWithLUPlaceSmallDto mapToRoadWithLUPlaceSmallDto(Road road);

    // 抽离公共的筛选Point逻辑,所有转换场景复用
    default Optional<Point> getMatchPointByOperation(Road road, OperationType operationType) {
        return Optional.ofNullable(road)
                .map(Road::getPoints)
                .filter(points -> !CollectionUtils.isEmpty(points))
                .flatMap(points -> points.stream()
                        .sorted(Comparator.comparing(Point::getOrder))
                        .filter(point -> isAllowed(point.getOperations(), operationType))
                        .findFirst()
                );
    }

    @Named("PointToLPlace")
    default RoadAddressDto mapLPlace(Road road) {
        return getMatchPointByOperation(road, OperationType.L)
                .map(this::mapRoadAddress)
                .orElse(null);
    }

    @Named("PointToLPlaceSmall")
    default RoadAddressSmallDto mapLPlaceSmall(Road road) {
        return getMatchPointByOperation(road, OperationType.L)
                .map(this::mapRoadAddressSmall)
                .orElse(null);
    }

    // UPlace的两个转换方法同理,复用getMatchPointByOperation即可
    // 省略其余转换方法...
}

这个方案无多余转换步骤,性能最优,核心业务逻辑仅需维护一份。

方案二:复用原有转换方法,新增Dto互转逻辑

如果RoadAddressDto和RoadAddressSmallDto字段是包含关系,你可以让Mapstruct自动生成二者的转换逻辑,直接复用原有@Named方法:

@Mapper(componentModel = "spring")
public interface MyMapper {

    @Mapping(target = "lPlace", source = "road", qualifiedByName = "PointToLPlace")
    @Mapping(target = "uPlace", source = "road", qualifiedByName = "PointToUPlace")
    RoadWithloUnPlaceDto map(Road road);

    // 用expression调用原有转换方法,再转成SmallDto
    @Mapping(target = "loadingPlace", expression = "java(toSmallDto(mapLPlace(road)))")
    @Mapping(target = "uPlace", expression = "java(toSmallDto(mapUPlace(road)))")
    RoadWithLUPlaceSmallDto mapToRoadWithLUPlaceSmallDto(Road road);

    // Mapstruct会自动生成该方法的实现,按字段名匹配转换
    RoadAddressSmallDto toSmallDto(RoadAddressDto dto);

    // 原有@Named方法完全保留不用修改
    @Named("PointToLPlace")
    default RoadAddressDto mapLPlace(Road road) {
        return Optional.ofNullable(road)
                .map(Road::getPoints)
                .filter(point -> !CollectionUtils.isEmpty(points))
                .flatMap(
                        points-> points.stream()
                                .sorted(Comparator.comparing(Point::getOrder))
                                .filter(point-> isAllowed(point.getOperations(), OperationType.L))
                                .findFirst()
                ).map(this::mapRoadAddress)
                .orElse(null);
    }
    // 省略其余方法...
}

这个方案不用修改原有转换逻辑,开发成本更低,仅多了一次Dto互转的开销,适合性能要求不高的场景。

内容的提问来源于stack exchange,提问作者Matexon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 18:18:03