Go項目實戰-商品分類管理和分類樹的查詢構造
本節大綱如下:
畫板
從用例圖中我們能看出來商品模塊主要由兩大類功能用例組成:
- 商品分類的相關功能
- 商品信息的相關功能
圖片
圖片
本節我們先來實現商品分類在商城應用中的常用功能。
商品分類在產品中的角色分析
商品分類作為商品的主要導購信息,在手機應用和PC網頁應用上的頁面優先級并不一樣。手機因為可顯示內容比PC少,所以首頁上顯示的內容大部分都是購買率高的推薦分類、爆款單品、以及各種在做的促銷活動。
所以商品分類在App的首頁上并不會全部展示給用戶,而是像下面這樣,在產品中留一個導航入口,進入二級頁面在進行所有商品分類的展示。
圖片
而在PC網頁上因為頁面顯示區域的變大,一般在首頁上就有一個商品分類導航,通過多級聯動來展示所有的商品分類。
圖片
所以服務端的API返回的分類數據的結構,要能適應商品分類在手機App和PC網頁上的展示,一般商品分類都是采用三級分類的結構進行組織和維護(層級如果再多維護分類的打工人也頭疼),以分類樹的形式返回給客戶端。
商品分類數據準備
商品分類在C端接口中不涉及添加刪除和更新的操作,這些工作統一放在管理后臺由公司的工作人員來維護。一般管理后臺的用戶跟C端的用戶是隔離開的,登錄也不是用我們之前做的用戶登錄和Token認證,更多的是單獨維護一套管理員用戶。
現在人員規模多點的中型公司,基本上管理后臺都是跟自己的員工的統一賬號打通,使用LDAP登錄認證,這樣員工離職了工號一禁用,所有的后臺就都不能登錄了,現在使用釘釘和企業微信的公司都能基于它們自己搭建LDAP服務。
我們這里就不再費力去開發管理后臺的接口和相關認證了,關于商品分類數據的創建,我們通過一個測試接口把商品分類數據初始化好,這里我為大家準備好了一份商品分類數據的JSON文件。
一共有97個分類,基本上電商App上常見的分類都有涵蓋,文件我放在了項目的資源目錄resources中,名稱為category_init_data.json
圖片
resources 這個目錄我們在搭框架的時候說過是準備放靜態資源文件的,之前創建了一直沒用過,今天正好把它用起來。
不過大家別忘了,Go 程序打包的時候只會打.go文件,這種靜態資源文件需要我們使用 go embed 功能才能打包到二進制文件里去,才能保證把Go項目的運行文件放在哪它都能讀取到資源文件。
所以針對resources目錄我們在其中創建一個loader.go
//go:embed *
var f embed.FS
func LoadResourceFile(filePath string) (io.Reader, error) {
_bytes, err := f.ReadFile(filePath)
if err != nil {
return nil, err
}
return bytes.NewReader(_bytes), nil
}
在loader.go中我們通過embed *載入當前目錄下的所有文件。并提供一個LoadResourceFile方法,讓項目的程序能讀取指定的資源文件
針對我們剛才說的商品分類初始數據JSON文件,我們在項目中通過
resources.LoadResourceFile("category_init_data.json")
就能把JSON數據加載到內存中去。稍后我們會再寫個初始化程序就能把這些數據初始化到MySQL的表里。
商品分類按層級分布和展示
商品分類信息有了,接下來就該考慮怎么把他們查出來了。PC 網頁版的購物網站首頁都有一個按層級劃分的分類導航,這個功能需要我們把商品的分類信息按層級組織好后返回給客戶端,接下來我們就來開發這個功能。
按層級劃分的分類信息該怎么實現呢?最簡單的實現方式就是先把所有一級分類查出來,遍歷它們然后再把各自下屬的二級分類查出來,同時二級分類也是這個邏輯:遍歷-每次查下屬的三級分類。
這么做當然可以,就是有點費數據庫,相當于一個獲取所有商品分類的接口有可能要查幾十次數據庫才能組織好數據。當然還有另外一種方法:先把分類數據查出來,在程序內存中靠排序、臨時變量等方式加工好要返回的數據。
那這里我們就采用第二種方法來實現啦,無論用哪種實現方式其實嚴格意義上來說都沒問題,因為像層級分類這種變更不太頻繁但是結構復雜的數據一般我們會在緩存中緩存一份數據,避免每次都讓程序去查數據庫。
開始寫邏輯前,我們先在 api/reply/commodity.go 中定義好響應的結構
type HierarchicCommodityCategory struct {
ID int64 `json:"id"`
Level int `json:"level"`
ParentId int64 `json:"parent_id"`
Name string `json:"name"`
IconImg string `json:"icon_img"`
Rank int `json:"rank"`
SubCategories []*HierarchicCommodityCategory `json:"sub_categories"` // 分類的子分類
}
我們的接口會返回[]*HierarchicCommodityCategory類型的列表,即以一級分類為元素的列表,每個分類的SubCategories中會包含子分類數據,這個字段的類型也是[]*HierarchicCommodityCategory,這樣就能滿足我們返回層級分類的要求啦,即使是有四、五級分類用這個結構也沒問題。
一般商品的分類最多也就三級,再多就有點反人類了,維護起來也不好維護。
這里說一下命名的問題:Hierarchic 是形容詞意思是按層級劃分的,Hierarchy 是名詞意思是等級、層級,所以在分類層級相關的技術文檔里這兩個單詞的出現頻率比較高。
用這個響應結構最終我們會構造出下面這樣的按層劃分好的分類數據,前端拿到這樣數據后直接使用即可,不需要做更多邏輯處理。
圖片
好了接下來我們來看生成商品分類層級信息的在領域服務中的主要邏輯:就能看到按層級劃分好的所有商品分類信息。