欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Java對象轉(zhuǎn)換神器MapStruct庫的使用

 更新時間:2022年09月02日 08:34:00   作者:指北君  
在我們?nèi)粘i_發(fā)的程序中,為了各層之間解耦,一般會定義不同的對象用來在不同層之間傳遞數(shù)據(jù)。當(dāng)在不同層之間傳輸數(shù)據(jù)時,不可避免地經(jīng)常需要將這些對象進行相互轉(zhuǎn)換。今天給大家介紹一個對象轉(zhuǎn)換工具MapStruct,代碼簡潔安全、性能高,強烈推薦

前言

在我們?nèi)粘i_發(fā)的程序中,為了各層之間解耦,一般會定義不同的對象用來在不同層之間傳遞數(shù)據(jù),比如xxxDTO、xxxVO、xxxQO,當(dāng)在不同層之間傳輸數(shù)據(jù)時,不可避免地經(jīng)常需要將這些對象進行相互轉(zhuǎn)換。

今天給大家介紹一個對象轉(zhuǎn)換工具MapStruct,代碼簡潔安全、性能高,強烈推薦。

MapStruct簡介

MapStruct是一個代碼生成器,它基于約定優(yōu)于配置,極大地簡化了Java Bean類型之間映射的實現(xiàn)。特點如下:

  • 基于注解
  • 在編譯期自動生成映射轉(zhuǎn)換代碼
  • 類型安全、高性能、無依賴性、易于理解閱讀

MapStruct入門

1. 引入依賴

這里使用Gradle構(gòu)建

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

2. 需要轉(zhuǎn)換的對象

創(chuàng)建兩個示例對象(e.g. 將Demo對象轉(zhuǎn)換為DemoDto對象)

/**
?*?源對象
?*/
@Data
public?class?Demo?{
????private?Integer?id;
????private?String?name;
}

/**
?*?目標(biāo)對象
?*/
@Data
public?class?DemoDto?{
????private?Integer?id;
????private?String?name;
}

3. 創(chuàng)建轉(zhuǎn)換器

只需要創(chuàng)建一個轉(zhuǎn)換器接口類,并在類上添加 @Mapper 注解即可(官方示例推薦以 xxxMapper 格式命名轉(zhuǎn)換器名稱)

@Mapper
public?interface?DemoMapper?{
????//使用Mappers工廠獲取DemoMapper實現(xiàn)類
????DemoMapper?INSTANCE?=?Mappers.getMapper(DemoMapper.class);
????//定義接口方法,參數(shù)為來源對象,返回值為目標(biāo)對象
????DemoDto?toDemoDto(Demo?demo);
}

4. 驗證

public?static?void?main(String[]?args)?{
????Demo?demo?=?new?Demo();
????demo.setId(111);
????demo.setName("hello");

????DemoDto?demoDto?=?DemoMapper.INSTANCE.toDemoDto(demo);

????System.out.println("目標(biāo)對象demoDto為:"?+?demoDto);
????//輸出結(jié)果:目標(biāo)對象demoDto為:DemoDto(id=111, name=hello)
}

測試結(jié)果如下:

目標(biāo)對象demoDto為:DemoDto(id=111, name=hello)

達到了我們的預(yù)期結(jié)果。

5. 自動生成的實現(xiàn)類

為什么聲明一個接口就可以轉(zhuǎn)換對象呢?我們看一下MapStruct在編譯期間自動生成的實現(xiàn)類:

@Generated(
????value?=?"org.mapstruct.ap.MappingProcessor",
????date?=?"2022-09-01T17:54:38+0800",
????comments?=?"version:?1.4.2.Final,?compiler:?IncrementalProcessingEnvironment?from?gradle-language-java-7.3.jar,?environment:?Java?1.8.0_231?(Oracle?Corporation)"
)
public?class?DemoMapperImpl?implements?DemoMapper?{

????@Override
????public?DemoDto?toDemoDto(Demo?demo)?{
????????if?(?demo?==?null?)?{
????????????return?null;
????????}

????????DemoDto?demoDto?=?new?DemoDto();

????????demoDto.setId(?demo.getId()?);
????????demoDto.setName(?demo.getName()?);

????????return?demoDto;
????}
}

可以看到,MapStruct幫我們將繁雜的代碼自動生成了,而且實現(xiàn)類中用的都是最基本的get、set方法,易于閱讀理解,轉(zhuǎn)換速度非???。

MapStruct進階

上面的例子只是小試牛刀,下面開始展示MapStruct的強大之處。

(限于篇幅,這里不展示自動生成的實現(xiàn)類和驗證結(jié)果,大家可自行測試)

場景1:屬性名稱不同、(基本)類型不同

  • 屬性名稱不同: 在方法上加上 @Mapping 注解,用來映射屬性
  • 屬性基本類型不同: 基本類型和String等類型會自動轉(zhuǎn)換

關(guān)鍵字:@Mapping注解

/**
?*?來源對象
?*/
@Data
public?class?Demo?{
????private?Integer?id;
????private?String?name;
}

/**
?*?目標(biāo)對象
?*/
@Data
public?class?DemoDto?{
????private?String?id;
????private?String?fullname;
}

/**
?*?轉(zhuǎn)換器
?*/
@Mapper
public?interface?DemoMapper?{
????DemoMapper?INSTANCE?=?Mappers.getMapper(DemoMapper.class);

????@Mapping(target?=?"fullname",?source?=?"name")
????DemoDto?toDemoDto(Demo?demo);
}

場景2:統(tǒng)一映射不同類型

下面例子中,time1、time2、time3都會被轉(zhuǎn)換,具體說明看下面的注釋:

/**
?*?來源對象
?*/
@Data
public?class?Demo?{
????private?Integer?id;
????private?String?name;
????/**
?????*?time1、time2名稱相同,time3轉(zhuǎn)為time33
?????*?這里的time1、time2、time33都是Date類型
?????*/
????private?Date?time1;
????private?Date?time2;
????private?Date?time3;
}

/**
?*?目標(biāo)對象
?*/
@Data
public?class?DemoDto?{
????private?String?id;
????private?String?name;
????/**
?????*?這里的time1、time2、time33都是String類型
?????*/
????private?String?time1;
????private?String?time2;
????private?String?time33;
}

/**
?*?轉(zhuǎn)換器
?*/
@Mapper
public?interface?DemoMapper?{
????DemoMapper?INSTANCE?=?Mappers.getMapper(DemoMapper.class);

????@Mapping(target?=?"time33",?source?=?"time3")
????DemoDto?toDemoDto(Demo?demo);
????
????//MapStruct會將所有匹配到的:
????//源類型為Date、目標(biāo)類型為String的屬性,
????//按以下方法進行轉(zhuǎn)換
????static?String?date2String(Date?date)?{
????????SimpleDateFormat?simpleDateFormat?=?new?SimpleDateFormat("yyyy-MM-dd?HH:mm:ss");
????????String?strDate?=?simpleDateFormat.format(date);
????????return?strDate;
????}
}

場景3:固定值、忽略某個屬性、時間轉(zhuǎn)字符串格式

一個例子演示三種用法,具體說明看注釋,很容易理解:

關(guān)鍵字:ignore、constant、dateFormat

/**
?*?來源對象
?*/
@Data
public?class?Demo?{
????private?Integer?id;
????private?String?name;
????private?Date?time;
}

/**
?*?目標(biāo)對象
?*/
@Data
public?class?DemoDto?{
????private?String?id;
????private?String?name;
????private?String?time;
}

/**
?*?轉(zhuǎn)換器
?*/
@Mapper
public?interface?DemoMapper?{
????DemoMapper?INSTANCE?=?Mappers.getMapper(DemoMapper.class);

????//id屬性不賦值
????@Mapping(target?=?"id",?ignore?=?true)
????//name屬性固定賦值為“hello”
????@Mapping(target?=?"name",?constant?=?"hello")
????//time屬性轉(zhuǎn)為yyyy-MM-dd?HH:mm:ss格式的字符串
????@Mapping(target?=?"time",?dateFormat?=?"yyyy-MM-dd?HH:mm:ss")
????DemoDto?toDemoDto(Demo?demo);
}

場景4:為某個屬性指定轉(zhuǎn)換方法

場景2中,我們是按照某個轉(zhuǎn)換方法,統(tǒng)一將一種類型轉(zhuǎn)換為另外一種類型;而下面這個例子,是為某個屬性指定方法:

關(guān)鍵字:@Named注解、qualifiedByName

/**
?*?來源對象
?*/
@Data
public?class?Demo?{
????private?Integer?id;
????private?String?name;
}

/**
?*?目標(biāo)對象
?*/
@Data
public?class?DemoDto?{
????private?String?id;
????private?String?name;
}

/**
?*?轉(zhuǎn)換器
?*/
@Mapper
public?interface?DemoMapper?{
????DemoMapper?INSTANCE?=?Mappers.getMapper(DemoMapper.class);

????//為name屬性指定@Named為convertName的方法進行轉(zhuǎn)換
????@Mapping(target?=?"name",?qualifiedByName?=?"convertName")
????DemoDto?toDemoDto(Demo?demo);

????@Named("convertName")
????static?String?aaa(String?name)?{
????????return?"姓名為:"?+?name;
????}
}

場景5:多個參數(shù)合并為一個對象

如果參數(shù)為多個的話,@Mapping注解中的source就要指定是哪個參數(shù)了,用點分隔:

關(guān)鍵字:點(.)

/**
?*?來源對象
?*/
@Data
public?class?Demo?{
????private?Integer?id;
????private?String?name;
}

/**
?*?目標(biāo)對象
?*/
@Data
public?class?DemoDto?{
????private?String?fullname;
????private?String?timestamp;
}

/**
?*?轉(zhuǎn)換器
?*/
@Mapper
public?interface?DemoMapper?{
????DemoMapper?INSTANCE?=?Mappers.getMapper(DemoMapper.class);

????//fullname屬性賦值demo對象的name屬性(注意這里.的用法)
????//timestamp屬性賦值為傳入的time參數(shù)
????@Mapping(target?=?"fullname",?source?=?"demo.name")
????@Mapping(target?=?"timestamp",?source?=?"time")
????DemoDto?toDemoDto(Demo?demo,?String?time);
}

場景6:已有目標(biāo)對象,將源對象屬性覆蓋到目標(biāo)對象

覆蓋目標(biāo)對象屬性時,一般null值不覆蓋,所以需要在類上的@Mapper注解中添加屬性:nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE 代表null值不進行賦值。

關(guān)鍵字:@MappingTarget注解、nullValuePropertyMappingStrategy

/**
?*?來源對象
?*/
@Data
public?class?Demo?{
????private?Integer?id;
????private?String?name;
}

/**
?*?目標(biāo)對象
?*/
@Data
public?class?DemoDto?{
????private?String?id;
????private?String?name;
}

/**
?*?轉(zhuǎn)換器
?*/
@Mapper(unmappedTargetPolicy?=?ReportingPolicy.IGNORE,
????????nullValuePropertyMappingStrategy?=?NullValuePropertyMappingStrategy.IGNORE)
public?interface?DemoMapper?{
????DemoMapper?INSTANCE?=?Mappers.getMapper(DemoMapper.class);

????//將已有的目標(biāo)對象當(dāng)作一個參數(shù)傳進來
????DemoDto?toDemoDto(Demo?demo,?@MappingTarget?DemoDto?dto);
}

場景7:源對象兩個屬性合并為一個屬性

這種情況可以使用@AfterMapping注解。

關(guān)鍵字:@AfterMapping注解、@MappingTarget注解

/**
?*?來源對象
?*/
@Data
public?class?Demo?{
????private?Integer?id;
????private?String?firstName;
????private?String?lastName;
}

/**
?*?目標(biāo)對象
?*/
@Data
public?class?DemoDto?{
????private?String?id;
????private?String?name;
}

/**
?*?轉(zhuǎn)換器
?*/
@Mapper
public?interface?DemoMapper?{
????DemoMapper?INSTANCE?=?Mappers.getMapper(DemoMapper.class);

????DemoDto?toDemoDto(Demo?demo);

????//在轉(zhuǎn)換完成后執(zhí)行的方法,一般用到源對象兩個屬性合并為一個屬性的場景
????//需要將源對象、目標(biāo)對象(@MappingTarget)都作為參數(shù)傳進來,
????@AfterMapping
????static?void?afterToDemoDto(Demo?demo,?@MappingTarget?DemoDto?demoDto)?{
????????String?name?=?demo.getFirstName()?+?demo.getLastName();
????????demoDto.setName(name);
????}
}

小結(jié)

本文介紹了對象轉(zhuǎn)換工具 MapStruct 庫,以安全、簡潔、優(yōu)雅的方式來優(yōu)化我們的轉(zhuǎn)換代碼。

從文中的示例場景中可以看出,MapStruct 提供了大量的功能和配置,使我們可以快捷的創(chuàng)建出各種或簡單或復(fù)雜的映射器。而這些,也只是 MapStruct 庫的冰山一角,還有很多強大的功能文中沒有提到,感興趣的朋友可以自行查看官方文檔。

到此這篇關(guān)于詳解Java對象轉(zhuǎn)換神器MapStruct庫的使用的文章就介紹到這了,更多相關(guān)Java MapStruct內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java操作Apache druid的實例代碼

    java操作Apache druid的實例代碼

    這篇文章主要介紹了java操作Apache druid的實例代碼,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • 詳解Spring中@Valid和@Validated注解用法

    詳解Spring中@Valid和@Validated注解用法

    本文將以新增一個員工為功能切入點,以常規(guī)寫法為背景,慢慢烘托出?@Valid?和?@Validated?注解用法詳解,文中的示例代碼講解詳細,感興趣的可以了解一下
    2022-07-07
  • 聊聊SpringBoot中組件無法被注入的問題

    聊聊SpringBoot中組件無法被注入的問題

    這篇文章主要介紹了SpringBoot中組件無法被注入的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java多線程 實例解析

    Java多線程 實例解析

    這篇文章主要介紹了Java多線程 實例解析,需要的朋友可以參考下
    2017-04-04
  • 一文教你如何使用Java靈活讀取Excel內(nèi)容

    一文教你如何使用Java靈活讀取Excel內(nèi)容

    這篇文章主要給大家介紹了關(guān)于如何使用Java靈活讀取Excel內(nèi)容的相關(guān)資料,讀取Excel數(shù)據(jù)是Java開發(fā)中常見的任務(wù),文中通過代碼示例介紹的非常詳細,需要的朋友可以參考下
    2023-09-09
  • Java矢量隊列Vector使用示例

    Java矢量隊列Vector使用示例

    Vector類實現(xiàn)了一個動態(tài)數(shù)組。和ArrayList很相似,但是兩者是不同的Vector是同步訪問的;Vector包含了許多傳統(tǒng)的方法,這些方法不屬于集合框架
    2023-01-01
  • springboot+vue實現(xiàn)websocket配置過程解析

    springboot+vue實現(xiàn)websocket配置過程解析

    這篇文章主要介紹了springboot+vue實現(xiàn)websocket配置過程解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-04-04
  • Maven中dependency和plugins的繼承與約束

    Maven中dependency和plugins的繼承與約束

    這篇文章主要介紹了Maven中dependency和plugins的繼承與約束,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • kafka生產(chǎn)者和消費者的javaAPI的示例代碼

    kafka生產(chǎn)者和消費者的javaAPI的示例代碼

    這篇文章主要介紹了kafka生產(chǎn)者和消費者的javaAPI的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-06-06
  • SpringBoot3整合Druid監(jiān)控功能的項目實踐

    SpringBoot3整合Druid監(jiān)控功能的項目實踐

    Druid連接池作為一款強大的數(shù)據(jù)庫連接池,提供了豐富的監(jiān)控和管理功能,成為很多Java項目的首選,本文主要介紹了SpringBoot3整合Druid監(jiān)控功能的項目實踐,感興趣的可以了解一下
    2024-01-01

最新評論