【推薦一款實(shí)體類轉(zhuǎn)換工具 MapStruct蒜绽,性能強(qiáng)勁镶骗,簡單易上手 】

1.什么是MapStruct

1.1 JavaBean 的困擾

對于代碼中 JavaBean之間的轉(zhuǎn)換, 一直是困擾我很久的事情躲雅。在開發(fā)的時(shí)候我看到業(yè)務(wù)代碼之間有很多的 JavaBean 之間的相互轉(zhuǎn)化鼎姊, 非常的影響觀感,卻又不得不存在相赁。我后來想的一個(gè)辦法就是通過反射相寇,或者自己寫很多的轉(zhuǎn)換器。

第一種通過反射的方法確實(shí)比較方便钮科,但是現(xiàn)在無論是 BeanUtils, BeanCopier 等在使用反射的時(shí)候都會影響到性能唤衫。雖然我們可以進(jìn)行反射信息的緩存來提高性能。但是像這種的話绵脯,需要類型和名稱都一樣才會進(jìn)行映射战授,有很多時(shí)候,由于不同的團(tuán)隊(duì)之間使用的名詞不一樣桨嫁,還是需要很多的手動 set/get 等功能。

第二種的話就是會很浪費(fèi)時(shí)間份帐,而且在添加新的字段的時(shí)候也要進(jìn)行方法的修改璃吧。不過,由于不需要進(jìn)行反射废境,其性能是很高的畜挨。推薦:Java進(jìn)階視頻資源

1.2 MapStruct 帶來的改變

MapSturct 是一個(gè)生成類型安全筒繁,高性能且無依賴的 JavaBean 映射代碼的注解處理器(annotation processor)。

  • 注解處理器
  • 可以生成 JavaBean 之間那的映射代碼
  • 類型安全巴元,高性能毡咏,無依賴性

2.MapStruct 入門

2.1 添加依賴

2.2 po類

2.3 dto類

2.4 創(chuàng)建轉(zhuǎn)換接口

2.5 測試方法

2.6 運(yùn)行效果

2.7 查看編譯的class

底層通過自動取值賦值操作完成

3.MapStruct優(yōu)點(diǎn)分析

3.1 性能高

這是相對反射來說的,反射需要去讀取字節(jié)碼的內(nèi)容逮刨,花銷會比較大呕缭。而通過 MapStruct 來生成的代碼,其類似于人手寫修己。速度上可以得到保證恢总。

3.2 使用簡單

如果是完全映射的,使用起來肯定沒有反射簡單睬愤。用類似 BeanUtils 這些工具一條語句就搞定了片仿。但是,如果需要進(jìn)行特殊的匹配(特殊類型轉(zhuǎn)換尤辱,多對一轉(zhuǎn)換等)舷嗡,其相對來說也是比較簡單的。

基本上捆交,使用的時(shí)候疫蔓,我們只需要聲明一個(gè)接口,接口下寫對應(yīng)的方法可帽,就可以使用了娄涩。當(dāng)然,如果有特殊情況映跟,是需要額外處理的蓄拣。推薦:Java進(jìn)階視頻資源

3.3 代碼獨(dú)立

生成的代碼是對立的,沒有運(yùn)行時(shí)的依賴努隙。

3.4 易于 debug

在我們生成的代碼中球恤,我們可以輕易的進(jìn)行 debug。

4.MapStruct使用案例

4.1 屬性名稱相同

在實(shí)現(xiàn)類的時(shí)候荸镊,如果屬性名稱相同咽斧,則會進(jìn)行對應(yīng)的轉(zhuǎn)化。通過此種方式躬存,我們可以快速的編寫出轉(zhuǎn)換的方法张惹。(入門案例)

4.2 屬性名不相同

屬性名不相同,在需要進(jìn)行互相轉(zhuǎn)化的時(shí)候岭洲,則我們可以通過@Mapping 注解來進(jìn)行轉(zhuǎn)化宛逗。

  • source 需要轉(zhuǎn)換的對接,通常是入?yún)?/li>
  • target 轉(zhuǎn)換的對接盾剩,通常是出參
  • ignore 忽略雷激,默認(rèn)false不忽略替蔬,需要忽略設(shè)置為true
  • defaultValue 默認(rèn)值
  • expressions 可以通過表達(dá)式來構(gòu)造一些簡單的轉(zhuǎn)化關(guān)系。雖然設(shè)計(jì)的時(shí)候想兼容很多語言屎暇,不過目前只能寫Java代碼承桥。
@Mappings({
            @Mapping(source = "birthdate", target = "birth"),//屬性名不一致映射
            @Mapping(target = "birthformat", expression = "java(org.apache.commons.lang3.time.DateFormatUtils.format(person.getBirthdate(),\"yyyy-MM-dd HH:mm:ss\"))"),//自定義屬性通過java代碼映射
    })
public PersonVo PersonToPersonVo(Person person);

這里用到演示了如何使用TimeAndFormat對time和format操作,這里必須要指定需要使用的Java類的完整包名根悼,不然編譯的時(shí)候不知道你使用哪個(gè)Java類凶异,會報(bào)錯(cuò)。

4.3 轉(zhuǎn)換非基礎(chǔ)類型屬性

如果subUser與subUserDto字段名稱相同直接配置即可完成(對象類型番挺,包括list)

4.4 Mapper 中使用自定義的轉(zhuǎn)換

有時(shí)候唠帝,對于某些類型,無法通過代碼生成器的形式來進(jìn)行處理玄柏。那么襟衰, 就需要自定義的方法來進(jìn)行轉(zhuǎn)換。這時(shí)候粪摘,我們可以在接口(同一個(gè)接口瀑晒,后續(xù)還有調(diào)用別的 Mapper 的方法)中定義默認(rèn)方法(Java8及之后)。

只能存在一個(gè)default修飾的方法

4.5 多轉(zhuǎn)一

我們在實(shí)際的業(yè)務(wù)中少不了將多個(gè)對象轉(zhuǎn)換成一個(gè)的場景徘意。MapStruct 當(dāng)然也支持多轉(zhuǎn)一的操作苔悦。推薦:Java進(jìn)階視頻資源

4.5.1 遵循原則

  • 當(dāng)多個(gè)對象中, 有其中一個(gè)為 null椎咧, 則會直接返回 null
  • 如一對一轉(zhuǎn)換一樣玖详, 屬性通過名字來自動匹配。因此勤讽, 名稱和類型相同的不需要進(jìn)行特殊處理
  • 當(dāng)多個(gè)原對象中蟋座,有相同名字的屬性時(shí),需要通過 @Mapping 注解來具體的指定脚牍, 以免出現(xiàn)歧義(不指定會報(bào)錯(cuò))向臀。如上面的 name

屬性也可以直接從傳入的參數(shù)來賦值

4.6 更新 Bean 對象

有時(shí)候,我們不是想返回一個(gè)新的 Bean 對象诸狭,而是希望更新傳入對象的一些屬性券膀。這個(gè)在實(shí)際的時(shí)候也會經(jīng)常使用到。

4.7 map映射

4.8 多級嵌套

只需要在mapper接口中定義相關(guān)的類型轉(zhuǎn)換方法即可驯遇,list類型也適用

4.8.1 方式1

4.8.2 方式2

通過uses配置類型轉(zhuǎn)換

5.獲取 mapper

5.1 通過 Mapper 工廠獲取

我們都是通過 Mappers.getMapper(xxx.class) 的方式來進(jìn)行對應(yīng) Mapper 的獲取芹彬。此種方法為通過 Mapper 工廠獲取。

如果是此種方法叉庐,約定俗成的是在接口內(nèi)定義一個(gè)接口本身的實(shí)例 INSTANCE舒帮, 以方便獲取對應(yīng)的實(shí)例。

這樣在調(diào)用的時(shí)候,我們就不需要在重復(fù)的去實(shí)例化對象了会前。類似下面

Target target = SourceMapper.INSTANCE.source2target(source);

5.2 使用依賴注入

對于 Web 開發(fā),依賴注入應(yīng)該很熟悉匾竿。MapSturct 也支持使用依賴注入瓦宜,同時(shí)也推薦使用依賴注入。

@Mapper(componentModel = "spring")

5.3 依賴注入策略

可以選擇是通過構(gòu)造方法或者屬性注入岭妖,默認(rèn)是屬性注入临庇。

類似如此使用

@Mapper(componentModel = "cdi" injectionStrategy = InjectionStrategy.CONSTRUCTOR)

5.4 自定義類型轉(zhuǎn)換

有時(shí)候,在對象轉(zhuǎn)換的時(shí)候可能會出現(xiàn)這樣一個(gè)問題昵慌,就是源對象中的類型是Boolean類型假夺,而目標(biāo)對象類型是String類型,這種情況可以通過@Mapper的uses屬性來實(shí)現(xiàn):

要注意的是斋攀,如果使用了例如像spring這樣的環(huán)境已卷,Mapper引入uses類實(shí)例的方式將是自動注入,那么這個(gè)類也應(yīng)該納入Spring容器

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末淳蔼,一起剝皮案震驚了整個(gè)濱河市侧蘸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鹉梨,老刑警劉巖讳癌,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異存皂,居然都是意外死亡晌坤,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進(jìn)店門旦袋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來骤菠,“玉大人,你說我怎么就攤上這事猜憎∶湓酰” “怎么了?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵胰柑,是天一觀的道長截亦。 經(jīng)常有香客問我,道長柬讨,這世上最難降的妖魔是什么崩瓤? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮踩官,結(jié)果婚禮上却桶,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好颖系,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布嗅剖。 她就那樣靜靜地躺著,像睡著了一般嘁扼。 火紅的嫁衣襯著肌膚如雪信粮。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天趁啸,我揣著相機(jī)與錄音强缘,去河邊找鬼。 笑死不傅,一個(gè)胖子當(dāng)著我的面吹牛旅掂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播访娶,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼商虐,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了震肮?” 一聲冷哼從身側(cè)響起称龙,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎戳晌,沒想到半個(gè)月后鲫尊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡沦偎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年疫向,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片豪嚎。...
    茶點(diǎn)故事閱讀 38,622評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡搔驼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出侈询,到底是詐尸還是另有隱情舌涨,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布扔字,位于F島的核電站囊嘉,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏革为。R本人自食惡果不足惜扭粱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望震檩。 院中可真熱鬧琢蛤,春花似錦蜓堕、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至慕淡,卻和暖如春霜旧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背儡率。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留以清,地道東北人儿普。 一個(gè)月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像掷倔,于是被迫代替她去往敵國和親眉孩。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內(nèi)容