Java中MapStruct入门使用及对比

 更新时间:2023年12月06日 09:57:24   作者:檀越剑指大厂  
MapStruct是一个Java注解处理器框架,用于简化Java Bean之间的映射,本文主要介绍了Java中MapStruct入门使用及对比,感兴趣的可以了解一下

一.简单介绍

1.什么是 MapStruct?

MapStruct 是一个 Java 注解处理器框架,用于简化 Java Bean 之间的映射。它通过生成映射代码来消除手动编写映射代码的繁琐工作,从而提高开发效率。

2.MapStruct 的特点

  • 简化映射: MapStruct 旨在简化 Java Bean 之间的映射,减少手动编写映射代码的工作量。
  • 注解处理器: MapStruct 使用注解处理器技术,在编译时生成映射代码,而不是在运行时进行反射。
  • 类型安全: 通过在映射接口上使用注解,MapStruct 能够在编译时检查映射的正确性,提供类型安全性。
  • 支持自定义映射逻辑: 尽管 MapStruct 提供了默认的映射规则,但你仍然可以通过在映射接口中定义自定义方法来指定特定的映射逻辑。

二.基础使用

1.添加依赖

添加依赖: 首先,在你的项目中添加 MapStruct 的依赖。你可以在 Maven 或 Gradle 中进行配置。

Maven:

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.4.2.Final</version> <!-- 使用最新版本 -->
</dependency>

Gradle:

implementation 'org.mapstruct:mapstruct:1.4.2.Final' // 使用最新版本
annotationProcessor 'org.mapstruct:mapstruct-processor:1.4.2.Final'

2.定义映射接口

定义映射接口: 创建一个带有@Mapper注解的接口,定义映射方法。

@Mapper
public interface CarMapper {
    CarDto carToCarDto(Car car);
}

3.编写配置

编写映射配置: 如果需要自定义映射逻辑,可以在映射接口中定义自定义方法,或者使用@Mapping注解。

@Mapper
public interface CarMapper {
    @Mapping(source = "make", target = "manufacturer")
    CarDto carToCarDto(Car car);
}

4.生成代码

生成映射代码: 编译项目时,MapStruct 注解处理器将生成映射代码。

5.调用方法

调用映射方法: 在应用程序中调用生成的映射方法。

CarMapper carMapper = Mappers.getMapper(CarMapper.class);
CarDto carDto = carMapper.carToCarDto(car);

以上是 MapStruct 的基本介绍和使用步骤。通过这些步骤,你可以轻松地实现 Java Bean 之间的映射,同时保持代码的简洁和易维护性。

三.封装使用

1.FromConverter

public interface FromConverter<T, FROM> {

    T from(FROM from);

    List<T> from(List<FROM> list);

    default PageBean<T> from(PageBean<FROM> page) {
        PageBean<T> result = new PageBean<>();
        result.setTotalElements(page.getTotalElements());
        result.setNumber(page.getNumber());
        result.setSize(page.getSize());
        result.setTotalPages(page.getTotalPages());
        result.setNumberOfElements(page.getNumberOfElements());
        result.setContent(this.from(page.getContent()));
        return result;
    }

    default PageBean<T> from(IPage<FROM> page) {
        PageBean<T> result = new PageBean<>();
        result.setTotalElements((int) page.getTotal());
        result.setNumber((int) page.getCurrent());
        result.setSize((int) page.getSize());
        result.setTotalPages((int) page.getPages());
        result.setNumberOfElements(page.getRecords().size());
        result.setContent(this.from(page.getRecords()));
        return result;
    }
}

2.PropertyCopier

public interface PropertyCopier<TARGET, T> {
    void copy(@MappingTarget TARGET target, T t);
}

3.ToConverter

public interface ToConverter<T, TO> {
    TO to(T t);

    List<TO> to(List<T> list);

    default PageBean<TO> to(PageBean<T> page) {
        PageBean<TO> result = new PageBean<>();
        result.setTotalElements(page.getTotalElements());
        result.setNumber(page.getNumber());
        result.setSize(page.getSize());
        result.setTotalPages(page.getTotalPages());
        result.setNumberOfElements(page.getNumberOfElements());
        result.setContent(this.to(page.getContent()));
        return result;
    }

    default PageBean<TO> to(IPage<T> page) {
        PageBean<TO> result = new PageBean<>();
        result.setTotalElements((int) page.getTotal());
        result.setNumber((int) page.getCurrent());
        result.setSize((int) page.getSize());
        result.setTotalPages((int) page.getPages());
        result.setNumberOfElements(page.getRecords().size());
        result.setContent(this.to(page.getRecords()));
        return result;
    }
}

4.TwoWayConverter

public interface TwoWayConverter<SRC, DEST> extends ToConverter<SRC, DEST>, FromConverter<SRC, DEST> {
}

5.基本使用

@Data
public class ChatbotDTO {

    private Integer id;
    private String question;
    private String response;
    private Date createTime;
    private Integer isDelete;

    @Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE)
    public interface Converter extends FromConverter<ChatbotDTO, Chatbot> {
        Converter INSTANCE = Mappers.getMapper(Converter.class);
    }
}
@Data
public class Chatbot extends Model<Chatbot> {
    private Integer id;
    private String question;
    private String response;
    private Date createTime;
    private Integer isDelete;
}

6.原理分析

打开 target 目录,可以看到如图所示的编译后生成的类,说明在编译器就生成了对应的 DTO,相比其他 2 种方式在运行时生成 DTO 更加高效。

7.使用技巧

  • 忽略字段映射
  • 源对象与目标对象属性名不符的映射方法
  • 直接设置特定值
  • 表达式映射
  • 自定义映射

四.工具对比

1.概述

MapStruct、Apache BeanUtils 以及 Spring BeanUtils 都是用于 Java Bean 之间属性复制的工具,但它们有一些区别,包括实现方式、性能、功能等方面。

2.MapStruct

优势:

  • 编译时检查: MapStruct 在编译时生成映射代码,提供了类型安全性,可以在编译时捕获一些映射错误。
  • 性能: 由于生成的映射代码是直接的 Java 代码,MapStruct 通常在性能上优于运行时反射的解决方案。
  • 可配置性: 提供了很高的自定义能力,你可以在映射接口中定义自定义方法或使用@Mapping注解来指定映射规则。
  • MapStruct 能自动的将名字一样,类型不一致的属性值进行转化再赋值(仅限基本类型的包装类型,如果转化值适配不了对应类型会报错

不足:

  • 学习曲线: 对于初学者而言,可能需要一些时间来理解和配置 MapStruct。

3.Apache BeanUtils

优势:

  • 简单易用: Apache BeanUtils 提供了简单的 API,易于上手。
  • 反射: 使用反射机制实现属性复制,可以在运行时处理动态对象。

不足:

  • 性能: 相对于 MapStruct,Apache BeanUtils 在性能上可能较慢,因为它使用反射进行属性复制。
  • 类型安全: 由于是在运行时进行反射,缺乏编译时类型检查。

4.Spring BeanUtils

优势:

  • 集成 Spring: Spring BeanUtils 是 Spring 框架的一部分,可以很容易地集成到 Spring 应用程序中。
  • 简化代码: 提供了一些方便的方法,可以简化属性复制的代码。

不足:

  • 性能: 与 Apache BeanUtils 类似,Spring BeanUtils 也是使用反射,因此性能相对较低。
  • 可配置性: 相较于 MapStruct,可配置性相对较低。

5.总结:

  • MapStruct 提供了编译时类型检查和高度可配置性,适用于需要更高性能和更复杂映射规则的场景。

  • Apache BeanUtils 和 Spring BeanUtils 简单易用,适用于简单的属性复制场景,但在性能和类型安全性方面可能相对较差。

选择使用哪个工具取决于你的具体需求,如果性能和类型安全性是关键考虑因素,而且你愿意付出一些学习成本,那么 MapStruct 可能是一个更好的选择。如果你需要一个简单且易于使用的解决方案,并且性能要求不是很高,那么 Apache BeanUtils 或 Spring BeanUtils 可能是更合适的选择。

到此这篇关于Java中MapStruct入门使用及对比的文章就介绍到这了,更多相关Java MapStruct内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • MyBatis框架零基础快速入门案例详解

    MyBatis框架零基础快速入门案例详解

    MyBatis本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation迁移到了google code,并且改名为MyBatis。2013年11月迁移到Github。iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架
    2022-04-04
  • java的SimpleDateFormat线程不安全的几种解决方案

    java的SimpleDateFormat线程不安全的几种解决方案

    但我们知道SimpleDateFormat是线程不安全的,处理时要特别小心,要加锁或者不能定义为static,要在方法内new出对象,再进行格式化,本文就介绍了几种方法,感兴趣的可以了解一下
    2021-08-08
  • Java中的static关键字用法总结

    Java中的static关键字用法总结

    这篇文章主要介绍了Java中的static关键字用法总结,static是Java50个关键字之一,static关键字可以用来修饰代码块表示静态代码块,修饰成员变量表示全局静态成员变量,修饰方法表示静态方法,需要的朋友可以参考下
    2023-11-11
  • 老生常谈java中的Future模式

    老生常谈java中的Future模式

    下面小编就为大家带来一篇老生常谈java中的Future模式。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • 如何使用 Spring Boot 和 Canal 实现 MySQL 数据库同步

    如何使用 Spring Boot 和 Canal 实现 My

    本文介绍了如何使用SpringBoot和Canal实现MySQL数据库之间的数据同步,通过配置主库、创建Canal用户、配置CanalServer以及开发SpringBoot客户端,实现了将主库的数据实时同步到多个从库,感兴趣的朋友跟随小编一起看看吧
    2025-02-02
  • java利用冒泡排序对数组进行排序

    java利用冒泡排序对数组进行排序

    这篇文章主要介绍了java利用冒泡排序对数组进行排序的方法,实例分析了冒泡排序的概念与java实现方法,以及java操作数组的相关技巧,需要的朋友可以参考下
    2015-05-05
  • java链式创建json对象的实现

    java链式创建json对象的实现

    本文主要介绍了java中如何通过最简单的方式实现链式创建json对象,解决创建json代码臃肿的问题,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • Java JTable 实现日历的示例

    Java JTable 实现日历的示例

    这篇文章主要介绍了Java JTable 实现日历的示例,帮助大家更好的理解和学习Java jtable的使用方法,感兴趣的朋友可以了解下
    2020-10-10
  • HashMap的get()方法的NullPointerException问题

    HashMap的get()方法的NullPointerException问题

    这篇文章主要介绍了HashMap的get()方法的NullPointerException问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • Java数组和可变参数使用举例详解

    Java数组和可变参数使用举例详解

    Java中的可变参数和数组参数在使用上很相似,但它们在方法定义、调用方式以及编译处理上有明显区别,理解这些差异有助于写出更清晰、安全的代码,这篇文章主要介绍了Java数组和可变参数的相关资料,需要的朋友可以参考下
    2026-05-05

最新评论