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

詳解Java中的mapstruct插件使用

 更新時(shí)間:2022年04月06日 10:35:48   作者:淼淼之森  
mapstruct 的插件是專(zhuān)門(mén)用來(lái)處理 domin 實(shí)體類(lèi)與 model 類(lèi)的屬性映射的,我們只需定義 mapper 接口,mapstruct 在編譯的時(shí)候就會(huì)自動(dòng)的幫我們實(shí)現(xiàn)這個(gè)映射接口,避免了麻煩復(fù)雜的映射實(shí)現(xiàn),對(duì)Java?mapstruct使用相關(guān)知識(shí)感興趣的朋友一起看看吧

實(shí)體類(lèi)的屬性映射怎么可以少了它?

我們都知道,隨著一個(gè)工程的越來(lái)越成熟,模塊劃分會(huì)越來(lái)越細(xì),其中實(shí)體類(lèi)一般存于 domain 之中,但 domain 工程最好不要被其他工程依賴(lài),所以其他工程想獲取實(shí)體類(lèi)數(shù)據(jù)時(shí)就需要在各自工程寫(xiě) model,自定義 model 可以根據(jù)自身業(yè)務(wù)需要映射相應(yīng)的實(shí)體屬性。這樣一來(lái),這個(gè)映射工程貌似并不簡(jiǎn)單了。阿森差點(diǎn)就犯難了……

所以阿淼今天就要給大家安利一款叫 mapstruct 的插件,它就是專(zhuān)門(mén)用來(lái)處理 domin 實(shí)體類(lèi)與 model 類(lèi)的屬性映射的,我們只需定義 mapper 接口,mapstruct 在編譯的時(shí)候就會(huì)自動(dòng)的幫我們實(shí)現(xiàn)這個(gè)映射接口,避免了麻煩復(fù)雜的映射實(shí)現(xiàn)。

那可能有的小伙伴就要問(wèn)了?為啥不用 BeanUtilscopyProperties 方法呢?不也照樣可以實(shí)現(xiàn)屬性的映射么?

這個(gè)啊,阿淼我開(kāi)始也是好奇,所以就和 BeanUtils 深入交流了一番,最后才發(fā)現(xiàn),BeanUtils 就是一個(gè)大老粗,只能同屬性映射,或者在屬性相同的情況下,允許被映射的對(duì)象屬性少;但當(dāng)遇到被映射的屬性數(shù)據(jù)類(lèi)型被修改或者被映射的字段名被修改,則會(huì)導(dǎo)致映射失敗。而 mapstruct 就是一個(gè)巧媳婦兒了,她心思細(xì)膩,把我們可能會(huì)遇到的情況都給考慮到了(要是阿淼我也能找一個(gè)這樣的媳婦兒該多好,內(nèi)心笑出了豬聲)

如下是這個(gè)插件的開(kāi)源項(xiàng)目地址和各種例子:

一、準(zhǔn)備工作

接下來(lái),阿淼將和大家一起去解開(kāi)這個(gè)巧媳婦兒的真正面紗,所以我們還需要做一點(diǎn)準(zhǔn)備工作。

1.1、了解@Mapper 注解

從 mybatis3.4.0 開(kāi)始加入的 @Mapper 注解,目的就是為了不再寫(xiě)mapper映射文件。

我們只需要在 dao 層定義的接口上使用注解就可以實(shí)現(xiàn)sql語(yǔ)句的編寫(xiě),例如:

@Select("select * from user where name = #{name}")
public User find(String name);

如上就是一個(gè)簡(jiǎn)單的使用,雖然簡(jiǎn)單,但也確實(shí)體現(xiàn)出了這個(gè)注解的優(yōu)越性,至少少寫(xiě)了一個(gè)xml文件。

但阿淼我今天可不是想跟你探討 @Mapper 注解,我主要是想去看我的巧媳婦兒 mapstruct ,所以我就只是想說(shuō)下 @Mapper 注解的 componentModel 屬性,componentModel 屬性用于指定自動(dòng)生成的接口實(shí)現(xiàn)類(lèi)的組件類(lèi)型,這個(gè)屬性支持四個(gè)值:

 

  • default: 這是默認(rèn)的情況,mapstruct 不使用任何組件類(lèi)型, 可以通過(guò)Mappers.getMapper(Class)方式獲取自動(dòng)生成的實(shí)例對(duì)象。
  • cdi: the generated mapper is an application-scoped CDI bean and can be retrieved via @Inject
  • spring: 生成的實(shí)現(xiàn)類(lèi)上面會(huì)自動(dòng)添加一個(gè)@Component注解,可以通過(guò)Spring的 @Autowired方式進(jìn)行注入
  • jsr330: 生成的實(shí)現(xiàn)類(lèi)上會(huì)添加@javax.inject.Named 和@Singleton注解,可以通過(guò) @Inject注解獲取

1.2、依賴(lài)包

首先需要把依賴(lài)包導(dǎo)入,主要由兩個(gè)包組成:

  • org.mapstruct:mapstruct:包含了一些必要的注解,例如@Mapping。r若我們使用的JDK版本高于1.8,當(dāng)我們?cè)趐om里面導(dǎo)入依賴(lài)時(shí)候,建議使用坐標(biāo)是:org.mapstruct:mapstruct-jdk8,這可以幫助我們利用一些Java8的新特性。
  • org.mapstruct:mapstruct-processor:注解處理器,根據(jù)注解自動(dòng)生成mapper的實(shí)現(xiàn)。
<dependency>
        <groupId>org.mapstruct</groupId>
        <!-- jdk8以下就使用mapstruct -->
        <artifactId>mapstruct-jdk8</artifactId>
        <version>1.2.0.Final</version>
    </dependency>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct-processor</artifactId>
        <version>1.2.0.Final</version>
    </dependency>

好了,準(zhǔn)備工作做完了,接下來(lái)我們就看看巧媳婦兒巧在什么地方吧。

二、先簡(jiǎn)單玩一把

2.1、定義實(shí)體類(lèi)以及被映射類(lèi)

// 實(shí)體類(lèi)
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User {
    private Integer id;
    private String name;
    private String createTime;
    private LocalDateTime updateTime;
}
// 被映射類(lèi)VO1:和實(shí)體類(lèi)一模一樣
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class UserVO1 {
    private Integer id;
    private String name;
    private String createTime;
    private LocalDateTime updateTime;
}
// 被映射類(lèi)VO1:比實(shí)體類(lèi)少一個(gè)字段
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class UserVO2 {
    private Integer id;
    private String name;
    private String createTime;
}

2.2、定義接口:

當(dāng)實(shí)體類(lèi)和被映射對(duì)象屬性相同或者被映射對(duì)象屬性值少幾個(gè)時(shí):

@Mapper(componentModel = "spring")
public interface UserCovertBasic {
    UserCovertBasic INSTANCE = Mappers.getMapper(UserCovertBasic.class);
    /**
     * 字段數(shù)量類(lèi)型數(shù)量相同,利用工具BeanUtils也可以實(shí)現(xiàn)類(lèi)似效果
     * @param source
     * @return
     */
    UserVO1 toConvertVO1(User source);
    User fromConvertEntity1(UserVO1 userVO1);
    /**
     * 字段數(shù)量類(lèi)型相同,數(shù)量少:僅能讓多的轉(zhuǎn)換成少的,故沒(méi)有fromConvertEntity2
     * @param source
     * @return
     */
    UserVO2 toConvertVO2(User source);
}

從上面的代碼可以看出:接口中聲明了一個(gè)成員變量INSTANCE,母的是讓客戶(hù)端可以訪問(wèn) Mapper 接口的實(shí)現(xiàn)。

2.3、使用

@RestController
public class TestController {
    @GetMapping("convert")
    public Object convertEntity() {
        User user = User.builder()
                .id(1)
                .name("張三")
                .createTime("2020-04-01 11:05:07")
                .updateTime(LocalDateTime.now())
                .build();
        List<Object> objectList = new ArrayList<>();
        objectList.add(user);
        // 使用mapstruct
        UserVO1 userVO1 = UserCovertBasic.INSTANCE.toConvertVO1(user);
        objectList.add("userVO1:" + UserCovertBasic.INSTANCE.toConvertVO1(user));
        objectList.add("userVO1轉(zhuǎn)換回實(shí)體類(lèi)user:" + UserCovertBasic.INSTANCE.fromConvertEntity1(userVO1));
        // 輸出轉(zhuǎn)換結(jié)果
        objectList.add("userVO2:" + " | " + UserCovertBasic.INSTANCE.toConvertVO2(user));
        // 使用BeanUtils
        UserVO2 userVO22 = new UserVO2();
        BeanUtils.copyProperties(user, userVO22);
        objectList.add("userVO22:" + " | " + userVO22);
        return objectList;
    }
}

2.4、查看編譯結(jié)果

通過(guò)IDE的反編譯功能查看編譯后自動(dòng)生成 UserCovertBasic 的實(shí)現(xiàn)類(lèi) UserCovertBasicImpl ,內(nèi)容如下:

@Component
public class UserCovertBasicImpl implements UserCovertBasic {
    public UserCovertBasicImpl() {
    }
    public UserVO1 toConvertVO1(User source) {
        if (source == null) {
            return null;
        } else {
            UserVO1 userVO1 = new UserVO1();
            userVO1.setId(source.getId());
            userVO1.setName(source.getName());
            userVO1.setCreateTime(source.getCreateTime());
            userVO1.setUpdateTime(source.getUpdateTime());
            return userVO1;
        }
    }
    public User fromConvertEntity1(UserVO1 userVO1) {
        if (userVO1 == null) {
            return null;
        } else {
            User user = new User();
            user.setId(userVO1.getId());
            user.setName(userVO1.getName());
            user.setCreateTime(userVO1.getCreateTime());
            user.setUpdateTime(userVO1.getUpdateTime());
            return user;
        }
    }
    public UserVO2 toConvertVO2(User source) {
        if (source == null) {
            return null;
        } else {
            UserVO2 userVO2 = new UserVO2();
            userVO2.setId(source.getId());
            userVO2.setName(source.getName());
            userVO2.setCreateTime(source.getCreateTime());
            return userVO2;
        }
    }
}

2.5、瀏覽器查看結(jié)果

好了,一個(gè)流程就走完了,是不是感覺(jué)賊簡(jiǎn)單呢?

而且呀,阿淼溫馨提醒:
如果是要轉(zhuǎn)換一個(gè)集合的話,只需要把這里的實(shí)體類(lèi)換成集合就行了,例如:

List<UserVO1> toConvertVOList(List<User> source);

三、不簡(jiǎn)單的情況

上面已經(jīng)把整個(gè)流程都給過(guò)了一遍了,相信大家對(duì) mapstruct 也有了一個(gè)基礎(chǔ)的了解了,所以接下來(lái)的情況我們就不展示全部代碼了,畢竟篇幅也有限,所以就直接上關(guān)鍵代碼(因?yàn)椴魂P(guān)鍵的和上面內(nèi)容一樣,哈哈)

3.1、類(lèi)型不一致

實(shí)體類(lèi)我們還是沿用 User;被映射對(duì)象 UserVO3 改為:

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class UserVO3 {
    private String id;
    private String name;
    // 實(shí)體類(lèi)該屬性是String
    private LocalDateTime createTime;
    // 實(shí)體類(lèi)該屬性是LocalDateTime
    private String updateTime;
}

那么我們定義的接口就要稍稍修改一下了:

 @Mappings({
            @Mapping(target = "createTime", expression = "java(com.java.mmzsblog.util.DateTransform.strToDate(source.getCreateTime()))"),
    })
    UserVO3 toConvertVO3(User source);
    User fromConvertEntity3(UserVO3 userVO3);

上面 expression 指定的表達(dá)式內(nèi)容如下:

public class DateTransform {
    public static LocalDateTime strToDate(String str){
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyy-MM-dd HH:mm:ss");
        return LocalDateTime.parse("2018-01-12 17:07:05",df);
    }
}

通過(guò)IDE的反編譯功能查看編譯后的實(shí)現(xiàn)類(lèi),結(jié)果是這樣子的:

從圖中我們可以看到,編譯時(shí)使用了expression中定義的表達(dá)式對(duì)目標(biāo)字段 createTime 進(jìn)行了轉(zhuǎn)換;然后你還會(huì)發(fā)現(xiàn) updateTime 字段也被自動(dòng)從 LocalDateTime 類(lèi)型轉(zhuǎn)換成了 String 類(lèi)型。

阿淼小結(jié):

當(dāng)字段類(lèi)型不一致時(shí),以下的類(lèi)型之間是 mapstruct 自動(dòng)進(jìn)行類(lèi)型轉(zhuǎn)換的:

  • 1、基本類(lèi)型及其他們對(duì)應(yīng)的包裝類(lèi)型。
  • 此時(shí) mapstruct 會(huì)自動(dòng)進(jìn)行拆裝箱。不需要人為的處理
  • 2、基本類(lèi)型的包裝類(lèi)型和string類(lèi)型之間

除此之外的類(lèi)型轉(zhuǎn)換我們可以通過(guò)定義表達(dá)式來(lái)進(jìn)行指定轉(zhuǎn)換。

3.2、字段名不一致

實(shí)體類(lèi)我們還是沿用 User;被映射對(duì)象 UserVO4 改為:

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class UserVO4 {
    // 實(shí)體類(lèi)該屬性名是id
    private String userId;
    // 實(shí)體類(lèi)該屬性名是name
    private String userName;
    private String createTime;
    private String updateTime;
}

那么我們定義的接口就要稍稍修改一下了:

@Mappings({
            @Mapping(source = "id", target = "userId"),
            @Mapping(source = "name", target = "userName")
    })
    UserVO4 toConvertVO(User source);
    
    User fromConvertEntity(UserVO4 userVO4);

通過(guò)IDE的反編譯功能查看編譯后的實(shí)現(xiàn)類(lèi),編譯后的結(jié)果是這樣子的:

很明顯, mapstruct 通過(guò)讀取我們配置的字段名對(duì)應(yīng)關(guān)系,幫我們把它們賦值在了相對(duì)應(yīng)的位置上,可以說(shuō)是相當(dāng)優(yōu)秀了,但這也僅僅是優(yōu)秀,而更秀的還請(qǐng)繼續(xù)往下看:

阿淼小結(jié):

當(dāng)字段名不一致時(shí),通過(guò)使用 @Mappings 注解指定對(duì)應(yīng)關(guān)系,編譯后即可實(shí)現(xiàn)對(duì)應(yīng)字段的賦值。

3.3、屬性是枚舉類(lèi)型

實(shí)體類(lèi)我們還是改用 UserEnum:

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class UserEnum {
    private Integer id;
    private String name;
    private UserTypeEnum userTypeEnum;
}

被映射對(duì)象 UserVO5 改為:

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class UserVO5 {
    private Integer id;
    private String name;
    private String type;
}

枚舉對(duì)象是:

@Getter
@AllArgsConstructor
public enum UserTypeEnum {
    Java("000", "Java開(kāi)發(fā)工程師"),
    DB("001", "數(shù)據(jù)庫(kù)管理員"),
    LINUX("002", "Linux運(yùn)維員");
    private String value;
    private String title;
}

那么我們定義的接口還是照常定義,不會(huì)受到它是枚舉就有所變化:

 @Mapping(source = "userTypeEnum", target = "type")
    UserVO5 toConvertVO5(UserEnum source);
    UserEnum fromConvertEntity5(UserVO5 userVO5);

通過(guò)IDE的反編譯功能查看編譯后的實(shí)現(xiàn)類(lèi),編譯后的結(jié)果是這樣子的:

很明顯, mapstruct 通過(guò)枚舉類(lèi)型的內(nèi)容,幫我們把枚舉類(lèi)型轉(zhuǎn)換成字符串,并給type賦值,可謂是小心使得萬(wàn)年船啊??磥?lái)這巧媳婦兒不僅僅優(yōu)秀還心細(xì)啊……

源代碼

文章中的所有例子已上傳github:https://github.com/mmzsblog/mapstructDemo

到此這篇關(guān)于詳解Java中的mapstruct使用的文章就介紹到這了,更多相關(guān)Java mapstruct使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java字符串中刪除指定子字符串的方法簡(jiǎn)介

    Java字符串中刪除指定子字符串的方法簡(jiǎn)介

    這篇文章主要介紹了Java字符串中刪除指定子字符串的方法,是Java入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-11-11
  • Java多線程工具CompletableFuture詳解

    Java多線程工具CompletableFuture詳解

    這篇文章主要介紹了Java多線程工具CompletableFuture詳解,CompletableFuture?是?java?1.8?追加的新特性,通俗的話來(lái)說(shuō),是一個(gè)函數(shù)式的,用于控制多任務(wù)同步、異步組合操作的工具,需要的朋友可以參考下
    2024-01-01
  • Java instanceof和getClass()區(qū)別實(shí)例解析

    Java instanceof和getClass()區(qū)別實(shí)例解析

    這篇文章主要介紹了Java instanceof和getClass()區(qū)別實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • 史上最難的一道Java面試題

    史上最難的一道Java面試題

    本文給大家分享一道史上最難的一道Java面試題,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧
    2018-03-03
  • java分布式面試接口如何保證冪等及概念理解

    java分布式面試接口如何保證冪等及概念理解

    這篇文章主要為大家介紹了java分布式面試中接口如何保證冪等的問(wèn)題解答以及概念描述,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2022-03-03
  • mybatis多個(gè)接口參數(shù)的注解使用方式(@Param)

    mybatis多個(gè)接口參數(shù)的注解使用方式(@Param)

    這篇文章主要介紹了mybatis多個(gè)接口參數(shù)的注解使用方式(@Param),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-10-10
  • IntelliJ IDEA安裝目錄和設(shè)置目錄的說(shuō)明(IntelliJ IDEA快速入門(mén))

    IntelliJ IDEA安裝目錄和設(shè)置目錄的說(shuō)明(IntelliJ IDEA快速入門(mén))

    這篇文章主要介紹了IntelliJ IDEA安裝目錄和設(shè)置目錄的說(shuō)明(IntelliJ IDEA快速入門(mén)),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04
  • Java快速排序QuickSort(實(shí)例)

    Java快速排序QuickSort(實(shí)例)

    下面小編就為大家?guī)?lái)一篇Java快速排序QuickSort(實(shí)例)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-10-10
  • 使用arthas命令redefine實(shí)現(xiàn)Java熱更新(推薦)

    使用arthas命令redefine實(shí)現(xiàn)Java熱更新(推薦)

    今天分享一個(gè)非常重要的命令 redefine ,主要作用是加載外部的 .class 文件,用來(lái)替換 JVM 已經(jīng)加載的類(lèi),總結(jié)起來(lái)就是實(shí)現(xiàn)了 Java 的熱更新,感興趣的朋友跟隨小編一起看看吧
    2020-05-05
  • 使用jdbcTemplate查詢(xún)返回自定義對(duì)象集合代碼示例

    使用jdbcTemplate查詢(xún)返回自定義對(duì)象集合代碼示例

    這篇文章主要介紹了使用jdbcTemplate查詢(xún)返回自定義對(duì)象集合代碼示例,分享了相關(guān)代碼示例,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-02-02

最新評(píng)論