在我们深入探讨之前,先快速回顾一下MapStruct是什么。它是一个代码生成器,在编译时创建类型安全的bean映射器。没有运行时开销,没有反射魔法——只有纯粹、高效的Java代码。以下是一个基本映射器的示例:
@Mapper
public interface UserMapper {
UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
UserDTO mapToDTO(User user);
}
简单吧?但我们才刚刚开始!
你可能不知道的10个MapStruct技巧
1. 带上下文的映射:秘密武器
是否曾经需要向映射器传递额外信息?试试@Context注解:
@Mapper
public interface UserMapper {
@Mapping(target = "role", source = "user")
UserDTO mapToDTO(User user, @Context SecurityContext securityContext);
default String mapRole(User user, @Context SecurityContext securityContext) {
return securityContext.isAdmin() ? "ADMIN" : user.getRole();
}
}
现在你可以在映射逻辑中注入运行时上下文。很酷吧?
2. 自定义方法映射:当标准方法不够用时
有时候,你需要亲自编写自定义映射逻辑:
@Mapper
public interface DateMapper {
@Mapping(target = "formattedDate", source = "date", qualifiedByName = "formatDate")
DateDTO map(DateEntity date);
@Named("formatDate")
default String formatDate(LocalDate date) {
return date != null ? date.format(DateTimeFormatter.ISO_LOCAL_DATE) : null;
}
}
小贴士:使用@Named来组织和重用不同映射器中的自定义方法。
3. 集合映射:因为一个从来不够
MapStruct处理集合如同高手:
@Mapper
public interface ProductMapper {
List mapToDTOList(List products);
Set mapToProductNames(List products);
}
它会自动将元素映射应用于集合中的每个项目。神奇吧!
4. 嵌套对象映射:深入探讨
处理复杂对象图?MapStruct为你保驾护航:
@Mapper
public interface OrderMapper {
@Mapping(target = "customerName", source = "customer.name")
@Mapping(target = "orderItems", source = "items")
OrderDTO mapToDTO(Order order);
@Mapping(target = "productName", source = "product.name")
OrderItemDTO mapToItemDTO(OrderItem item);
}
它无缝处理嵌套对象,免去手动映射的麻烦。
5. 条件映射:决策的艺术
有时,你需要即时做出映射决策:
@Mapper
public interface UserMapper {
@Mapping(target = "status", expression = "java(mapStatus(user))")
UserDTO mapToDTO(User user);
default String mapStatus(User user) {
return user.getLastLoginDate() != null &&
user.getLastLoginDate().isAfter(LocalDate.now().minusDays(30))
? "ACTIVE" : "INACTIVE";
}
}
使用表达式将复杂逻辑注入到映射中。
6. 忽略字段:选择性映射的艺术
有时候,少即是多。忽略不需要的字段:
@Mapper
public interface UserMapper {
@Mapping(target = "password", ignore = true)
@Mapping(target = "createdAt", ignore = true)
UserDTO mapToDTO(User user);
}
非常适合处理敏感数据或不属于DTO的字段。
7. 反向映射:双向进行
需要来回映射?MapStruct为你提供支持:
@Mapper
public interface UserMapper {
@Mapping(target = "id", ignore = true)
User mapToEntity(UserDTO dto);
UserDTO mapToDTO(User user);
}
只需定义两个方法,MapStruct会为你处理双向映射。
8. 默认值:填补空白
有时,你需要为缺失的数据提供默认值:
@Mapper
public interface ProductMapper {
@Mapping(target = "inStock", constant = "true")
@Mapping(target = "category", defaultValue = "UNCATEGORIZED")
ProductDTO mapToDTO(Product product);
}
使用constant为硬编码值,使用defaultValue为源为空时的备用值。
9. 映射前后:最后的润色
需要在映射前后执行一些操作?试试@BeforeMapping和@AfterMapping:
@Mapper
public abstract class OrderMapper {
@Mapping(target = "total", ignore = true)
public abstract OrderDTO mapToDTO(Order order);
@AfterMapping
protected void calculateTotal(Order order, @MappingTarget OrderDTO orderDTO) {
orderDTO.setTotal(order.getItems().stream()
.mapToDouble(item -> item.getPrice() * item.getQuantity())
.sum());
}
}
非常适合复杂计算或最后的调整。
10. 自定义MapStruct注解:抽象的力量
创建自己的注解以封装常见的映射模式:
@Retention(RetentionPolicy.CLASS)
@Mapping(target = "id", ignore = true)
@Mapping(target = "createdAt", expression = "java(java.time.LocalDateTime.now())")
public @interface ToEntity { }
@Mapper
public interface UserMapper {
@ToEntity
User mapToEntity(UserDTO dto);
}
这种方法有助于保持映射器的整洁,并促进代码库中的重用。
总结:MapStruct的魔力释放
以上就是10个MapStruct技巧,它们将提升你的Quarkus映射水平。从上下文感知的映射到自定义注解,MapStruct充满了可以简化复杂对象转换的功能。
记住,掌握MapStruct的关键在于实验。不要害怕深入文档,尝试这些技术的不同组合。你的未来自我(以及代码审查员)会感谢你编写的干净、高效且可维护的映射代码。
所以,下次当你想手动设置时,退一步问问自己:“MapStruct会怎么做?”很可能,它有一个技巧可以让你的生活轻松很多。
祝映射愉快,Quarkus忍者们!🚀
“映射的艺术不在于创建新对象,而在于揭示现有对象之间的关系。” - 匿名开发者(可能)
附言:如果你觉得MapStruct有用,别忘了在GitHub上为MapStruct仓库加星。开源项目依赖社区支持!