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

什么是樣板代碼

樣板代碼就是那些和主要邏輯無關(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;
    }

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

使用mapstruct的效果

先不說怎么用,咱們先看看效果,覺得有用,咱們?cè)偻驴?
首先,寫一個(gè)映射接口

@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的簡(jiǎn)單使用

引入依賴

<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)生新對(duì)象

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

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)會(huì)給復(fù)制.

編寫映射器:給對(duì)象填充值

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

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

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

原理

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

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

在編譯之后,會(huì)在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ì)是一個(gè)代碼生成器
相比使用反射的BeanUtils.copyProperties()而言,mapstruct的效率更高,代碼可追溯性也更好.
推薦大家使用.
更多用法請(qǐng)見官方文檔,十分詳細(xì)且易讀
https://mapstruct.org/documentation/reference-guide/

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容