當前位置: 妍妍網 > 碼農

強烈推薦 MapperStruct,不建議用 BeanUtils.copyProperties 拷貝數據?

2024-05-29碼農

來源:juejin.cn/post/7333458486435987494

👉 歡迎 ,你將獲得: 專屬的計畫實戰 / Java 學習路線 / 一對一提問 / 學習打卡 / 每月贈書

新計畫: 仿小紅書 (微服務架構)正在更新中... , 全棧前後端分離部落格計畫 2.0 版本完結啦, 演示連結 http://116.62.199.48/ 。全程手摸手,後端 + 前端全棧開發,從 0 到 1 講解每個功能點開發步驟,1v1 答疑,直到計畫上線。 目前已更新了261小節,累計43w+字,講解圖:1806張,還在持續爆肝中.. 後續還會上新更多計畫,目標是將Java領域典型的計畫都整一波,如秒殺系統, 線上商城, IM即時通訊,Spring Cloud Alibaba 等等,

  • 為什麽使用MapperStruct

  • 怎麽使用MapperStruct

  • 總結

  • 在實際的業務開發中,我們經常會碰到BO、PO、DTO等物件內容之間的賦值,當內容較多的時候我們使用get,set的方式進行賦值的工作量相對較大,因此很多人會選擇使用spring提供的拷貝工具 BeanUtils copyProperties 方法完成物件之間內容的拷貝。

    透過這種方式可以很大程度上降低我們手動編寫物件內容賦值程式碼的工作量,既然它那麽方便為什麽還不建議使用呢?

    我總結為以下幾點:

  • 內容型別不一致導致拷貝失敗

  • 在實際開發中,很可能會出現同一欄位在不同的類中定義的型別不一致,例如Id,可能在A類中定義的型別為Long,在B類中定義的型別為String,此時如果使用 BeanUtils.copyProperties 進行拷貝,就會出現拷貝失敗的現象,導致對應的欄位為null

  • 同一欄位分別使用包裝型別和基本型別

  • 如果同一個欄位分別使用包裝類和基本型別,在沒有傳遞實際值的時候,會出現異常

    註意,如果一個布爾型別的內容分別使用了基本型別和包裝型別,且內容名如果使用is開頭,例如isSuccess,也會導致拷貝失敗

  • null值覆蓋導致數據異常

  • 在業務開發時,我們可能會有部份欄位拷貝的需求,被拷貝的數據裏面如果某些欄位有null值存在,但是對應的需要被拷貝過去的數據的相同欄位的值並不為null,如果直接使用 BeanUtils.copyProperties 進行數據拷貝,就會出現被拷貝數據的null值覆蓋拷貝目標數據的欄位,導致原有的數據失效

    簡單舉個例子,我有一個BO(已經存在了A內容且有值),需要拷貝DTO中除了A內容的其他內容(DTO中的A內容為null),此時使用 BeanUtils.copyProperties 就會導致BO中的A內容的值被DTO中A的null給覆蓋了

    雖然可以使用 BeanUtils.copyProperties 的多載方法,配合自訂的 ConvertUtilsBean 來實作部份欄位的拷貝,但是這麽做本身也比較復雜,也就失去了使用 BeanUtils.copyProperties 拷貝數據的意義,因此也不推薦這麽做。

  • 底層實作為反射拷貝效率低

  • 導包錯誤導致拷貝數據異常

  • 為什麽使用MapperStruct

    為什麽使用 MapperStruct ? ---> 快,對就是因為很快,效能比 BeanUtils.copyProperties 快很多很多

    放張參考圖給大家參考

    圖片

    那麽為什麽 MapperStruct比BeanUtils.copyProperties 快?

  • 避免了反射操作的效能開銷

  • 預編譯的高效程式碼執行更快 (看到這裏就懵了,預編譯?咋回事啊到底)

  • 什麽是預編譯? --- 在計畫啟動的時候,自動幫你生成物件拷貝的程式碼,拒絕使用的時候才去透過反射呼叫get/set...

    具體的可以往下看

    @Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2024-02-07T00:50:05+0800",
    comments = "version: 1.4.2.Final, compiler: javac, environment: Java 1.8.0_211 (Oracle Corporation)"
    )
    public class XXXDTOConverterImpl implements XXXDTOConverter {
    @Override
    public XXXBO convertDtoToBo(XXXDTO XXXDTO) {
    if ( XXXDTO == null ) {
    return null;
    }
    XXXBO XXXBO = new XXXBO();
    XXXBO.setId( XXXDTO.getId() );
    XXXBO.setLabelName( XXXDTO.getLabelName() );
    XXXBO.setSortNum( XXXDTO.getSortNum() );
    XXXBO.setCategoryId( XXXDTO.getCategoryId() );
    return XXXBO;
    }
    }


    怎麽使用MapperStruct

    Maven引入依賴

    <dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.4.2.Final</version>
    </dependency>
    <dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-processor</artifactId>
    <version>1.4.2.Final</version>
    </dependency>

    編寫程式碼

    @Data
    public class SubjectLabelDTO implements Serializable {
    private String labelName;
    }
    @Data
    public class SubjectLabelBO implements Serializable {
    private String labelName;
    }
    @Mapper
    public interface SubjectLabelDTOConverter {
    SubjectLabelDTOConverter INSTANCE = Mappers.getMapper(SubjectLabelDTOConverter. class);
    SubjectLabelBO convertDtoToBo(SubjectLabelDTO subjectLabelDTO);
    }
    public Result<Boolean> add( SubjectLabelDTO subjectLabelDTO){
    SubjectLabelBO subjectLabelBO = SubjectLabelDTOConverter.INSTANCE
    .convertDtoToBo(subjectLabelDTO);
    }

    總結

    Mapper-struct同樣也是淺拷貝,需要進行深拷貝,就寫多個Converter把需要深拷貝的再轉一次吧,如果要配置深拷貝太麻煩了

    Mapper-struct也存在一點小問題,跟lombok在配合的時候會出現問題,如果mapperStruct的依賴放在lombok的依賴上面的話就會出現在物件復制的時候,會將原有數據全變為null的情況,所以一定要將lombok的依賴放在mapperStruct上面

    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>${lombok.version}</version>
    </dependency>
    <dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.4.2.Final</version>
    </dependency>
    <dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-processor</artifactId>
    <version>1.4.2.Final</version>
    </dependency>

    👉 歡迎 ,你將獲得: 專屬的計畫實戰 / Java 學習路線 / 一對一提問 / 學習打卡 / 每月贈書

    新計畫: 仿小紅書 (微服務架構)正在更新中... , 全棧前後端分離部落格計畫 2.0 版本完結啦, 演示連結 http://116.62.199.48/ 。全程手摸手,後端 + 前端全棧開發,從 0 到 1 講解每個功能點開發步驟,1v1 答疑,直到計畫上線。 目前已更新了261小節,累計43w+字,講解圖:1806張,還在持續爆肝中.. 後續還會上新更多計畫,目標是將Java領域典型的計畫都整一波,如秒殺系統, 線上商城, IM即時通訊,Spring Cloud Alibaba 等等,


    1. 

    2. 

    3. 

    4. 

    最近面試BAT,整理一份面試資料Java面試BATJ通關手冊,覆蓋了Java核心技術、JVM、Java並行、SSM、微服務、資料庫、數據結構等等。

    獲取方式:點「在看」,關註公眾號並回復 Java 領取,更多內容陸續奉上。

    PS:因公眾號平台更改了推播規則,如果不想錯過內容,記得讀完點一下在看,加個星標,這樣每次新文章推播才會第一時間出現在你的訂閱列表裏。

    「在看」支持小哈呀,謝謝啦