在使用 MapStruct 进行对象映射时,@BeforeMapping
和@AfterMapping
这两个注解能让开发者在映射前后执行自定义逻辑,极大地增强了映射的灵活性,满足多样化的业务需求。
一、@BeforeMapping 注解
1.1 作用
@BeforeMapping
用于在映射方法执行前进行预处理操作。它允许开发者对源对象或其他相关数据进行修改、验证等操作,确保映射过程能基于符合预期的数据进行。
1.2 使用场景
在一个电商系统中,订单对象Order
有个创建时间字段creationTime
,类型为Date
。在映射到用于展示的OrderDto
时,需要将creationTime
格式化为特定的字符串格式(如 "yyyy-MM-dd HH:mm:ss")。此时就可以使用@BeforeMapping
注解在映射前进行格式化处理。
1.3 示例代码
import org.mapstruct.BeforeMapping;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.text.SimpleDateFormat;
import java.util.Date;@Mapper
public interface OrderMapper {OrderMapper INSTANCE = Mappers.getMapper(OrderMapper.class);@BeforeMappingdefault void formatCreationTime(Order order) {if (order != null && order.getCreationTime() != null) {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");String formattedTime = sdf.format(order.getCreationTime());order.setFormattedCreationTime(formattedTime);}}OrderDto orderToOrderDto(Order order);
}class Order {private Date creationTime;private String formattedCreationTime;// 省略getter和setter
}class OrderDto {private String creationTime;// 省略getter和setter
}
在上述代码中,formatCreationTime
方法被@BeforeMapping
注解修饰。在执行orderToOrderDto
映射方法前,会先调用formatCreationTime
方法对Order
对象的creationTime
进行格式化,并将格式化后的结果存储在formattedCreationTime
字段中,后续映射时就可以将formattedCreationTime
映射到OrderDto
的creationTime
字段。
二、@AfterMapping 注解
2.1 作用
@AfterMapping
用于在映射方法执行后进行后处理操作。通常用于对映射后的目标对象进行额外的修改、填充等操作,使目标对象更符合业务要求。
2.2 使用场景
还是在电商系统中,映射得到的OrderDto
对象需要添加一个表示订单状态描述的字段statusDescription
,该描述根据订单的实际状态(如已支付、已发货等)动态生成。由于这个描述信息在源对象Order
中并不直接存在,所以可以在映射完成后使用@AfterMapping
来添加这个字段。
2.3 示例代码
java">import org.mapstruct.AfterMapping;
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;
import org.mapstruct.factory.Mappers;@Mapper
public interface OrderMapper {OrderMapper INSTANCE = Mappers.getMapper(OrderMapper.class);OrderDto orderToOrderDto(Order order);@AfterMappingdefault void addStatusDescription(Order order, @MappingTarget OrderDto orderDto) {if (order != null && orderDto != null) {if ("PAID".equals(order.getStatus())) {orderDto.setStatusDescription("订单已支付");} else if ("SHIPPED".equals(order.getStatus())) {orderDto.setStatusDescription("订单已发货");} else {orderDto.setStatusDescription("未知状态");}}}
}class Order {private String status;// 省略getter和setter
}class OrderDto {private String statusDescription;// 省略getter和setter
}
在这段代码里,addStatusDescription
方法被@AfterMapping
注解修饰,并且接收源对象Order
和目标对象OrderDto
(通过@MappingTarget
注解标注目标对象)作为参数。在orderToOrderDto
映射方法执行完毕后,会调用addStatusDescription
方法,根据Order
对象的status
字段为OrderDto
对象添加statusDescription
字段。
三、注意事项
- 方法签名规范:被
@BeforeMapping
和@AfterMapping
注解的方法必须是default
方法,且方法签名要符合要求。@BeforeMapping
方法一般接收源对象作为参数(可以有多个源对象相关参数),@AfterMapping
方法除了可以接收源对象,还需要通过@MappingTarget
注解标注目标对象作为参数。 - 顺序问题:多个
@BeforeMapping
方法和多个@AfterMapping
方法的执行顺序是不确定的。如果有严格的顺序要求,建议将相关逻辑合并到一个方法中。 - 异常处理:在
@BeforeMapping
和@AfterMapping
方法中抛出的异常会中断映射过程,所以需要根据业务需求合理处理异常,避免影响整个映射流程。
通过合理运用@BeforeMapping
和@AfterMapping
注解,开发者可以在 MapStruct 的对象映射过程中,轻松实现各种复杂的业务逻辑,让映射功能更加完善和灵活。