1. 你還在用 BeanUtils來做對象轉(zhuǎn)換嗎?快試試 MapStruct吧

        共 4424字,需瀏覽 9分鐘

         ·

        2020-09-19 23:12

        作者:阿進(jìn)的寫字臺

        https://www.cnblogs.com/homejim/

        第一次看到 MapStruct 的時候, 我個人非常的開心。因為其跟我內(nèi)心里面的想法不謀而合。

        1 MapStruct 是什么?

        1.1 JavaBean 的困擾

        對于代碼中 JavaBean之間的轉(zhuǎn)換, 一直是困擾我很久的事情。

        在開發(fā)的時候我看到業(yè)務(wù)代碼之間有很多的 JavaBean 之間的相互轉(zhuǎn)化, 非常的影響觀感, 卻又不得不存在。我后來想的一個辦法就是通過反射, 或者自己寫很多的轉(zhuǎn)換器。

        第一種通過反射的方法確實(shí)比較方便, 但是現(xiàn)在無論是 BeanUtils, BeanCopier 等在使用反射的時候都會影響到性能。雖然我們可以進(jìn)行反射信息的緩存來提高性能。

        但是像這種的話, 需要類型和名稱都一樣才會進(jìn)行映射, 有很多時候, 由于不同的團(tuán)隊之間使用的名詞不一樣, 還是需要很多的手動 set/get 等功能。

        第二種的話就是會很浪費(fèi)時間, 而且在添加新的字段的時候也要進(jìn)行方法的修改。不過, 由于不需要進(jìn)行反射, 其性能是很高的。

        1.2 MapStruct 帶來的改變

        MapSturct 是一個生成類型安全, 高性能且無依賴的 JavaBean 映射代碼的注解處理器(annotation processor)。

        抓一下重點(diǎn):

        1. 注解處理器

        2. 可以生成 JavaBean 之間那的映射代碼

        3. 類型安全, 高性能, 無依賴性

        從字面的理解, 我們可以知道, 該工具可以幫我們實(shí)現(xiàn) JavaBean 之間的轉(zhuǎn)換, 通過注解的方式。

        同時, 作為一個工具類,相比于手寫, 其應(yīng)該具有便捷, 不容易出錯的特點(diǎn)。

        2 MapStruct 入門

        入門很簡單。我是基于 Maven 來進(jìn)行項目 jar 包管理的。

        2.1 引入依賴


        ????????1.3.0.Final



        ????org.mapstruct
        ????mapstruct-jdk8
        ????${org.mapstruct.version}



        ????org.mapstruct
        ????mapstruct-processor
        ????${org.mapstruct.version}

        2.2 創(chuàng)建entity和dto對象

        該類是從 github 某個訂單系統(tǒng)里面拿下來的部分。

        @Data
        public?class?Order?{

        ????/**
        ?????*訂單id
        ?????*/
        ????private?Long?id;

        ????/**
        ?????*?訂單編號
        ?????*/
        ????private?String?orderSn;

        ????/**
        ?????*?收貨人姓名/號碼
        ?????*/
        ????private?String?receiverKeyword;

        ????/**
        ?????*?訂單狀態(tài):0->待付款;1->待發(fā)貨;2->已發(fā)貨;3->已完成;4->已關(guān)閉;5->無效訂單
        ?????*/
        ????private?Integer?status;

        ????/**
        ?????*?訂單類型:0->正常訂單;1->秒殺訂單
        ?????*/
        ????private?Integer?orderType;

        ????/**
        ?????*?訂單來源:0->PC訂單;1->app訂單
        ?????*/
        ????private?Integer?sourceType;
        }

        對應(yīng)的查詢參數(shù)

        @Data
        public?class?OrderQueryParam?{
        ????/**
        ?????*?訂單編號
        ?????*/
        ????private?String?orderSn;

        ????/**
        ?????*?收貨人姓名/號碼
        ?????*/
        ????private?String?receiverKeyword;

        ????/**
        ?????*?訂單狀態(tài):0->待付款;1->待發(fā)貨;2->已發(fā)貨;3->已完成;4->已關(guān)閉;5->無效訂單
        ?????*/
        ????private?Integer?status;

        ????/**
        ?????*?訂單類型:0->正常訂單;1->秒殺訂單
        ?????*/
        ????private?Integer?orderType;

        ????/**
        ?????*?訂單來源:0->PC訂單;1->app訂單
        ?????*/
        ????private?Integer?sourceType;


        }

        2.3 寫 Mapper

        Mapper 即映射器, 一般來說就是寫 xxxMapper 接口。

        當(dāng)然, 不一定是以 Mapper 結(jié)尾的。只是官方是這么寫的。在本入門例子中,對應(yīng)的接口如下

        import?com.homejim.mapstruct.dto.OrderQueryParam;
        import?com.homejim.mapstruct.entity.Order;
        import?org.mapstruct.Mapper;
        import?org.mapstruct.Mapping;

        @Mapper
        public?interface?OrderMapper?{

        ????OrderQueryParam?entity2queryParam(Order?order);

        }

        簡單的映射(字段和類型都匹配), 只有一個要求, 在接口上寫 @Mapper 注解即可。

        然后方法上, 入?yún)?yīng)要被轉(zhuǎn)化的對象, 返回值對應(yīng)轉(zhuǎn)化后的對象, 方法名稱可任意。

        2.4 測試

        寫一個測試類測試一下。

        @Test
        public?void?entity2queryParam()?{
        ????Order?order?=?new?Order();
        ????order.setId(12345L);
        ????order.setOrderSn("orderSn");
        ????order.setOrderType(0);
        ????order.setReceiverKeyword("keyword");
        ????order.setSourceType(1);
        ????order.setStatus(2);

        ????OrderMapper?mapper?=?Mappers.getMapper(OrderMapper.class);
        ????OrderQueryParam?orderQueryParam?=?mapper.entity2queryParam(order);
        ????assertEquals(orderQueryParam.getOrderSn(),?order.getOrderSn());
        ????assertEquals(orderQueryParam.getOrderType(),?order.getOrderType());
        ????assertEquals(orderQueryParam.getReceiverKeyword(),?order.getReceiverKeyword());
        ????assertEquals(orderQueryParam.getSourceType(),?order.getSourceType());
        ????assertEquals(orderQueryParam.getStatus(),?order.getStatus());

        }

        測試通過, 沒有任何的問題。

        3 MapStruct 分析

        上面中, 我寫了3個步驟來實(shí)現(xiàn)了從 OrderOrderQueryParam 的轉(zhuǎn)換。

        那么, 作為一個注解處理器, 通過MapStruct 生成的代碼具有怎么樣的優(yōu)勢呢?

        3.1 高性能

        這是相對反射來說的, 反射需要去讀取字節(jié)碼的內(nèi)容, 花銷會比較大。而通過 MapStruct 來生成的代碼, 其類似于人手寫。速度上可以得到保證。

        前面例子中生成的代碼可以在編譯后看到。在 target/generated-sources/annotations 里可以看到。

        生成的代碼

        對應(yīng)的代碼

        @Generated(
        ????value?=?"org.mapstruct.ap.MappingProcessor",
        ????date?=?"2019-08-02T00:29:49+0800",
        ????comments?=?"version:?1.3.0.Final,?compiler:?javac,?environment:?Java?11.0.2?(Oracle?Corporation)"
        )
        public?class?OrderMapperImpl?implements?OrderMapper?{

        ????@Override
        ????public?OrderQueryParam?entity2queryParam(Order?order)?{
        ????????if?(?order?==?null?)?{
        ????????????return?null;
        ????????}

        ????????OrderQueryParam?orderQueryParam?=?new?OrderQueryParam();

        ????????orderQueryParam.setOrderSn(?order.getOrderSn()?);
        ????????orderQueryParam.setReceiverKeyword(?order.getReceiverKeyword()?);
        ????????orderQueryParam.setStatus(?order.getStatus()?);
        ????????orderQueryParam.setOrderType(?order.getOrderType()?);
        ????????orderQueryParam.setSourceType(?order.getSourceType()?);

        ????????return?orderQueryParam;
        ????}
        }

        可以看到其生成了一個實(shí)現(xiàn)類, 而代碼也類似于我們手寫, 通俗易懂。

        3.2 易于 debug

        在我們生成的代碼中, 我們可以輕易的進(jìn)行 debug。

        易于 DEBUG

        在使用反射的時候, 如果出現(xiàn)了問題, 很多時候是很難找到是什么原因的。

        3.3 使用相對簡單

        如果是完全映射的, 使用起來肯定沒有反射簡單。用類似 BeanUtils 這些工具一條語句就搞定了。但是,如果需要進(jìn)行特殊的匹配(特殊類型轉(zhuǎn)換, 多對一轉(zhuǎn)換等), 其相對來說也是比較簡單的。

        基本上, 使用的時候, 我們只需要聲明一個接口, 接口下寫對應(yīng)的方法, 就可以使用了。當(dāng)然, 如果有特殊情況, 是需要額外處理的。

        3.4 代碼獨(dú)立

        生成的代碼是對立的, 沒有運(yùn)行時的依賴。

        瀏覽 55
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
          
          

            1. 大胸纲手雏田被羞羞视频 | 美女三级在线 | 台湾精品一区二区三区 | chinese国产18粉嫩dh | 在线播放【国产精品】 |