1. 程式人生 > >從產品展示頁面談談Hybris系列之二: DTO, Converter和Populator

從產品展示頁面談談Hybris系列之二: DTO, Converter和Populator

ext 存儲 resource tar adl 裏的 resolve 個數 lis

文章作者:張健(Zhang Jonathan)

上一篇文章 從產品展示頁面談談Hybris的特有概念和設計結構 我們講解了Hybris一些特有的概念以及大體架構,並且介紹了Facade層裏是如何定義DTO(Data Transfer Object)對象。

一個尚未回答的問題: 為什麽DTO(在上一篇文章的具體例子裏是Java類ProductData)會由Converter來生成?

這篇文章就從此問題開始。

我們再次翻出上一篇文章展示過的這張架構圖。

技術分享圖片

當我們打開一個Hybris應用網頁,比如某個Product(產品)的明細頁面時, 背後實際上執行了下列的邏輯:

  1. Service層從數據庫裏把數據取出,以Model(又稱為DAO對象)的形式返回給Facade層。

  2. Facade層調用Converter, 在Populator的幫助下,基於Model生成了DTO。

  3. 明細頁面的Controller將其對應的JSP路徑返回給Hybris框架。

上述步驟完成之後,我們即可看到數據填充完畢之後的Hybris Product明細頁面。

本文將詳細介紹上述步驟(2), 即DTO的生成邏輯。

DAO

當點擊這個名為DSC-H20 BLUE的產品圖片後,

技術分享圖片

可以跳轉到它的明細頁面。

其中DAO的生成,也就是下圖137行代碼裏的變量productModel的生成邏輯,會在下一篇文章即這個系列的第三篇文章詳細闡述。 本文我們重點介紹DTO(第138行變量productData的生成邏輯)。

技術分享圖片

現在我們可以簡單地把DAO對象,即變量productModel理解成它包含了DSC-H20 BLUE這個產品在數據庫裏存儲的明細。

如果有ABAP開發經驗的朋友,可以把這個變量包含的內容類比成ABAP裏通過OPEN SQL從透明表裏取出的數據。 這些數據由於格式原因還不能直接給上層的UI做展示,而需要經過進一步的加工和處理。這些加工由下文的converter和populator來完成。

DTO

之前我們介紹了DTO(productData)是由第138行的convert方法生成的。這個方法的調用者是getProductConverter方法返回的一個Converter的實例,該實例實際上是Spring框架幫我們註入的一個Bean。對Bean這個概念不熟悉的朋友可以用關鍵字"Spring Bean"在百度或者Google上搜索。

技術分享圖片

那麽ProductConverter這個Bean的Spring相關定義在Hybris項目文件夾的什麽地方呢?

  1. Converter

前一篇文章從產品展示頁面談談Hybris的特有概念和設計結構介紹過,產品相關的Facade層存在於bin/ext-commerce/commercefacades這個extension。而在其中的resource/commercefacades-spring.xml文件中可以找到productConverter的定義:

技術分享圖片

第137行到139行表明實際註入的populators屬性是一個列表(List),這個List裏的每一個元素是ProductPopulator。 從List這個數據結構我們可以猜想到,Converter主要是通過調用1個或多個Populator來生成DTO對象的。

  1. Populator

我們再來看看Populator這個接口的代碼,它定義了一個名為populate(SOURCE,TARGET)的方法。方法的註釋清楚地說明了Populator是用Source變量的字段值去生成(Populate)Target變量的字段值,如下圖所示。

回到我們的Product明細頁面的展示例子。在ProductPopulator中:

  • Source對應Java類ProductModel

  • Target對應Java類ProductData

可見, Populator一般用於從Service層的DAO對象生成Facade層的DTO對象。

技術分享圖片

關於Populator的實際例子, 我們可以看看ProductUrlPopulator這個類, 它是接口Populator的一個具體實現類, 位於packagede.hybris.platform.commercefacades.product.converters.populator下面。從這個package下面我們也能發現很多其他的Populator,這也解釋了本文Converter章節裏介紹的為什麽Populator屬性註入的類型需要選擇為List。

技術分享圖片

從populate方法中可以看到:

  • DTO ProductData裏的code和name屬性的值都是直接取自DAO ProductModel裏對應的同名屬性;

  • DTO ProductData的url屬性則是第47行的resolve方法根據DAO ProductModel計算出來的。

這個resolve方法的使用,表明了Populator不只是簡單的把DAO對象的值設置到DTO對象中。在Hybris的標準實現裏諸如Product url屬性這樣需要調用其它Service來處理後然後再展示到前端的例子還有很多。

比如商品的庫存,多貨幣價格等信息, 在數據庫端本來就沒有和產品信息存在同一張表,自然也不能直接從Product的DAO對象中獲取,而是需要在相關的Populator裏調用單獨的物流處理和價格處理的Service來生成。

這裏我們再回想下Hybris的三層結構圖。

設想下如果沒有Facade層和DTO對象,前端的Controller將不得不調用很多Service,返回很多單獨的Model(如產品,物流和價格信息)給頁面,加重頁面處理的負擔。而Hybris的Facade層包裝了Service層的復雜邏輯,為前端提供了簡明統一的DTO對象,大大降低了前端的處理復雜度。這正是面向對象設計模式中的Facade(外觀)模式的體現,因此我們能夠從Hybris的架構圖中發現Facade層的名字。

希望大家通過這篇文章對Hybris Facade層的Converter和Populator能有比較詳細的了解。下一篇我們將繼續介紹Hybris的Service層。

Jerry註:

優秀的產品總是有著相似的設計思路。本文介紹的DAO和DTO, 不僅僅出現在Hybris裏,在SAP的很多其他產品裏也有用到。

在SAP CRM裏,從ABAP數據庫裏取出的數據因為結構差異無法直接被SAP CRM的BSP UI消費,必須要在圖中的Generic Interaction Layer裏做一個結構和格式的轉換:

技術分享圖片

下圖是SAP CRM UI上產品長文本字段的一個截圖:

技術分享圖片

這個長文本字段的值, 從數據庫取出到最後顯示在UI上,也經歷了在Populator(下圖的ABAP類: CL_CRM_PRODIL_LONGTEXT)裏從DAO到DTO的轉換。

技術分享圖片

至此我們能發現無論是在SAP Hybris還是SAP CRM裏,這種DAO到DTO的映射都體現在具體的代碼裏。

而在SAP Business by Design, SAP Hybris Cloud for Customer和SAP S/4HANA裏,這種DAO到DTO的映射關系則維護在一些模型裏。這樣, 應用開發人員負責維護映射關系,而框架負責統一處理映射關系。即使將來因為業務變化導致這些映射關系也需要發生變化,此時可以僅修改維護映射關系的模型,而無需修改任何代碼。

SAP把底層模型層(Model Layer)和上層消費層(Consumption Layer)之間的存儲及解析映射關系模型的這一中間層稱為SADL(Service Adaptation Definition Layer, L在有的上下文裏也稱為Language)。維護映射關系的模型則成為SADL模型。如下圖所示:

技術分享圖片

在這個系列的下一篇文章裏,Jonathan將介紹Hybris Commerce的持久層設計原理。

要獲取更多Jerry的原創技術文章,請關註公眾號"汪子熙"或者掃描下面二維碼:
技術分享圖片

技術分享圖片

從產品展示頁面談談Hybris系列之二: DTO, Converter和Populator