停止编写样板代码!使用 MapStruct 简化 Java Bean 映射

发布: (2026年3月14日 GMT+8 12:34)
6 分钟阅读
原文: Dev.to

Source: Dev.to

停止编写样板代码!使用 MapStruct 简化 Java Bean 映射的封面图片

Manoj Mishra

DTO、实体和 Java Bean 之间手动编写对象映射是 Java 开发中最重复且最容易出错的任务之一。开发者常常需要编写数百行使用 getter、setter 和手动转换的样板代码——这使得代码更难维护,也更容易出错。

幸运的是,有一种更聪明的方式。

MapStruct 是一个强大的 Java 注解处理器,能够在编译时自动生成 类型安全的 Bean 映射代码。与其自己编写繁琐的映射逻辑,MapStruct 会为你生成干净且高效的映射实现。

与基于反射的库不同,MapStruct 生成 纯 Java 代码,这意味着 更好的性能、编译时安全性以及更容易的调试

在本指南中,你将学习 MapStruct 如何简化 Java 对象映射,消除样板代码,并帮助你构建更清晰、更易维护的应用程序。

什么是 MapStruct

MapStruct 不是依赖反射的运行时映射库。它是一个 插入 Java 编译器的代码生成器

  1. 定义一个接口并使用 MapStruct 注解进行标注。
  2. 在编译期间,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 BootLombok 无缝配合。

最后思考

如果您经常在 Java 应用程序中映射 DTO 和实体,MapStruct 可以显著减少样板代码,同时提升可维护性和性能。

您在项目中使用过 MapStruct 吗? 在评论中分享您的经验!

0 浏览
Back to Blog

相关文章

阅读更多 »

继承的简单代码示例

简单的银行系统代码示例,java 包 bank.task;public class BankAccount { int accountNumber; double balance; public void deposit(double depositAm...