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

Java MapStruct解了對(duì)象映射的毒

 更新時(shí)間:2021年04月23日 11:44:17   作者:JaJian  
這篇文章主要介紹了MapStruct解了對(duì)象映射的毒,對(duì)MapStruct感興趣的同學(xué),可以參考下

前言

MVC模式是目前主流項(xiàng)目的標(biāo)準(zhǔn)開(kāi)發(fā)模式,這種模式下框架的分層結(jié)構(gòu)清晰,主要分為Controller,Service,Dao。分層的結(jié)構(gòu)下,各層之間的數(shù)據(jù)傳輸要求就會(huì)存在差異,我們不能用一個(gè)對(duì)象來(lái)貫穿3層,這樣不符合開(kāi)發(fā)規(guī)范且不夠靈活。

我們常常會(huì)遇到層級(jí)之間字段格式需求不一致的情況,例如數(shù)據(jù)庫(kù)中某個(gè)字段是datetime日期格式,這個(gè)時(shí)間戳在數(shù)據(jù)庫(kù)中的存儲(chǔ)值為2020-11-06 23:59:59.999999,但是傳遞給前端的時(shí)候要求接口返回yyyy-MM-dd的格式,或者有些數(shù)據(jù)在數(shù)據(jù)庫(kù)中是逗號(hào)拼接的String類(lèi)型,但是前端需要的是切割后的List類(lèi)型等等。

所以我們提出了層級(jí)間的對(duì)象模型,就是我們常見(jiàn)的VO,DTO,DO,PO等等。這種區(qū)分層級(jí)對(duì)象模型的方式雖然清晰化了我們各層級(jí)間的對(duì)象傳遞,但是對(duì)象模型間的相互轉(zhuǎn)換和值拷貝確是讓人感覺(jué)很麻煩,拷貝來(lái)拷貝去,來(lái)來(lái)回回,過(guò)程重復(fù)乏味,編寫(xiě)此類(lèi)映射代碼是一項(xiàng)繁瑣且容易出錯(cuò)的任務(wù)。

最簡(jiǎn)單粗糙的拷貝方法就是不斷的new對(duì)象然后對(duì)象間的 setter 和 getter,這種方式應(yīng)對(duì)字段屬性少的還可以,如果屬性字段很多那么大段的set,get的代碼就顯得很不雅美。因此需要借助對(duì)象拷貝工具,目前市場(chǎng)上的也蠻多的像BeanCopy,Dozer等等,但是這些我感覺(jué)都不夠好,今天我推薦一個(gè)實(shí)體映射工具就是 MapStruct。

介紹

MapStruct的官網(wǎng)地址是 https://mapstruct.org/MapStruct,是一個(gè)快速安全的bean 映射代碼生成器,只需要通過(guò)簡(jiǎn)單的注解就可以實(shí)現(xiàn)對(duì)象間的屬性轉(zhuǎn)換,是一款 Apache LICENSE 2.0 授權(quán)的開(kāi)源產(chǎn)品,Github的源碼地址是 https://github.com/mapstruct。

通過(guò)官網(wǎng)的三連問(wèn)(What,Why,How)我們可以大概的了解到 MapStruct 的作用,它的優(yōu)勢(shì)以及它是如何實(shí)現(xiàn)的。

從上面的三連問(wèn)中我們可以得到如下信息:

  • 基于約定優(yōu)于配置的方法 MapStruct 極大地簡(jiǎn)化了 Java bean 類(lèi)型之間的映射的實(shí)現(xiàn),通過(guò)簡(jiǎn)單的注解就可以工作。生成的映射代碼使用普通的方法調(diào)用而不是反射,因此速度快,類(lèi)型安全且易于理解。
  • 在編譯時(shí)生成 Bean 映射 與其他映射框架相比,MapStruct 在編譯時(shí)生成 Bean 映射,這樣可以確保高性能,而且開(kāi)發(fā)人員可以快速的得到反饋和徹底的錯(cuò)誤檢查。
  • 一個(gè)注釋處理器 MapStruct 是一個(gè)注釋處理器,已插入 Java 編譯器,可用于命令行構(gòu)建(Maven,Gradle等),也可用于您首選的IDE中(IDEA,Eclipse等)。

代碼編寫(xiě)

MapStruct 需要 Java 1.8或更高版本。對(duì)于Maven-based 的項(xiàng)目,在pom 文件中添加如下依賴(lài)即可

<!-- 指定版本-->
<properties>
    <org.mapstruct.version>1.4.1.Final</org.mapstruct.version>
</properties>
<!-- 添加依賴(lài) -->
<dependencies>
   <dependency>
	<groupId>org.mapstruct</groupId>
	<artifactId>mapstruct</artifactId>
	<version>${org.mapstruct.version}</version>
   </dependency>
   <dependency>
	<groupId>org.mapstruct</groupId>
	<artifactId>mapstruct-processor</artifactId>
	<version>${org.mapstruct.version}</version>
   </dependency>
</dependencies>

基本的依賴(lài)引入后就可以編寫(xiě)代碼了,簡(jiǎn)單的定義一個(gè)映射類(lèi),為了與 Mybatis中的 mapper 接口區(qū)分,我們可以取名為 xxObjectConverter。

例如汽車(chē)對(duì)象的映射類(lèi)名為 CarObjectConverter,我們有兩個(gè)對(duì)象模型 DO 和 DTO,它們內(nèi)部的屬性字段如下:

數(shù)據(jù)庫(kù)對(duì)應(yīng)的持久化對(duì)象模型 CarDo

public class Car {
    @ApiModelProperty(value = "主鍵id")
    private Long id;
	
    @ApiModelProperty(value = "制造商")
    private String manufacturers;
	
    @ApiModelProperty(value = "銷(xiāo)售渠道")
    private String saleChannel;

    @ApiModelProperty(value = "生產(chǎn)日期")
    private Date productionDate;
    ...
}

層級(jí)間傳輸?shù)膶?duì)象模型 CarDto

public class CarDto {
    @ApiModelProperty(value = "主鍵id")
    private Long id;
	
    @ApiModelProperty(value = "制造商")
    private String maker;
	
    @ApiModelProperty(value = "銷(xiāo)售渠道")
    private List<Integer> saleChannel;

    @ApiModelProperty(value = "生產(chǎn)日期")
    private Date productionDate;
    ...
}

再編寫(xiě)具體的 MapStruct 對(duì)象映射器

@Mapper
public interface CarObjectConverter{

    CarObjectConverter INSTANCE = Mappers.getMapper(CarObjectConverter.class);

    @Mapping(target = "maker", source = "manufacturers")
    CarDto carToCarDto(Car car);

}

對(duì)于字段名相同的可以不用額外的指定映射規(guī)則,但是字段名不同的屬性則需要指出字段的映射規(guī)則,如上我們持久層 DO 的制造商的字段名是manufacturers 而層級(jí)間傳輸?shù)腄TO模型中則是maker,我們就需要在映射方法上通過(guò)@Mapping注解指出映射規(guī)則,我個(gè)人習(xí)慣是喜歡將target寫(xiě)在前面,source寫(xiě)在后面,這樣是與映射對(duì)象的位置保持一致,差異字段多的時(shí)候方便對(duì)比且不易混淆。

開(kāi)發(fā)過(guò)程中還會(huì)經(jīng)常遇到一些日期格式的轉(zhuǎn)換,就如開(kāi)篇時(shí)說(shuō)的那種,這時(shí)我們也可以指定日期的映射規(guī)則

@Mapper
public interface CarObjectConverter{

    CarObjectConverter INSTANCE = Mappers.getMapper(CarObjectConverter.class);

    @Mapping(target = "maker", source = "manufacturers")
    @Mapping(target = "productionDate", dateFormat = "yyyy-MM-dd", source = "productionDate")
    CarDto carToCarDto(Car car);

}

這些都還是一些簡(jiǎn)單的字段的映射,但有時(shí)候我們兩個(gè)對(duì)象模型間的字段類(lèi)型不一致,如上汽車(chē)的銷(xiāo)售渠道字段saleChannel,這個(gè)在數(shù)據(jù)庫(kù)中是字符串逗號(hào)拼接的值1,2,3,而我們傳遞出去的需要是 List 的 Integer 類(lèi)型,這種復(fù)雜的如何映射呢?

也是有方法的,我們先編寫(xiě)一個(gè)將字符串逗號(hào)分隔然后轉(zhuǎn)成 List 的工具方法,如下

public class CollectionUtils {

    public static List<Integer> list2String(String str) {
        if (StringUtils.isNoneBlank(str)) {
            return Arrays.asList(str.split(",")).stream().map(s -> Integer.valueOf(s.trim())).collect(Collectors.toList());
        }
        return null;
    }
}

然后在映射Mapping中使用表達(dá)式即可

@Mapper
public interface CarObjectConverter {

    CarObjectConverter INSTANCE = Mappers.getMapper(CarObjectConverter.class);

    @Mapping(target = "maker", source = "manufacturers")
    @Mapping(target = "productionDate", dateFormat = "yyyy-MM-dd", source = "productionDate")
    @Mapping(target = "saleChannel", expression = "java(com.jiajian.demo.utils.CollectionUtils.list2String(car.getSaleChannel()))")
    CarDto carToCarDto(Car car);

}

這樣就完成了所有字段的映射工作,我們?cè)谛枰獙?duì)象模型轉(zhuǎn)換的地方按照如下方式調(diào)用即可

CarDto carDto = CarObjectConverter.INSTANCE.carToCarDto(car);

這種是單體對(duì)象之間的 Copy 很多時(shí)候我們需要 List 對(duì)象模型間的轉(zhuǎn)換,只需要再寫(xiě)一個(gè)方法carToCarDtos即可

@Mapper
public interface CarObjectConverter{

    CarObjectConverter INSTANCE = Mappers.getMapper(CarObjectConverter.class);

    @Mapping(target = "maker", source = "manufacturers")
    @Mapping(target = "productionDate", dateFormat = "yyyy-MM-dd", source = "productionDate")
    @Mapping(target ="saleChannel", expression = "java(com.jiajian.demo.utils.CollectionUtils.list2String(car.getSaleChannel()))")
    CarDto carToCarDto(Car car);

    List<CarDto> carToCarDtos(List<Car> carList);

}

探個(gè)究竟

會(huì)不會(huì)好奇這是怎么實(shí)現(xiàn)的,我們只是創(chuàng)建了一個(gè)接口然后在接口方法上加一個(gè)注解并在注解里面指定字段的映射規(guī)則就可以實(shí)現(xiàn)對(duì)象屬性間的拷貝,這是怎么做到的呢?

我們這里通過(guò) MapStruct 創(chuàng)建的只是一個(gè)接口,要實(shí)現(xiàn)具體的功能接口必有實(shí)現(xiàn)。

MapStruct 會(huì)在我們代碼編譯的時(shí)候?yàn)槲覀儎?chuàng)建一個(gè)實(shí)現(xiàn)類(lèi),而這個(gè)實(shí)現(xiàn)類(lèi)里面通過(guò)字段的setter, getter方法來(lái)實(shí)現(xiàn)字段的賦值,從而實(shí)現(xiàn)對(duì)象的映射。

這里需要注意一點(diǎn):如果你修改了任一映射對(duì)象,記得需要先執(zhí)行mvn clean再啟動(dòng)項(xiàng)目,否則調(diào)試的時(shí)候會(huì)報(bào)錯(cuò)。

結(jié)尾

MapStrut 的功能遠(yuǎn)不至于上面介紹的這些,我只是挑出幾個(gè)常用的語(yǔ)法進(jìn)行示例講解,如果讀者感興趣想深入的了解更多可以參考官方的參考文檔

遇見(jiàn) MapStruct 后我就開(kāi)始在項(xiàng)目中拋棄掉了原來(lái)的那些 BeanCopyUtils 的工具,相對(duì)而言 MapStruct 確實(shí)更簡(jiǎn)潔且易使用而且定制功能也很強(qiáng)。

從編譯文件可以看出 MapStruct 是通過(guò)setter,getter來(lái)實(shí)現(xiàn)屬性值的拷貝,然后這種方式不是最簡(jiǎn)單又最安全高效的嗎?只是 MapStruct 更好的幫助我們實(shí)現(xiàn)了,避免了項(xiàng)目中冗余的重復(fù)代碼,大道至簡(jiǎn)。

以上就是MapStruct解了對(duì)象映射的毒的詳細(xì)內(nèi)容,更多關(guān)于MapStruct的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java ScheduledExecutorService的具體使用

    Java ScheduledExecutorService的具體使用

    ScheduledExecutorService有線程池的特性,也可以實(shí)現(xiàn)任務(wù)循環(huán)執(zhí)行,本文主要介紹了Java ScheduledExecutorService的具體使用,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-05-05
  • Java導(dǎo)出Execl疑難點(diǎn)處理的實(shí)現(xiàn)

    Java導(dǎo)出Execl疑難點(diǎn)處理的實(shí)現(xiàn)

    這篇文章主要介紹了Java導(dǎo)出Execl疑難點(diǎn)處理的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • 使用Kubernetes和Docker部署Java微服務(wù)詳細(xì)代碼

    使用Kubernetes和Docker部署Java微服務(wù)詳細(xì)代碼

    Java微服務(wù)項(xiàng)目是一種基于Java技術(shù)棧的分布式系統(tǒng)開(kāi)發(fā)方式,下面這篇文章主要給大家介紹了關(guān)于使用Kubernetes和Docker部署Java微服務(wù)的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-07-07
  • 基于Spring Boot不同的環(huán)境使用不同的配置方法

    基于Spring Boot不同的環(huán)境使用不同的配置方法

    下面小編就為大家分享一篇基于Spring Boot不同的環(huán)境使用不同的配置方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01
  • 每日六道java新手入門(mén)面試題,通往自由的道路--多線程

    每日六道java新手入門(mén)面試題,通往自由的道路--多線程

    這篇文章主要為大家分享了最有價(jià)值的6道多線程面試題,涵蓋內(nèi)容全面,包括數(shù)據(jù)結(jié)構(gòu)和算法相關(guān)的題目、經(jīng)典面試編程題等,對(duì)hashCode方法的設(shè)計(jì)、垃圾收集的堆和代進(jìn)行剖析,感興趣的小伙伴們可以參考一下
    2021-06-06
  • Java中什么是類(lèi)加載及類(lèi)加載的過(guò)程

    Java中什么是類(lèi)加載及類(lèi)加載的過(guò)程

    Java類(lèi)加載是JVM將類(lèi)文件加載至內(nèi)存,分加載、連接(驗(yàn)證/準(zhǔn)備/解析)和初始化三階段,本文給大家介紹Java中什么是類(lèi)加載及類(lèi)加載的過(guò)程,感興趣的朋友一起看看吧
    2025-06-06
  • 關(guān)于springboot-starter-undertow和tomcat的區(qū)別說(shuō)明

    關(guān)于springboot-starter-undertow和tomcat的區(qū)別說(shuō)明

    這篇文章主要介紹了關(guān)于springboot-starter-undertow和tomcat的區(qū)別說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java線程三種命名方法詳解

    Java線程三種命名方法詳解

    這篇文章主要介紹了Java線程三種命名方法詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • TransactionSynchronization的invokeAfterCompletion事務(wù)源碼解析

    TransactionSynchronization的invokeAfterCompletion事務(wù)源碼解析

    這篇文章主要為大家介紹了TransactionSynchronization的invokeAfterCompletion事務(wù)源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • 使用ElasticSearch6.0快速實(shí)現(xiàn)全文搜索功能的示例代碼

    使用ElasticSearch6.0快速實(shí)現(xiàn)全文搜索功能的示例代碼

    本篇文章主要介紹了使用ElasticSearch6.0快速實(shí)現(xiàn)全文搜索功能,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-02-02

最新評(píng)論