如何優(yōu)雅的轉(zhuǎn)換對象

什么是樣板代碼

樣板代碼就是那些和主要邏輯無關(guān),卻又不得不寫的代碼.
比如一段常見的實(shí)體類映射代碼:

    public User toUser(UserAddr addr, UserInfo info) {
        User user = new User();
        user.setAddr( addr.getAddress() );
        user.setCountry( addr.getCountry() );
        user.setCity( addr.getCity() );
        user.setName( info.getNameCn() );
        user.setAge( info.getAge() );
        return user;
    }

我們想把某個對象的屬性賦值給另一個對象時,不可避免的要寫上一大堆get/set之類的操作.
就算使用BeanUtils.copyProperties()方法,也只能消除同名屬性的get/set操作.
那有沒有一種方法,可以完全消除這種樣板代碼呢?
有的.

使用mapstruct的效果

先不說怎么用,咱們先看看效果,覺得有用,咱們再往下看.
首先,寫一個映射接口

@Mapper(componentModel = "spring")
public interface UserDOMapper {
    @Mapping(source = "info.nameCn",target = "name")
    @Mapping(source = "addr.address",target = "addr")
    User toUser(UserAddr addr, UserInfo info);
}

然后就可以使用了

@Autowired
private UserDOMapper userDOMapper;
public User toUser(UserAddr addr, UserInfo info) {
    return userDOMapper.toUser(addr,info);
}
    

修改前后的toUser作用完全相同,這效果可還行?

mapstruct的簡單使用

引入依賴

<properties>
        <org.mapstruct.version>1.2.0.Final</org.mapstruct.version>
</properties>
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-jdk8</artifactId>
    <version>${org.mapstruct.version}</version>
</dependency>
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-processor</artifactId>
    <version>${org.mapstruct.version}</version>
</dependency>

編寫映射器:產(chǎn)生新對象

@Mapper(componentModel = "spring")
public interface UserDOMapper {
    @Mapping(source = "info.nameCn",target = "name")
    @Mapping(source = "addr.address",target = "addr")
    User toUser(UserAddr addr, UserInfo info);
}

如果是要產(chǎn)生新對象,可以按照如上寫法編寫映射器.
source表示數(shù)據(jù)來源,target表示要賦值的變量.
比如@Mapping(source = "addr.address",target = "addr")就表示,把入?yún)ddr的address變量的值,賦值給User中的addr變量.
看下UserAddr和User定義會更清楚些:

public class UserAddr {
    private String country;
    private String city;
    private String address;
    ...
}
public class User {
    private String name;
    private Integer age;
    private String country;
    private String city;
    private String addr;
    ...
}

如果是變量的名字和數(shù)據(jù)類型都相同,則不需要顯示的聲明映射關(guān)系,默認(rèn)會給復(fù)制.

編寫映射器:給對象填充值

如果是要給已存在的對象填充值,可以按照下面這樣寫:

    @Mapping(source = "addr.address",target = "addr")
    void fillUser(UserAddr addr,@MappingTarget User user);

@MappingTarget表示被填充的對象.
其他規(guī)則還是跟之前一樣

原理

看完了使用,咱們來看下mapstruct是怎么做到這些事的.
實(shí)際上,mapstruct是一個代碼生成器,在編譯項(xiàng)目的時候,它會為映射器生成實(shí)現(xiàn)類.
比如下面這個映射器:

@Mapper(componentModel = "spring")
public interface UserDOMapper {
    @Mapping(source = "info.nameCn",target = "name")
    @Mapping(source = "addr.address",target = "addr")
    User toUser(UserAddr addr, UserInfo info);
}

在編譯之后,會在target中生成如下實(shí)現(xiàn)類:

@Component
public class UserDOMapperImpl implements UserDOMapper {

    @Override
    public User toUser(UserAddr addr, UserInfo info) {
        if ( addr == null && info == null ) {
            return null;
        }

        User user = new User();

        if ( addr != null ) {
            user.setAddr( addr.getAddress() );
            user.setCountry( addr.getCountry() );
            user.setCity( addr.getCity() );
        }
        if ( info != null ) {
            user.setName( info.getNameCn() );
            user.setAge( info.getAge() );
        }

        return user;
    }
}

總結(jié)

本次向大家介紹了一種減少樣板代碼,提高開發(fā)效率的工具mapstruct
其本質(zhì)是一個代碼生成器
相比使用反射的BeanUtils.copyProperties()而言,mapstruct的效率更高,代碼可追溯性也更好.
推薦大家使用.
更多用法請見官方文檔,十分詳細(xì)且易讀
https://mapstruct.org/documentation/reference-guide/

系列文章總目錄:https://mp.weixin.qq.com/s/56JgXLArTAEDj1f3y4arLA

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末孙技,一起剝皮案震驚了整個濱河市屉符,隨后出現(xiàn)的幾起案子脆淹,更是在濱河造成了極大的恐慌戏罢,老刑警劉巖塘辅,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件挪蹭,死亡現(xiàn)場離奇詭異浓镜,居然都是意外死亡锭魔,警方通過查閱死者的電腦和手機(jī)蜕企,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進(jìn)店門咬荷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人轻掩,你說我怎么就攤上這事幸乒。” “怎么了唇牧?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵罕扎,是天一觀的道長。 經(jīng)常有香客問我丐重,道長腔召,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任扮惦,我火速辦了婚禮臀蛛,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘崖蜜。我一直安慰自己浊仆,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布豫领。 她就那樣靜靜地躺著抡柿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪等恐。 梳的紋絲不亂的頭發(fā)上洲劣,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天,我揣著相機(jī)與錄音鼠锈,去河邊找鬼闪檬。 笑死,一個胖子當(dāng)著我的面吹牛购笆,可吹牛的內(nèi)容都是我干的粗悯。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼同欠,長吁一口氣:“原來是場噩夢啊……” “哼样傍!你這毒婦竟也來了横缔?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤衫哥,失蹤者是張志新(化名)和其女友劉穎茎刚,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體撤逢,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡膛锭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蚊荣。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片初狰。...
    茶點(diǎn)故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖互例,靈堂內(nèi)的尸體忽然破棺而出奢入,到底是詐尸還是另有隱情,我是刑警寧澤媳叨,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布腥光,位于F島的核電站,受9級特大地震影響糊秆,放射性物質(zhì)發(fā)生泄漏武福。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一痘番、第九天 我趴在偏房一處隱蔽的房頂上張望艘儒。 院中可真熱鬧,春花似錦夫偶、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至逾礁,卻和暖如春说铃,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背嘹履。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工腻扇, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人砾嫉。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓幼苛,卻偏偏與公主長得像,于是被迫代替她去往敵國和親焕刮。 傳聞我的和親對象是個殘疾皇子舶沿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評論 2 355

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