当前位置: 首页 > article >正文

MapStruct 使用教程

MapStruct 使用教程

MapStruct 是一个用于在 Java Bean 之间执行对象映射的代码生成器。它通过注解处理器在编译时自动生成映射代码,而不是在运行时使用反射技术,从而提供了高性能的映射解决方案。本文将详细介绍 MapStruct 的基本用法、高级特性以及如何在实际项目中集成和使用 MapStruct。

目录

  1. 什么是 MapStruct
  2. MapStruct 的优势
  3. MapStruct 的基本用法
    ◦ 1. 添加依赖
    ◦ 2. 定义源和目标 Bean
    ◦ 3. 创建映射器接口
    ◦ 4. 使用映射器
  4. MapStruct 的高级特性
    ◦ 1. 字段映射
    ◦ 2. 嵌套对象映射
    ◦ 3. 集合映射
    ◦ 4. 自定义映射方法
    ◦ 5. 使用条件映射
    ◦ 6. 默认值和常量映射
  5. 集成 MapStruct 到项目中
    ◦ 1. Maven 配置
    ◦ 2. Gradle 配置
  6. 常见问题与解决方案
  7. 总结

什么是 MapStruct

MapStruct 是一个基于注解的 Java Bean 映射工具,它在编译时生成类型安全的映射代码,避免了运行时的反射开销。MapStruct 的主要目标是简化对象之间的映射过程,同时保持高性能和可维护性。

MapStruct 的优势

编译时类型安全:在编译阶段捕捉类型不匹配的问题,避免运行时错误。
高性能:生成的代码避免了反射,性能接近手写映射代码。
可定制性强:支持自定义映射方法、表达式和条件映射。
易于集成:简单的注解配置,无缝集成到现有项目中。
良好的可测试性:生成的映射器是普通的 Java 接口,易于进行单元测试。

MapStruct 的基本用法

1. 添加依赖

以 Maven 项目为例,需要在 pom.xml 文件中添加 MapStruct 的依赖及注解处理器。

<dependencies>
    <!-- MapStruct 核心库 -->
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>1.5.5.Final</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.11.0</version>
            <configuration>
                <source>17</source>
                <target>17</target>
                <annotationProcessorPaths>
                    <!-- MapStruct 注解处理器 -->
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>1.5.5.Final</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>

注意:确保 <source><target> 版本与项目使用的 Java 版本一致。如果使用其他构建工具(如 Gradle),请参考 MapStruct 官方文档 进行相应配置。

2. 定义源和目标 Bean

假设我们有两个类 SourceBeanTargetBean,需要将 SourceBean 的属性映射到 TargetBean

// SourceBean.java
public class SourceBean {
    private String firstName;
    private String lastName;
    private int age;
    private Address sourceAddress;

    // getters and setters
}

// TargetBean.java
public class TargetBean {
    private String fullName;
    private int age;
    private Address targetAddress;

    // getters and setters
}

// Address.java
public class Address {
    private String street;
    private String city;

    // getters and setters
}

3. 创建映射器接口

使用 @Mapper 注解定义一个映射器接口,并在需要的地方使用 @Mapping 注解指定字段映射规则。

// SourceTargetMapper.java
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;

@Mapper
public interface SourceTargetMapper {
    SourceTargetMapper INSTANCE = Mappers.getMapper(SourceTargetMapper.class);

    @Mapping(source = "firstName", target = "fullName", 
              expression = "java(sourceBean.getFirstName() + \" \" + sourceBean.getLastName())")
    @Mapping(source = "sourceAddress", target = "targetAddress")
    TargetBean sourceToTarget(SourceBean sourceBean);

    // 如果 Address 类也需要映射,可以定义嵌套的映射方法
    Address mapAddress(SourceBean.Address sourceAddress);
}

说明

@Mapper 注解标识这是一个 MapStruct 映射器接口。
INSTANCE 是一个单例实例,用于调用映射方法。
@Mapping 注解用于指定字段之间的映射关系。如果字段名称不一致,需要使用 sourcetarget 属性进行映射。
expression 属性允许使用 Java 表达式进行复杂的字段转换。

4. 使用映射器

在代码中使用映射器接口进行对象映射。

// App.java
public class App {
    public static void main(String[] args) {
        SourceBean source = new SourceBean();
        source.setFirstName("John");
        source.setLastName("Doe");
        source.setAge(30);

        Address address = new Address();
        address.setStreet("123 Main St");
        address.setCity("Anytown");
        source.setSourceAddress(address);

        TargetBean target = SourceTargetMapper.INSTANCE.sourceToTarget(source);

        System.out.println(target.getFullName()); // 输出: John Doe
        System.out.println(target.getAge()); // 输出: 30
        System.out.println(target.getTargetAddress().getStreet()); // 输出: 123 Main St
    }
}

MapStruct 的高级特性

1. 字段映射

默认情况下,MapStruct 会根据字段名称自动映射。如果源和目标字段名称不一致,可以使用 @Mapping 注解指定。

@Mapper
public interface AdvancedMapper {
    @Mapping(source = "sourceField", target = "targetField")
    TargetBean map(SourceBean source);
}

2. 嵌套对象映射

当源和目标对象包含嵌套对象时,需要定义嵌套对象的映射方法。

@Mapper
public interface NestedMapper {
    NestedMapper INSTANCE = Mappers.getMapper(NestedMapper.class);

    @Mapping(source = "address.street", target = "location.street")
    @Mapping(source = "address.city", target = "location.city")
    TargetBean map(SourceBean source);

    default Location map(Address address) {
        if (address == null) return null;
        Location loc = new Location();
        loc.setStreet(address.getStreet());
        loc.setCity(address.getCity());
        return loc;
    }
}

3. 集合映射

MapStruct 支持集合类型的映射,如 ListSet 等。

@Mapper
public interface CollectionMapper {
    CollectionMapper INSTANCE = Mappers.getMapper(CollectionMapper.class);

    List<TargetBean> mapSources(List<SourceBean> sources);

    TargetBean map(SourceBean source);
}

注意:集合中的每个元素将逐一映射,需要确保单个元素的映射方法已定义。

4. 自定义映射方法

对于复杂的映射逻辑,可以定义自定义的映射方法。

@Mapper
public interface CustomMapper {
    CustomMapper INSTANCE = Mappers.getMapper(CustomMapper.class);

    @Mapping(source = "age", target = "ageGroup")
    TargetBean map(SourceBean source);

    default String mapAgeToAgeGroup(int age) {
        if (age < 18) return "Minor";
        else if (age < 65) return "Adult";
        else return "Senior";
    }
}

5. 使用条件映射

可以使用 @Condition 注解或自定义表达式实现条件映射。

@Mapper
public interface ConditionalMapper {
    ConditionalMapper INSTANCE = Mappers.getMapper(ConditionalMapper.class);

    @Mapping(target = "status", 
              expression = "java(source.getAge() >= 18 ? \"Adult\" : \"Minor\")")
    TargetBean map(SourceBean source);
}

6. 默认值和常量映射

可以为目标字段设置默认值或常量。

@Mapper
public interface DefaultValueMapper {
    DefaultValueMapper INSTANCE = Mappers.getMapper(DefaultValueMapper.class);

    @Mapping(target = "status", constant = "Active")
    TargetBean map(SourceBean source);
}

集成 MapStruct 到项目中

1. Maven 配置

确保在 pom.xml 中正确添加 MapStruct 依赖和注解处理器。

<dependencies>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>1.5.5.Final</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.11.0</version>
            <configuration>
                <source>17</source>
                <target>17</target>
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>1.5.5.Final</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>

2. Gradle 配置

如果使用 Gradle,可以在 build.gradle 中添加如下配置:

plugins {
    id 'java'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.mapstruct:mapstruct:1.5.5.Final'
    annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.5.Final'
}

// 对于 Gradle 6.0 及以上版本,可以使用以下配置
// 如果使用 Kapt(Kotlin),请相应调整

注意:确保使用的 Gradle 版本支持 annotationProcessor 配置。对于 Kotlin 项目,需要使用 kapt 插件。

常见问题与解决方案

  1. 映射器接口未被实现
    ◦ 确保在构建工具中正确配置了 MapStruct 注解处理器。
    ◦ 检查 @Mapper 注解是否正确应用在接口上。
    ◦ 确保源和目标类具有相应的 getter 和 setter 方法。

  2. 字段未映射警告
    ◦ 使用 @Mapping 注解明确指定所有需要映射的字段。
    ◦ 使用 @Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE) 忽略未映射的目标字段(不推荐,除非确信不需要映射)。

  3. 复杂类型映射失败
    ◦ 确保为复杂类型定义了相应的映射方法。
    ◦ 使用 @Mapperuses 属性引用其他映射器接口。

    @Mapper(uses = AddressMapper.class)
    public interface ComplexMapper {
        ComplexMapper INSTANCE = Mappers.getMapper(ComplexMapper.class);
    
        @Mapping(source = "address", target = "location")
        TargetBean map(SourceBean source);
    }
    
    @Mapper
    public interface AddressMapper {
        AddressMapper INSTANCE = Mappers.getMapper(AddressMapper.class);
    
        Location map(Address address);
    }
    
  4. 泛型类型映射
    ◦ MapStruct 支持泛型类型的映射,但需要确保泛型类型参数被正确推断或指定。

    @Mapper
    public interface GenericMapper<S, T> {
        T map(S source);
    }
    
    // 使用时指定具体类型
    GenericMapper<SourceBean, TargetBean> specificMapper = Mappers.getMapper(GenericMapper.class);
    

    注意:对于更复杂的泛型映射,可能需要结合其他工具或手动编写部分代码。

总结

MapStruct 是一个功能强大且高效的 Java Bean 映射工具,通过编译时生成映射代码,提供了类型安全和高性能的映射解决方案。其丰富的注解和灵活的自定义能力使得处理复杂映射变得简单。在实际项目中,合理使用 MapStruct 可以显著减少样板代码,提高开发效率和代码质量。

通过本文的介绍,相信您已经掌握了 MapStruct 的基本用法和一些高级特性。建议在实际项目中尝试使用 MapStruct,并参考 MapStruct 官方文档 了解更多详细信息和最佳实践。


http://www.kler.cn/a/594764.html

相关文章:

  • 技术分享 | MySQL内存使用率高问题排查
  • 如何用C++封装纯C写的函数库,如何处理C函数调用返回错误
  • OpenNJet:下一代云原生应用引擎,支持动态配置与高效管理,简化运维任务,提升应用灵活性与安全性。
  • 【Docker入门】用Docker启动项目
  • Leetcode 378. 有序矩阵中第 K 小的元素 二分查找
  • 【uni-app】集成SQLite,无服务数据库
  • 上海蒂正科技有限公司:技术驱动数字化,打造高端企业门户新标杆
  • Web-Machine-N7靶机攻略
  • C# 派生 详解
  • ONE Deep模型:LG AI Research的开源突破
  • uni-app基础问题(一)
  • 后端框架模块化
  • Docker安装,并pullMySQL和redis
  • C#入门:从变量与数据类型开始你的游戏开发之旅
  • 京东物流数据+商品API融合应用:打造供应链智能预警系统
  • wps打开的excel如何插入、编辑、删除、显示批注?
  • 阿里云平台域名
  • 数据库与其所用数据结构
  • Stream 流中 flatMap 方法详解
  • 生成式AI三巨头技术解析:ChatGPT、DeepSeek与Grok的核心差异与未来竞争格局