如何向MapStruct映射器传递额外参数?
我完全懂你现在的痛点——不想在OrderMapper的@AfterMapping里手动遍历填充OrderLineRequest的orderId,而是希望让OrderLineMapper直接拿到Order的ID来处理,这样代码更符合职责单一原则。其实MapStruct早就提供了传递额外参数的方案,就是用@Context注解,下面给你一步步的实现方案:
方案核心:用@Context传递上下文参数
@Context是MapStruct专门用来传递映射过程中额外数据的注解,它可以把父级映射中的对象(比如这里的Order)传递给子映射器(比如OrderLineMapper),而且集合映射时会自动把上下文传递给每个元素的映射方法。
1. 修改OrderLineMapper,添加带上下文的映射方法
我们需要调整OrderLineMapper的映射方法,让它能接收Order作为上下文参数,直接从Order里取ID赋值给OrderLineRequest:
@Mapper(componentModel = "spring") public abstract class OrderLineMapper { @Mappings({ @Mapping(target = "order_line_number", source = "orderLineNumber"), // 从上下文的Order对象中获取id,赋值给orderId @Mapping(target = "orderId", source = "order.id") }) public abstract OrderLineRequest orderLineToOrderLineRequest(OrderLine orderLine, @Context Order order); // 逆映射保持你的原有逻辑即可 @InheritInverseConfiguration public abstract OrderLine orderLineRequestToOrderLine(OrderLineRequest orderLineRequest); }
2. 调整OrderLineMappers,传递上下文参数
因为OrderLineMappers是处理集合映射的,我们需要修改它的集合映射方法,添加@Context参数,这样MapStruct会自动把上下文传递给每个OrderLine的映射:
@Mapper(componentModel = "spring", uses = {OrderLineMapper.class}) public interface OrderLineMappers { List<OrderLine> orderLines(List<OrderLineRequest> orderLineRequest); // 添加@Context Order order参数,传递给单个元素的映射方法 List<OrderLineRequest> orderLineRequests(List<OrderLine> orderLine, @Context Order order); }
3. 修改OrderMapper,移除手动遍历逻辑并传递上下文
现在可以删掉原来的@AfterMapping方法,直接在映射注解里把当前的Order作为上下文传递给orderLines的映射:
@Mapper(componentModel = "spring", uses = {OrderLineMappers.class}) public abstract class OrderMapper { // 移除原来的@AfterMapping手动遍历代码 @Mappings({ @Mapping(source = "id", target = "orderId"), @Mapping(source = "orderNumber", target = "order_number"), // 用context = "this"把当前的Order对象传递给orderLineRequests方法 @Mapping(source = "orderLines", target = "orderLines", context = "this") }) public abstract OrderRequest orderToOrderRequest(Order order); @InheritInverseConfiguration public abstract Order orderRequestToOrder(OrderRequest orderRequest); }
可选优化:直接传递OrderId而非整个Order对象
如果不需要传递整个Order对象,只想传orderId,可以简化一下:
OrderLineMapper的方法改成:
@Mappings({ @Mapping(target = "order_line_number", source = "orderLineNumber"), @Mapping(target = "orderId", source = "orderId") }) public abstract OrderLineRequest orderLineToOrderLineRequest(OrderLine orderLine, @Context String orderId);
OrderLineMappers的方法改成:
List<OrderLineRequest> orderLineRequests(List<OrderLine> orderLine, @Context String orderId);
OrderMapper的映射注解改成:
@Mapping(source = "orderLines", target = "orderLines", context = "id")
这样更轻量化,看你的业务需求选择即可。
注意事项
确保你的MapStruct版本在1.2.0及以上,@Context注解是从这个版本开始支持的,如果你用的是旧版本,需要先升级依赖。
这样改造后,映射逻辑就完全交给MapStruct处理了,不用再手动遍历集合,代码更简洁也更符合MapStruct的设计理念。
内容的提问来源于stack exchange,提问作者shadley

