1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

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

        共 8059字,需瀏覽 17分鐘

         ·

        2020-12-07 04:56


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

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

        第一次看到 MapStruct 的時(shí)候, 我個(gè)人非常的開心。因?yàn)槠涓覂?nèi)心里面的想法不謀而合。

        1 MapStruct 是什么?

        1.1 JavaBean 的困擾

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

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

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

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

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

        1.2 MapStruct 帶來的改變

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

        抓一下重點(diǎn):

        1. 注解處理器

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

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

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

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

        2 MapStruct 入門

        入門很簡單。我是基于 Maven 來進(jìn)行項(xiàng)目 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 某個(gè)訂單系統(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);

        }

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

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

        2.4 測試

        寫一個(gè)測試類測試一下。

        @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個(gè)步驟來實(shí)現(xiàn)了從 OrderOrderQueryParam 的轉(zhuǎn)換。

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

        3.1 高性能

        這是相對反射來說的, 反射需要去讀取字節(jié)碼的內(nèi)容, 花銷會(huì)比較大。而通過 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;
            }
        }

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

        3.2 易于 debug

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

        易于 DEBUG


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

        3.3 使用相對簡單

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

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

        3.4 代碼獨(dú)立

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


        --------------------------   END  --------------------------


        原創(chuàng)整理《第2版:互聯(lián)網(wǎng)大廠面試題》



        掃碼添加,我的個(gè)人微信,備注:面試題
         注意,不要亂回復(fù) 
        (一定要備注:面試題)否則不給通過

        如果被添加頻繁,請30分鐘后再試試

        沒錯(cuò),加我好友,給你安排到位

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

        手機(jī)掃一掃分享

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

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            秋霞性爱视频 | www精品美女久久久tv | 日日色综合| 日韩欧美小电影 | 国产精品午夜成人免费 | 亚洲成人黄色在线 | 深夜福利视频在线观看 | 国产女同互慰高潮 | 美国诗诗毛片xX 八重神子精夜狂飙游戏漫画 | bdsm乳铐bdsm折磨bdsm |