@MappingTarget 注解的使用

@MappingTarget 注解在 MapStruct 中用于标记目标对象,表示该对象是要被更新的实例,而不是创建一个新实例。这在需要更新已存在对象的场景中非常有用。

基本用法

@Mapper
public interface UserMapper {
    // 将 UserDTO 的数据更新到现有的 User 对象中
    void updateUserFromDto(UserDTO dto, @MappingTarget User user);
}

在上面的例子中,UserDTO 中的属性会被复制到已存在的 User 实例中,而不是创建新的 User 对象。

实际应用场景

1. 部分更新实体

@Mapper
public interface CustomerMapper {
    // 只更新非空字段
    @Mapping(target = "id", ignore = true) // 防止ID被修改
    @BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
    void updateCustomerFromDto(CustomerDTO dto, @MappingTarget Customer customer);
}

这个例子中,CustomerDTO 中的非空字段会更新到 Customer 对象中,而空字段会被忽略,这对于处理部分更新请求很有用。

2. 结合 @AfterMapping 使用

@Mapper
public abstract class OrderMapper {
    
    // 基本更新方法
    public abstract void updateOrderFromDto(OrderDTO dto, @MappingTarget Order order);
    
    // 在映射完成后执行额外逻辑
    @AfterMapping
    protected void calculateTotals(@MappingTarget Order order) {
        order.setTotalPrice(order.getItems().stream()
            .mapToDouble(item -> item.getPrice() * item.getQuantity())
            .sum());
    }
}

这个例子演示了如何在更新完成后执行额外的计算逻辑。

3. 处理不同字段名称

@Mapper
public interface ProductMapper {
    
    @Mapping(source = "productName", target = "name")
    @Mapping(source = "productPrice", target = "price")
    void updateProductFromDto(ProductDTO dto, @MappingTarget Product product);
}

在这个例子中,ProductDTO 中的 productName 字段会被映射到 Product 的 name 字段。

使用 @MappingTarget 的优势