日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
實(shí)體類的屬性映射怎么可以少了它?

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

創(chuàng)新互聯(lián)公司服務(wù)項(xiàng)目包括石拐網(wǎng)站建設(shè)、石拐網(wǎng)站制作、石拐網(wǎng)頁制作以及石拐網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,石拐網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到石拐省份的部分城市,未來相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!

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

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

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

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

  • Github地址:https://github.com/mapstruct/mapstruct/
  • 使用例子:https://github.com/mapstruct/mapstruct-examples

一、準(zhǔn)備工作

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

1.1、了解@Mapper 注解

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

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

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

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

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

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

1.2、依賴包

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

  • org.mapstruct:mapstruct:包含了一些必要的注解,例如@Mapping。r若我們使用的JDK版本高于1.8,當(dāng)我們在pom里面導(dǎo)入依賴時(shí)候,建議使用坐標(biāo)是:org.mapstruct:mapstruct-jdk8,這可以幫助我們利用一些Java8的新特性。
  • org.mapstruct:mapstruct-processor:注解處理器,根據(jù)注解自動(dòng)生成mapper的實(shí)現(xiàn)。
 
 
 
 
  1.  
  2.         org.mapstruct 
  3.          
  4.         mapstruct-jdk8 
  5.         1.2.0.Final 
  6.      
  7.      
  8.         org.mapstruct 
  9.         mapstruct-processor 
  10.         1.2.0.Final 
  11.      

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

二、先簡單玩一把

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

 
 
 
 
  1. // 實(shí)體類 
  2. @Data 
  3. @NoArgsConstructor 
  4. @AllArgsConstructor 
  5. @Builder 
  6. public class User { 
  7.     private Integer id; 
  8.     private String name; 
  9.     private String createTime; 
  10.     private LocalDateTime updateTime; 
  11.  
  12. // 被映射類VO1:和實(shí)體類一模一樣 
  13. @Data 
  14. @NoArgsConstructor 
  15. @AllArgsConstructor 
  16. @Builder 
  17. public class UserVO1 { 
  18.     private Integer id; 
  19.     private String name; 
  20.     private String createTime; 
  21.     private LocalDateTime updateTime; 
  22.  
  23. // 被映射類VO1:比實(shí)體類少一個(gè)字段 
  24. @Data 
  25. @NoArgsConstructor 
  26. @AllArgsConstructor 
  27. @Builder 
  28. public class UserVO2 { 
  29.     private Integer id; 
  30.     private String name; 
  31.     private String createTime; 
  32.  

2.2、定義接口:

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

 
 
 
 
  1. @Mapper(componentModel = "spring") 
  2. public interface UserCovertBasic { 
  3.     UserCovertBasic INSTANCE = Mappers.getMapper(UserCovertBasic.class); 
  4.  
  5.     /** 
  6.      * 字段數(shù)量類型數(shù)量相同,利用工具BeanUtils也可以實(shí)現(xiàn)類似效果 
  7.      * @param source 
  8.      * @return 
  9.      */ 
  10.     UserVO1 toConvertVO1(User source); 
  11.     User fromConvertEntity1(UserVO1 userVO1); 
  12.  
  13.     /** 
  14.      * 字段數(shù)量類型相同,數(shù)量少:僅能讓多的轉(zhuǎn)換成少的,故沒有fromConvertEntity2 
  15.      * @param source 
  16.      * @return 
  17.      */ 
  18.     UserVO2 toConvertVO2(User source); 

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

2.3、使用

 
 
 
 
  1. @RestController 
  2. public class TestController { 
  3.  
  4.     @GetMapping("convert") 
  5.     public Object convertEntity() { 
  6.         User user = User.builder() 
  7.                 .id(1) 
  8.                 .name("張三") 
  9.                 .createTime("2020-04-01 11:05:07") 
  10.                 .updateTime(LocalDateTime.now()) 
  11.                 .build(); 
  12.         List objectList = new ArrayList<>(); 
  13.  
  14.         objectList.add(user); 
  15.  
  16.         // 使用mapstruct 
  17.         UserVO1 userVO1 = UserCovertBasic.INSTANCE.toConvertVO1(user); 
  18.         objectList.add("userVO1:" + UserCovertBasic.INSTANCE.toConvertVO1(user)); 
  19.         objectList.add("userVO1轉(zhuǎn)換回實(shí)體類user:" + UserCovertBasic.INSTANCE.fromConvertEntity1(userVO1)); 
  20.         // 輸出轉(zhuǎn)換結(jié)果 
  21.         objectList.add("userVO2:" + " | " + UserCovertBasic.INSTANCE.toConvertVO2(user)); 
  22.         // 使用BeanUtils 
  23.         UserVO2 userVO22 = new UserVO2(); 
  24.         BeanUtils.copyProperties(user, userVO22); 
  25.         objectList.add("userVO22:" + " | " + userVO22); 
  26.  
  27.         return objectList; 
  28.     } 
  29. 2.4、查看編譯結(jié)果

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

     
     
     
     
    1. @Component 
    2. public class UserCovertBasicImpl implements UserCovertBasic { 
    3.     public UserCovertBasicImpl() { 
    4.     } 
    5.  
    6.     public UserVO1 toConvertVO1(User source) { 
    7.         if (source == null) { 
    8.             return null; 
    9.         } else { 
    10.             UserVO1 userVO1 = new UserVO1(); 
    11.             userVO1.setId(source.getId()); 
    12.             userVO1.setName(source.getName()); 
    13.             userVO1.setCreateTime(source.getCreateTime()); 
    14.             userVO1.setUpdateTime(source.getUpdateTime()); 
    15.             return userVO1; 
    16.         } 
    17.     } 
    18.  
    19.     public User fromConvertEntity1(UserVO1 userVO1) { 
    20.         if (userVO1 == null) { 
    21.             return null; 
    22.         } else { 
    23.             User user = new User(); 
    24.             user.setId(userVO1.getId()); 
    25.             user.setName(userVO1.getName()); 
    26.             user.setCreateTime(userVO1.getCreateTime()); 
    27.             user.setUpdateTime(userVO1.getUpdateTime()); 
    28.             return user; 
    29.         } 
    30.     } 
    31.  
    32.     public UserVO2 toConvertVO2(User source) { 
    33.         if (source == null) { 
    34.             return null; 
    35.         } else { 
    36.             UserVO2 userVO2 = new UserVO2(); 
    37.             userVO2.setId(source.getId()); 
    38.             userVO2.setName(source.getName()); 
    39.             userVO2.setCreateTime(source.getCreateTime()); 
    40.             return userVO2; 
    41.         } 
    42.     } 

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

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

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

     
     
     
     
    1. List toConvertVOList(List source); 

    三、不簡單的情況

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

    3.1、類型不一致

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

     
     
     
     
    1. @Data 
    2. @NoArgsConstructor 
    3. @AllArgsConstructor 
    4. @Builder 
    5. public class UserVO3 { 
    6.     private String id; 
    7.     private String name; 
    8.     // 實(shí)體類該屬性是String 
    9.     private LocalDateTime createTime; 
    10.     // 實(shí)體類該屬性是LocalDateTime 
    11.     private String updateTime; 

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

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

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

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

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

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

    阿粉小結(jié):

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

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

    2、基本類型的包裝類型和string類型之間

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

    3.2、字段名不一致

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

     
     
     
     
    1. @Data 
    2. @NoArgsConstructor 
    3. @AllArgsConstructor 
    4. @Builder 
    5. public class UserVO4 { 
    6.     // 實(shí)體類該屬性名是id 
    7.     private String userId; 
    8.     // 實(shí)體類該屬性名是name 
    9.     private String userName; 
    10.     private String createTime; 
    11.     private String updateTime; 

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

     
     
     
     
    1. @Mappings({ 
    2.             @Mapping(source = "id", target = "userId"), 
    3.             @Mapping(source = "name", target = "userName") 
    4.     }) 
    5.     UserVO4 toConvertVO(User source); 
    6.      
    7.     User fromConvertEntity(UserVO4 userVO4); 

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

    阿粉小結(jié):

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

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

    3.3、屬性是枚舉類型

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

     
     
     
     
    1. @Data 
    2. @NoArgsConstructor 
    3. @AllArgsConstructor 
    4. @Builder 
    5. public class UserEnum { 
    6.     private Integer id; 
    7.     private String name; 
    8.     private UserTypeEnum userTypeEnum; 

    被映射對象 UserVO5 改為:

     
     
     
     
    1. @Data 
    2. @NoArgsConstructor 
    3. @AllArgsConstructor 
    4. @Builder 
    5. public class UserVO5 { 
    6.     private Integer id; 
    7.     private String name; 
    8.     private String type; 

    枚舉對象是:

     
     
     
     
    1. @Getter 
    2. @AllArgsConstructor 
    3. public enum UserTypeEnum { 
    4.     Java("000", "Java開發(fā)工程師"), 
    5.     DB("001", "數(shù)據(jù)庫管理員"), 
    6.     LINUX("002", "Linux運(yùn)維員"); 
    7.      
    8.     private String value; 
    9.     private String title; 
    10.  

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

     
     
     
     
    1. @Mapping(source = "userTypeEnum", target = "type") 
    2.     UserVO5 toConvertVO5(UserEnum source); 
    3.  
    4.     UserEnum fromConvertEntity5(UserVO5 userVO5); 

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

    很明顯, mapstruct 通過枚舉類型的內(nèi)容,幫我們把枚舉類型轉(zhuǎn)換成字符串,并給type賦值,可謂是小心使得萬年船啊。

    看來這巧媳婦兒不僅僅優(yōu)秀還心細(xì)啊……

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


    新聞名稱:實(shí)體類的屬性映射怎么可以少了它?
    轉(zhuǎn)載源于:http://www.5511xx.com/article/cdegohs.html