国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

丟棄掉那些BeanUtils工具類吧,MapStruct真香!!!

開發 后端
本文介紹了一款Java中的字段映射工具類,MapStruct,他的用法比較簡單,并且功能非常完善,可以應付各種情況的字段映射。

[[336990]]

在前幾天的文章《為什么阿里巴巴禁止使用Apache Beanutils進行屬性的copy?》中,我曾經對幾款屬性拷貝的工具類進行了對比。

然后在評論區有些讀者反饋說MapStruct才是真的香,于是我就抽時間了解了一下MapStruct。結果我發現,這真的是一個神仙框架,炒雞香。

這一篇文章就來簡單介紹下MapStruct的用法,并且再和其他幾個工具類進行一下對比。

為什么需要MapStruct ?

首先,我們先說一下MapStruct這類框架適用于什么樣的場景,為什么市面上會有這么多的類似的框架。

在軟件體系架構設計中,分層式結構是最常見,也是最重要的一種結構。很多人都對三層架構、四層架構等并不陌生。

甚至有人說:"計算機科學領域的任何問題都可以通過增加一個間接的中間層來解決,如果不行,那就加兩層。"

但是,隨著軟件架構分層越來越多,那么各個層次之間的數據模型就要面臨著相互轉換的問題,典型的就是我們可以在代碼中見到各種O,如DO、DTO、VO等。

一般情況下,同樣一個數據模型,我們在不同的層次要使用不同的數據模型。如在數據存儲層,我們使用DO來抽象一個業務實體;在業務邏輯層,我們使用DTO來表示數據傳輸對象;到了展示層,我們又把對象封裝成VO來與前端進行交互。

那么,數據的從前端透傳到數據持久化層(從持久層透傳到前端),就需要進行對象之間的互相轉化,即在不同的對象模型之間進行映射。

通常我們可以使用get/set等方式逐一進行字段映射操作,如: 

  1. personDTO.setName(personDO.getName());  
  2. personDTO.setAge(personDO.getAge());  
  3. personDTO.setSex(personDO.getSex());  
  4. personDTO.setBirthday(personDO.getBirthday()); 

但是,編寫這樣的映射代碼是一項冗長且容易出錯的任務。MapStruct等類似的框架的目標是通過自動化的方式盡可能多地簡化這項工作。

MapStruct的使用

MapStruct(https://mapstruct.org/ )是一種代碼生成器,它極大地簡化了基于"約定優于配置"方法的Java bean類型之間映射的實現。生成的映射代碼使用純方法調用,因此快速、類型安全且易于理解。

約定優于配置,也稱作按約定編程,是一種軟件設計范式,旨在減少軟件開發人員需做決定的數量,獲得簡單的好處,而又不失靈活性。

假設我們有兩個類需要進行互相轉換,分別是PersonDO和PersonDTO,類定義如下: 

  1. public class PersonDO {  
  2.     private Integer id;  
  3.     private String name;  
  4.     private int age;  
  5.     private Date birthday;  
  6.     private String gender;  
  7.  
  8. public class PersonDTO {  
  9.     private String userName;  
  10.     private Integer age;  
  11.     private Date birthday;  
  12.     private Gender gender;  

我們演示下如何使用MapStruct進行bean映射。

想要使用MapStruct,首先需要依賴他的相關的jar包,使用maven依賴方式如下: 

  1. ...  
  2. <properties>  
  3.     <org.mapstruct.version>1.3.1.Final</org.mapstruct.version>  
  4. </properties>  
  5. ...  
  6. <dependencies>  
  7.     <dependency>  
  8.         <groupId>org.mapstruct</groupId>  
  9.         <artifactId>mapstruct</artifactId>  
  10.         <version>${org.mapstruct.version}</version>  
  11.     </dependency>  
  12. </dependencies>  
  13. ...  
  14. <build>  
  15.     <plugins>  
  16.         <plugin>  
  17.             <groupId>org.apache.maven.plugins</groupId>  
  18.             <artifactId>maven-compiler-plugin</artifactId>  
  19.             <version>3.8.1</version>  
  20.             <configuration>  
  21.                 <source>1.8</source> <!-- depending on your project -->  
  22.                 <target>1.8</target> <!-- depending on your project -->  
  23.                 <annotationProcessorPaths>  
  24.                     <path>  
  25.                         <groupId>org.mapstruct</groupId>  
  26.                         <artifactId>mapstruct-processor</artifactId>  
  27.                         <version>${org.mapstruct.version}</version>  
  28.                     </path>  
  29.                     <!-- other annotation processors -->  
  30.                 </annotationProcessorPaths>  
  31.             </configuration>  
  32.         </plugin>  
  33.     </plugins>  
  34. </build> 

因為MapStruct需要在編譯器生成轉換代碼,所以需要在maven-compiler-plugin插件中配置上對mapstruct-processor的引用。這部分在后文會再次介紹。

之后,我們需要定義一個做映射的接口,主要代碼如下: 

  1. @Mapper  
  2. interface PersonConverter {  
  3.     PersonConverter INSTANCE = Mappers.getMapper(PersonConverter.class);  
  4.     @Mappings(@Mapping(source = "name"target = "userName"))  
  5.     PersonDTO do2dto(PersonDO person);  

使用注解@Mapper定義一個Converter接口,在其中定義一個do2dto方法,方法的入參類型是PersonDO,出參類型是PersonDTO,這個方法就用于將PersonDO轉成PersonDTO。

測試代碼如下: 

  1. public static void main(String[] args) {  
  2.     PersonDO personDO = new PersonDO();  
  3.     personDO.setName("Hollis");  
  4.     personDO.setAge(26);  
  5.     personDO.setBirthday(new Date());  
  6.     personDO.setId(1);  
  7.     personDO.setGender(Gender.MALE.name());  
  8.     PersonDTO personDTO = PersonConverter.INSTANCE.do2dto(personDO);  
  9.     System.out.println(personDTO);  

輸出結果: 

  1. PersonDTO{userName='Hollis'age=26birthday=Sat Aug 08 19:00:44 CST 2020, gender=MALE

可以看到,我們使用MapStruct完美的將PersonDO轉成了PersonDTO。

上面的代碼可以看出,MapStruct的用法比較簡單,主要依賴@Mapper注解。

但是我們知道,大多數情況下,我們需要互相轉換的兩個類之間的屬性名稱、類型等并不完全一致,還有些情況我們并不想直接做映射,那么該如何處理呢?

其實MapStruct在這方面也是做的很好的。

MapStruct處理字段映射

首先,可以明確的告訴大家,如果要轉換的兩個類中源對象屬性與目標對象屬性的類型和名字一致的時候,會自動映射對應屬性。

那么,如果遇到特殊情況如何處理呢?

名字不一致如何映射

如上面的例子中,在PersonDO中用name表示用戶名稱,而在PersonDTO中使用userName表示用戶名,那么如何進行參數映射呢。

這時候就要使用@Mapping注解了,只需要在方法簽名上,使用該注解,并指明需要轉換的源對象的名字和目標對象的名字就可以了,如將name的值映射給userName,可以使用如下方式: 

  1. @Mapping(source = "name"target = "userName"

可以自動映射的類型

除了名字不一致以外,還有一種特殊情況,那就是類型不一致,如上面的例子中,在PersonDO中用String類型表示用戶性別,而在PersonDTO中使用一個Genter的枚舉表示用戶性別。

這時候類型不一致,就需要涉及到互相轉換的問題

其實,MapStruct會對部分類型自動做映射,不需要我們做額外配置,如例子中我們將String類型自動轉成了枚舉類型。

一般情況下,對于以下情況可以做自動類型轉換:

  •  基本類型及其他們對應的包裝類型。
  •  基本類型的包裝類型和String類型之間
  •  String類型和枚舉類型之間

自定義常量

如果我們在轉換映射過程中,想要給一些屬性定義一個固定的值,這個時候可以使用 constant 

  1. @Mapping(source = "name"constant = "hollis"

類型不一致的如何映射

還是上面的例子,如果我們需要在Person這個對象中增加家庭住址這個屬性,那么我們一般在PersonoDTO中會單獨定義一個HomeAddress類來表示家庭住址,而在Person類中,我們一般使用String類型表示家庭住址。

這就需要在HomeAddress和String之間使用JSON進行互相轉化,這種情況下,MapStruct也是可以支持的。 

  1. public class PersonDO {  
  2.     private String name;  
  3.     private String address;  
  4.  
  5. public class PersonDTO {  
  6.     private String userName;  
  7.     private HomeAddress address;  
  8.  
  9. @Mapper  
  10. interface PersonConverter {  
  11.     PersonConverter INSTANCE = Mappers.getMapper(PersonConverter.class);  
  12.     @Mapping(source = "userName"target = "name" 
  13.     @Mapping(target = "address",expression = "java(homeAddressToString(dto2do.getAddress()))" 
  14.     PersonDO dto2do(PersonDTO dto2do);  
  15.     default String homeAddressToString(HomeAddress address){  
  16.         return JSON.toJSONString(address);  
  17.     }  

我們只需要在PersonConverter中在定義一個方法(因為PersonConverter是一個接口,所以在JDK 1.8以后的版本中可以定義一個default方法),這個方法的作用就是將HomeAddress轉換成String類型。

default方法:Java 8 引入的新的語言特性,用關鍵字default來標注,被default所標注的方法,需要提供實現,而子類可以選擇實現或者不實現該方法

然后在dto2do方法上,通過以下注解方式即可實現類型的轉換: 

  1. @Mapping(target = "address",expression = "java(homeAddressToString(dto2do.getAddress()))"

上面這種是自定義的類型轉換,還有一些類型的轉換是MapStruct本身就支持的,如String和Date之間的轉換: 

  1. @Mapping(target = "birthday",dateFormat = "yyyy-MM-dd HH:mm:ss"

以上,簡單介紹了一些常用的字段映射的方法,也是我自己在工作中經常遇到的幾個場景,更多的情況大家可以查看官方的示例(https://github.com/mapstruct/mapstruct-examples)。

MapStruct的性能

前面說了這么多MapStruct的用法,可以看出MapStruct的使用還是比較簡單的,并且字段映射上面的功能很強大,那么他的性能到底怎么樣呢?

參考《為什么阿里巴巴禁止使用Apache Beanutils進行屬性的copy?》中的示例,我們對MapStruct進行性能測試。

分別執行1000、10000、100000、1000000次映射的耗時分別為:0ms、1ms、3ms、6ms。

可以看到,MapStruct的耗時相比較于其他幾款工具來說是非常短的。

那么,為什么MapStruct的性能可以這么好呢?

其實,MapStruct和其他幾類框架最大的區別就是:與其他映射框架相比,MapStruct在編譯時生成bean映射,這確保了高性能,可以提前將問題反饋出來,也使得開發人員可以徹底的錯誤檢查。

還記得前面我們在引入MapStruct的依賴的時候,特別在maven-compiler-plugin中增加了mapstruct-processor的支持嗎?

并且我們在代碼中使用了很多MapStruct提供的注解,這使得在編譯期,MapStruct就可以直接生成bean映射的代碼,相當于代替我們寫了很多setter和getter。

如我們在代碼中定義了以下一個Mapper: 

  1. @Mapper  
  2. interface PersonConverter {  
  3.     PersonConverter INSTANCE = Mappers.getMapper(PersonConverter.class);  
  4.     @Mapping(source = "userName"target = "name" 
  5.     @Mapping(target = "address",expression = "java(homeAddressToString(dto2do.getAddress()))" 
  6.     @Mapping(target = "birthday",dateFormat = "yyyy-MM-dd HH:mm:ss" 
  7.     PersonDO dto2do(PersonDTO dto2do);  
  8.     default String homeAddressToString(HomeAddress address){  
  9.         return JSON.toJSONString(address);  
  10.     }  

經過代碼編譯后,會自動生成一個PersonConverterImpl: 

  1. @Generated(  
  2.     value = "org.mapstruct.ap.MappingProcessor" 
  3.     date = "2020-08-09T12:58:41+0800" 
  4.     comments = "version: 1.3.1.Final, compiler: javac, environment: Java 1.8.0_181 (Oracle Corporation)"  
  5.  
  6. class PersonConverterImpl implements PersonConverter {  
  7.     @Override  
  8.     public PersonDO dto2do(PersonDTO dto2do) {  
  9.         if ( dto2do == null ) {  
  10.             return null;  
  11.         } 
  12.          PersonDO personDO = new PersonDO();  
  13.         personDO.setName( dto2do.getUserName() );  
  14.         if ( dto2do.getAge() != null ) {  
  15.             personDO.setAge( dto2do.getAge() );  
  16.         }  
  17.         if ( dto2do.getGender() != null ) {  
  18.             personDO.setGender( dto2do.getGender().name() ); 
  19.         }  
  20.         personDO.setAddress( homeAddressToString(dto2do.getAddress()) );  
  21.         return personDO;  
  22.     }  

在運行期,對于bean進行映射的時候,就會直接調用PersonConverterImpl的dto2do方法,這樣就沒有什么特殊的事情要做了,只是在內存中進行set和get就可以了。

所以,因為在編譯期做了很多事情,所以MapStruct在運行期的性能會很好,并且還有一個好處,那就是可以把問題的暴露提前到編譯期。

使得如果代碼中字段映射有問題,那么應用就會無法編譯,強制開發者要解決這個問題才行。

總結

本文介紹了一款Java中的字段映射工具類,MapStruct,他的用法比較簡單,并且功能非常完善,可以應付各種情況的字段映射。

并且因為他是編譯期就會生成真正的映射代碼,使得運行期的性能得到了大大的提升。

強烈推薦,真的很香!!! 

 

責任編輯:龐桂玉 來源: Hollis
相關推薦

2020-08-10 14:30:09

BeanUtils工具類MapStruct

2022-09-02 15:11:18

開發工具

2021-10-14 18:15:38

BeanUtils對象生成器

2024-03-11 08:21:49

2019-04-24 09:02:06

軟件互聯網工資

2023-05-16 07:35:29

2024-11-28 14:20:08

2023-09-08 07:23:52

2023-02-10 08:56:30

2021-09-06 14:05:57

工具自動映射

2025-08-26 02:25:00

2018-04-27 13:44:11

蘋果股價庫克

2024-01-08 08:44:06

2019-04-16 10:05:52

996公司互聯網

2021-02-23 09:50:42

PythonJSWeb SSH

2021-12-29 06:30:12

安全工具網絡安全CISO

2024-11-28 13:07:33

2020-04-24 08:23:23

開發在線工具前端

2020-06-27 09:01:53

Java包裝類編程語言

2021-04-21 10:36:47

StringBuildJava8StringJoine
點贊
收藏

51CTO技術棧公眾號

久久男人中文字幕资源站| 亚洲激情综合| 亚洲一级免费观看| 黄色片在线免费看| 天天操综合520| 久久综合色播五月| 精品一区二区三区国产| 手机看片久久| 亚洲三级在线免费| 中文字幕网站视频在线| 91碰在线视频| 只有这里有精品| 狠狠躁少妇一区二区三区| 亚洲午夜国产一区99re久久| 国模大尺度视频一区二区| 亚洲一区二区国产| 极品视频在线| 国产日韩欧美成人| 高清中文字幕在线| 欧洲精品在线观看| 国产精久久一区二区| 高清av一区二区| 不卡的国产精品| 欧美日韩国产成人在线91| 免费免费啪视频在线观看| 久久综合之合合综合久久| 亚洲欧美怡红院| 激情综合闲人网| 丝袜亚洲另类欧美| 日本男人操女人| 亚洲少妇在线| 欧美情侣性视频| 亚洲图色一区二区三区| 久久久精品在线观看| av成人综合| 国产精品一二区| 亚洲人人精品| 亚洲午夜精品福利| gogo大胆日本视频一区| eeuss鲁片一区| 欧美午夜精品一区二区三区| 在线视频中文字幕第一页| 亚洲九九九在线观看| 国产精品美女久久久久| 午夜精品免费视频| 在线电影一区二区| 亚洲成人蜜桃| 久久一二三国产| 国产污污在线观看| 欧美亚州韩日在线看免费版国语版| 在线视频观看国产| 一区二区三区美女xx视频| av日韩精品| 国产精品免费一区二区三区四区| 久久99精品国产麻豆婷婷| 午夜dv内射一区二区| 黑人狂躁日本妞一区二区三区 | 成人av在线影院| 亚洲污视频在线观看| 在线观看成人小视频| 性欧美videohd高精| 国产精品久久久久久久久久新婚 | 国产精品99精品久久免费| 午夜激情av在线| 91精品国产全国免费观看| 欧美aaaaaa| 国产富婆一区二区三区 | 亚洲国产中文字幕在线视频综合| 国产在线高清理伦片a| 久久久国产视频91| 亚洲人人精品| 手机在线看福利| 在线不卡的av| 三级小说欧洲区亚洲区| 国产精品夜夜夜爽张柏芝| 疯狂做受xxxx高潮欧美日本| 精品久久久网| 久久亚洲高清| 亚洲电影中文字幕在线观看| av有声小说一区二区三区| 成人精品一二区| 国产夜色精品一区二区av| 日本精品600av| 国产精品美女久久久免费| 国产精品亚洲一区二区三区妖精| 免费人成黄页在线观看忧物| 欧美黄色性视频| 精品一区二区三区久久| 三级无遮挡在线观看| 欧美日韩福利视频| 精品一区二区av| 日韩大片在线永久免费观看网站| 欧美日韩国产91| 激情五月婷婷综合| 第九色区av在线| 26uuu久久噜噜噜噜| 国产黄色精品视频| 在线看福利影| 国产精品区一区二区三含羞草| 专区另类欧美日韩| 国产a亚洲精品| 亚洲美女网站18| 欧美乱妇15p| 亚洲午夜精品一区二区国产| 成年网站免费| 欧美激情免费看| 成人av电影在线| 白浆视频在线观看| 日本视频精品一区| 欧美精品视频www在线观看| 欧美在线精品一区| 色网站在线免费观看| 国产精品久久久久久久久久尿| 欧美激情综合五月色丁香小说| 欧美v亚洲v综合v国产v仙踪林| 日本一本草久p| 亚洲福利在线看| 视频一区二区三区中文字幕| aaa日本高清在线播放免费观看| 91精品国产乱码久久久久久蜜臀| 久久久av毛片精品| 日本一区精品视频| 日韩免费毛片视频| 日韩中文字幕在线视频| 成人性视频免费网站| 久久久久伊人| 国产又黄又猛视频| 久久综合亚洲社区| 91丨porny丨中文| 日韩欧美中文在线观看| 国产男女在线观看| 欧美高清视频免费观看| 国产精品三级视频| 一个色免费成人影院| 特级全黄一级毛片| 91网免费观看| 欧美一级xxx| 久久99九九99精品| 成人黄色免费观看| 国产超碰在线播放| 国产精品第一区| 图片区小说区区亚洲影院| 欧美激情无毛| 成人短视频在线| 一区二区三区欧美成人| 一本大道久久加勒比香蕉| eeuss国产一区二区三区| 国产精品国产三级在线观看| 在线观看av网页| 国产精品爽爽ⅴa在线观看| 日韩欧美黄色动漫| 视频一区二区欧美| 欧美亚洲福利| 少妇一级淫免费播放| 国产免费一区二区三区在线能观看 | 国产在线播放一区| 日韩欧乱色一区二区三区在线| av免费中文字幕| 国产精品小说在线| 欧美日韩在线观看一区二区| 男男成人高潮片免费网站| 四虎成人精品一区二区免费网站| 成人黄色激情网站| 国产精品成人一区二区三区| 亚洲国产日韩欧美在线99| xf在线a精品一区二区视频网站| 牛牛视频精品一区二区不卡| 天堂在线中文字幕| 中文字幕精品—区二区日日骚| 操91在线视频| 亚洲成av人在线观看| 玖玖在线精品| 亚洲欧美日本国产| 成年人视频免费在线观看| 91网站在线观看免费| 久久久噜噜噜久久中文字免| 91电影在线观看| 99国产精品99久久久久久| 久久亚洲精品中文字幕蜜潮电影| 中文在线免费| 奇米777影视成人四色| 久久青青草原一区二区| 欧美日韩爱爱视频| 欧美熟乱第一页| 国产无一区二区| 亚洲精品韩国| 日本在线一区二区三区| 丁香婷婷在线观看| 国产又大又硬又粗| 超碰97在线播放| 久久这里只有精品视频首页| 在线国产电影不卡| 欧美国产成人精品| 久久精品日韩欧美| 亚洲另类av| 超碰这里只有精品| 91在线观看| 性网站在线免费观看| 青草视频在线观看视频| 99久久精品免费看国产一区二区三区 |