停止编写样板代码!使用 MapStruct 简化 Java Bean 映射
Source: Dev.to

在 DTO、实体和 Java Bean 之间手动编写对象映射是 Java 开发中最重复且最容易出错的任务之一。开发者常常需要编写数百行使用 getter、setter 和手动转换的样板代码——这使得代码更难维护,也更容易出错。
幸运的是,有一种更聪明的方式。
MapStruct 是一个强大的 Java 注解处理器,能够在编译时自动生成 类型安全的 Bean 映射代码。与其自己编写繁琐的映射逻辑,MapStruct 会为你生成干净且高效的映射实现。
与基于反射的库不同,MapStruct 生成 纯 Java 代码,这意味着 更好的性能、编译时安全性以及更容易的调试。
在本指南中,你将学习 MapStruct 如何简化 Java 对象映射,消除样板代码,并帮助你构建更清晰、更易维护的应用程序。
什么是 MapStruct?
MapStruct 不是依赖反射的运行时映射库。它是一个 插入 Java 编译器的代码生成器。
- 定义一个接口并使用 MapStruct 注解进行标注。
- 在编译期间,MapStruct 会生成该接口的实现,包含所有必要的映射逻辑。
关键优势
- Type Safety – 映射错误在编译时被检测到。
- High Performance – 生成的代码是纯 Java,不使用反射。
- Easy to Debug – 生成的代码可读且易于调试。
为什么选择 MapStruct 而不是手动映射或其他库?
MapStruct 脱颖而出,因为它提供:
- 减少样板代码
- 编译时安全性
- 高性能
- 清晰的声明式映射
- 与 Spring、Lombok 等框架的出色集成
强大功能
MapStruct 支持:
- 映射不同的字段名
- 嵌套 Bean 映射
- 集合映射
- 类型转换
- 自定义映射方法
- 默认值和表达式
入门:设置 MapStruct
Maven 配置
<properties>
<org.mapstruct.version>1.5.5.Final</org.mapstruct.version>
<lombok.version>1.18.30</lombok.version>
</properties>
<dependencies>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>0.2.0</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>Source: …
核心概念与示例
1. 基本映射
Domain 类
public class User {
private Long id;
private String firstName;
private String lastName;
private String email;
}DTO
public class UserDto {
private Long id;
private String firstName;
private String lastName;
private String email;
}Mapper
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper
public interface UserMapper {
UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
UserDto userToUserDto(User user);
User userDtoToUser(UserDto userDto);
}使用方式
User user = new User();
UserDto dto = UserMapper.INSTANCE.userToUserDto(user);2. 处理不同的字段名称
@Mapper
public interface SourceTargetMapper {
SourceTargetMapper INSTANCE = Mappers.getMapper(SourceTargetMapper.class);
@Mapping(source = "ageYears", target = "age")
TargetBean sourceToTarget(SourceBean source);
@Mapping(source = "age", target = "ageYears")
SourceBean targetToSource(TargetBean target);
}3. 映射嵌套对象
@Mapper(uses = {AddressMapper.class})
public interface UserMapper {
UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
UserDto userToUserDto(User user);
}4. 映射集合
@Mapper
public interface UserMapper {
List<UserDto> usersToUserDtos(List<User> users);
}5. 使用 @Named 的自定义逻辑
@Mapper
public abstract class OrderMapper {
@Named("formatDate")
String formatDate(LocalDate date) {
return date.format(DateTimeFormatter.ISO_LOCAL_DATE);
}
@Mapping(source = "orderDate", target = "orderDateString", qualifiedByName = "formatDate")
public abstract OrderDto orderToDto(Order order);
}Conclusion
MapStruct 消除了与手动 bean 映射相关的繁琐且易出错的样板代码,同时提供编译时安全性和高性能。通过将其集成到构建流程中,您可以专注于业务逻辑,而不是重复的转换代码。映射愉快!
6. 默认值和表达式
@Mapper
public interface ProductMapper {
@Mapping(target = "status", defaultValue = "AVAILABLE")
@Mapping(
target = "description",
expression = "java(product.getName().toUpperCase() + \" - AWESOME!\")"
)
ProductDto productToProductDto(Product product);
}最佳实践
- 保持映射器专注 – 每个映射器应只处理单一的逻辑关注点。
- 使用
uses进行映射器组合 – 将复杂的映射委托给其他映射器。 - 倾向使用显式
@Mapping– 使映射意图清晰,避免意外。 - 与 Lombok 结合 – Lombok 可以生成 getter/setter,而 MapStruct 负责映射。
- 对自定义逻辑进行单元测试 – 尤其是任何
@Named方法或表达式。
针对 Spring 项目
@Mapper(componentModel = "spring")结论
MapStruct 通过在编译时生成 类型安全、高性能的代码 来简化对象映射。
好处
- 减少样板代码
- 编译时安全
- 更好的可维护性
- 提高开发者生产力
如果你还没有尝试过 MapStruct,赶快试试吧!
关键要点
- MapStruct 在 编译时 生成映射代码。
- 它消除了 手动样板映射。
- 提供 类型安全的 DTO 转换。
- 与 Spring Boot 和 Lombok 无缝配合。
最后思考
如果您经常在 Java 应用程序中映射 DTO 和实体,MapStruct 可以显著减少样板代码,同时提升可维护性和性能。
您在项目中使用过 MapStruct 吗? 在评论中分享您的经验!
