0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

對象轉(zhuǎn)換工具:MapStruct 庫

科技綠洲 ? 來源:Java技術(shù)指北 ? 作者:Java技術(shù)指北 ? 2023-10-08 14:39 ? 次閱讀

在我們?nèi)粘i_發(fā)的程序中,為了各層之間解耦,一般會定義不同的對象用來在不同層之間傳遞數(shù)據(jù),比如xxxDTO、xxxVO、xxxQO,當在不同層之間傳輸數(shù)據(jù)時,不可避免地經(jīng)常需要將這些對象進行相互轉(zhuǎn)換。

今天給大家介紹一個對象轉(zhuǎn)換工具MapStruct,代碼簡潔安全、性能高,強烈推薦。

MapStruct簡介

MapStruct是一個代碼生成器,它基于約定優(yōu)于配置,極大地簡化了Java Bean類型之間映射的實現(xiàn)。特點如下:

  1. 基于注解
  2. 在編譯期自動生成映射轉(zhuǎn)換代碼
  3. 類型安全、高性能、無依賴性、易于理解閱讀

MapStruct入門

1. 引入依賴

這里使用Gradle構(gòu)建

dependencies {
    implementation 'org.mapstruct:mapstruct:1.4.2.Final'
    annotationProcessor 'org.mapstruct:mapstruct-processor:1.4.2.Final'
}
2. 需要轉(zhuǎn)換的對象

創(chuàng)建兩個示例對象(e.g. 將Demo對象轉(zhuǎn)換為DemoDto對象)

/**
 * 源對象
 */
@Data
public class Demo {
    private Integer id;
    private String name;
}

/**
 * 目標對象
 */
@Data
public class DemoDto {
    private Integer id;
    private String name;
}
3. 創(chuàng)建轉(zhuǎn)換器

只需要創(chuàng)建一個轉(zhuǎn)換器接口類,并在類上添加 @Mapper 注解即可(官方示例推薦以 xxxMapper 格式命名轉(zhuǎn)換器名稱)

@Mapper
public interface DemoMapper {
    //使用Mappers工廠獲取DemoMapper實現(xiàn)類
    DemoMapper INSTANCE = Mappers.getMapper(DemoMapper.class);
    //定義接口方法,參數(shù)為來源對象,返回值為目標對象
    DemoDto toDemoDto(Demo demo);
}
4. 驗證
public static void main(String[] args) {
    Demo demo = new Demo();
    demo.setId(111);
    demo.setName("hello");

    DemoDto demoDto = DemoMapper.INSTANCE.toDemoDto(demo);

    System.out.println("目標對象demoDto為:" + demoDto);
    //輸出結(jié)果:目標對象demoDto為:DemoDto(id=111, name=hello)
}

測試結(jié)果如下:

目標對象demoDto為:DemoDto(id=111, name=hello)

達到了我們的預(yù)期結(jié)果。

5. 自動生成的實現(xiàn)類

為什么聲明一個接口就可以轉(zhuǎn)換對象呢?我們看一下MapStruct在編譯期間自動生成的實現(xiàn)類:

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2022-09-01T17:54:38+0800",
    comments = "version: 1.4.2.Final, compiler: IncrementalProcessingEnvironment from gradle-language-java-7.3.jar, environment: Java 1.8.0_231 (Oracle Corporation)"
)
public class DemoMapperImpl implements DemoMapper {

    @Override
    public DemoDto toDemoDto(Demo demo) {
        if ( demo == null ) {
            return null;
        }

        DemoDto demoDto = new DemoDto();

        demoDto.setId( demo.getId() );
        demoDto.setName( demo.getName() );

        return demoDto;
    }
}

可以看到,MapStruct幫我們將繁雜的代碼自動生成了,而且實現(xiàn)類中用的都是最基本的get、set方法,易于閱讀理解,轉(zhuǎn)換速度非???。

MapStruct進階

上面的例子只是小試牛刀,下面開始展示MapStruct的強大之處。

(限于篇幅,這里不展示自動生成的實現(xiàn)類和驗證結(jié)果,大家可自行測試)

場景1:屬性名稱不同、(基本)類型不同
  • 屬性名稱不同: 在方法上加上 @Mapping 注解,用來映射屬性
  • 屬性基本類型不同: 基本類型和String等類型會自動轉(zhuǎn)換

關(guān)鍵字:@Mapping注解

/**
 * 來源對象
 */
@Data
public class Demo {
    private Integer id;
    private String name;
}

/**
 * 目標對象
 */
@Data
public class DemoDto {
    private String id;
    private String fullname;
}

/**
 * 轉(zhuǎn)換器
 */
@Mapper
public interface DemoMapper {
    DemoMapper INSTANCE = Mappers.getMapper(DemoMapper.class);

    @Mapping(target = "fullname", source = "name")
    DemoDto toDemoDto(Demo demo);
}
場景2:統(tǒng)一映射不同類型

下面例子中,time1、time2、time3都會被轉(zhuǎn)換,具體說明看下面的注釋:

/**
 * 來源對象
 */
@Data
public class Demo {
    private Integer id;
    private String name;
    /**
     * time1、time2名稱相同,time3轉(zhuǎn)為time33
     * 這里的time1、time2、time33都是Date類型
     */
    private Date time1;
    private Date time2;
    private Date time3;
}

/**
 * 目標對象
 */
@Data
public class DemoDto {
    private String id;
    private String name;
    /**
     * 這里的time1、time2、time33都是String類型
     */
    private String time1;
    private String time2;
    private String time33;
}

/**
 * 轉(zhuǎn)換器
 */
@Mapper
public interface DemoMapper {
    DemoMapper INSTANCE = Mappers.getMapper(DemoMapper.class);

    @Mapping(target = "time33", source = "time3")
    DemoDto toDemoDto(Demo demo);
    
    //MapStruct會將所有匹配到的:
    //源類型為Date、目標類型為String的屬性,
    //按以下方法進行轉(zhuǎn)換
    static String date2String(Date date) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String strDate = simpleDateFormat.format(date);
        return strDate;
    }
}
場景3:固定值、忽略某個屬性、時間轉(zhuǎn)字符串格式

一個例子演示三種用法,具體說明看注釋,很容易理解:

關(guān)鍵字:ignore、constant、dateFormat

/**
 * 來源對象
 */
@Data
public class Demo {
    private Integer id;
    private String name;
    private Date time;
}

/**
 * 目標對象
 */
@Data
public class DemoDto {
    private String id;
    private String name;
    private String time;
}

/**
 * 轉(zhuǎn)換器
 */
@Mapper
public interface DemoMapper {
    DemoMapper INSTANCE = Mappers.getMapper(DemoMapper.class);

    //id屬性不賦值
    @Mapping(target = "id", ignore = true)
    //name屬性固定賦值為“hello”
    @Mapping(target = "name", constant = "hello")
    //time屬性轉(zhuǎn)為yyyy-MM-dd HH:mm:ss格式的字符串
    @Mapping(target = "time", dateFormat = "yyyy-MM-dd HH:mm:ss")
    DemoDto toDemoDto(Demo demo);
}
場景4:為某個屬性指定轉(zhuǎn)換方法

場景2中,我們是按照某個轉(zhuǎn)換方法,統(tǒng)一將一種類型轉(zhuǎn)換為另外一種類型;而下面這個例子,是為某個屬性指定方法:

關(guān)鍵字:@Named注解、qualifiedByName

/**
 * 來源對象
 */
@Data
public class Demo {
    private Integer id;
    private String name;
}

/**
 * 目標對象
 */
@Data
public class DemoDto {
    private String id;
    private String name;
}

/**
 * 轉(zhuǎn)換器
 */
@Mapper
public interface DemoMapper {
    DemoMapper INSTANCE = Mappers.getMapper(DemoMapper.class);

    //為name屬性指定@Named為convertName的方法進行轉(zhuǎn)換
    @Mapping(target = "name", qualifiedByName = "convertName")
    DemoDto toDemoDto(Demo demo);

    @Named("convertName")
    static String aaa(String name) {
        return "姓名為:" + name;
    }
}
場景5:多個參數(shù)合并為一個對象

如果參數(shù)為多個的話,@Mapping注解中的source就要指定是哪個參數(shù)了,用點分隔:

關(guān)鍵字:點(.)

/**
 * 來源對象
 */
@Data
public class Demo {
    private Integer id;
    private String name;
}

/**
 * 目標對象
 */
@Data
public class DemoDto {
    private String fullname;
    private String timestamp;
}

/**
 * 轉(zhuǎn)換器
 */
@Mapper
public interface DemoMapper {
    DemoMapper INSTANCE = Mappers.getMapper(DemoMapper.class);

    //fullname屬性賦值demo對象的name屬性(注意這里.的用法)
    //timestamp屬性賦值為傳入的time參數(shù)
    @Mapping(target = "fullname", source = "demo.name")
    @Mapping(target = "timestamp", source = "time")
    DemoDto toDemoDto(Demo demo, String time);
}
場景6:已有目標對象,將源對象屬性覆蓋到目標對象

覆蓋目標對象屬性時,一般null值不覆蓋,所以需要在類上的@Mapper注解中添加屬性:nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE 代表null值不進行賦值。

關(guān)鍵字:@MappingTarget注解、nullValuePropertyMappingStrategy

/**
 * 來源對象
 */
@Data
public class Demo {
    private Integer id;
    private String name;
}

/**
 * 目標對象
 */
@Data
public class DemoDto {
    private String id;
    private String name;
}

/**
 * 轉(zhuǎn)換器
 */
@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE,
        nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
public interface DemoMapper {
    DemoMapper INSTANCE = Mappers.getMapper(DemoMapper.class);

    //將已有的目標對象當作一個參數(shù)傳進來
    DemoDto toDemoDto(Demo demo, @MappingTarget DemoDto dto);
}
場景7:源對象兩個屬性合并為一個屬性

這種情況可以使用@AfterMapping注解。

關(guān)鍵字:@AfterMapping注解、@MappingTarget注解

/**
 * 來源對象
 */
@Data
public class Demo {
    private Integer id;
    private String firstName;
    private String lastName;
}

/**
 * 目標對象
 */
@Data
public class DemoDto {
    private String id;
    private String name;
}

/**
 * 轉(zhuǎn)換器
 */
@Mapper
public interface DemoMapper {
    DemoMapper INSTANCE = Mappers.getMapper(DemoMapper.class);

    DemoDto toDemoDto(Demo demo);

    //在轉(zhuǎn)換完成后執(zhí)行的方法,一般用到源對象兩個屬性合并為一個屬性的場景
    //需要將源對象、目標對象(@MappingTarget)都作為參數(shù)傳進來,
    @AfterMapping
    static void afterToDemoDto(Demo demo, @MappingTarget DemoDto demoDto) {
        String name = demo.getFirstName() + demo.getLastName();
        demoDto.setName(name);
    }
}

小結(jié)

本文介紹了對象轉(zhuǎn)換工具 MapStruct 庫,以安全、簡潔、優(yōu)雅的方式來優(yōu)化我們的轉(zhuǎn)換代碼。

從文中的示例場景中可以看出,MapStruct 提供了大量的功能和配置,使我們可以快捷的創(chuàng)建出各種或簡單或復(fù)雜的映射器。而這些,也只是 MapStruct 庫的冰山一角,還有很多強大的功能文中沒有提到,感興趣的朋友可以自行查看官方文檔。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 對象
    +關(guān)注

    關(guān)注

    1

    文章

    38

    瀏覽量

    17368
  • 傳輸數(shù)據(jù)
    +關(guān)注

    關(guān)注

    1

    文章

    110

    瀏覽量

    16081
  • 代碼生成器
    +關(guān)注

    關(guān)注

    0

    文章

    25

    瀏覽量

    9080
收藏 人收藏

    評論

    相關(guān)推薦

    原理圖格式轉(zhuǎn)換工具

    現(xiàn)在正在做一個格式轉(zhuǎn)換工具,大家有什么好的建議和思路沒有呢,也就是可以protel的格式,orcad等原理圖,格式的互相轉(zhuǎn)換.
    發(fā)表于 06-17 14:08

    高質(zhì)量PDF轉(zhuǎn)換工具

    PDF文件轉(zhuǎn)換王PDF文件轉(zhuǎn)換王V1.79綠色特別版(高質(zhì)量PDF轉(zhuǎn)換工具)下載介紹:
    發(fā)表于 06-10 09:24 ?0次下載

    TKStudio 文件捆綁轉(zhuǎn)換工具

    TKStudio 文件捆綁轉(zhuǎn)換工具介紹
    發(fā)表于 07-19 15:51 ?65次下載

    PCB圖片轉(zhuǎn)換工具

    電子發(fā)燒友網(wǎng)站提供《PCB圖片轉(zhuǎn)換工具.rar》資料免費下載
    發(fā)表于 06-18 16:42 ?32次下載

    pcb單位轉(zhuǎn)換工具下載

    資料介紹說明: 軟件名稱 :pcb轉(zhuǎn)換工具 文件大小:2.03MB 文件格式:rar 軟件語言:簡體中文 運行環(huán)境: win2003winxpwin2000win9x pcb單位轉(zhuǎn)換工具,pcb工程專用工具,方便在設(shè)計過程
    發(fā)表于 11-05 09:40 ?47次下載
    pcb單位<b class='flag-5'>轉(zhuǎn)換工具</b>下載

    LCD彩色圖片轉(zhuǎn)換工具

    電子發(fā)燒友網(wǎng)站提供《LCD彩色圖片轉(zhuǎn)換工具.exe》資料免費下載
    發(fā)表于 06-16 15:17 ?2次下載

    IPTV版遙控轉(zhuǎn)換工具

    IPTV版遙控轉(zhuǎn)換工具根據(jù)說明自己看,不明白的找度娘。
    發(fā)表于 05-03 15:15 ?0次下載

    進制轉(zhuǎn)換工具

    進制轉(zhuǎn)換工具
    發(fā)表于 12-01 16:44 ?3次下載

    LCD彩色圖片轉(zhuǎn)換工具BMP_to_H

    LCD彩色圖片轉(zhuǎn)換工具BMP_to_H
    發(fā)表于 12-28 10:16 ?11次下載

    protel-pads轉(zhuǎn)換工具

    protel-pads轉(zhuǎn)換工具
    發(fā)表于 02-14 17:25 ?0次下載

    ASCII碼轉(zhuǎn)換工具下載

    數(shù)據(jù)轉(zhuǎn)換工具
    發(fā)表于 06-09 15:03 ?6次下載

    C浮點數(shù)與字符轉(zhuǎn)換工具

    C浮點數(shù)與字符轉(zhuǎn)換工具免費下載。
    發(fā)表于 06-19 18:17 ?0次下載

    xgus轉(zhuǎn)換工具

    xgus轉(zhuǎn)換工具
    發(fā)表于 04-28 13:52 ?2次下載

    視頻格式轉(zhuǎn)換工具

    視頻格式轉(zhuǎn)換工具
    發(fā)表于 04-28 13:58 ?1次下載

    音頻格式轉(zhuǎn)換工具

    音頻格式轉(zhuǎn)換工具
    發(fā)表于 04-28 13:59 ?6次下載