摘要:商品詳情接口商品表按索引查詢商品信息。接著,我們來看看和定義名稱概念解釋標準產品單位剝離銷售屬性的部分,例如小米。
前言
建議使用大屏設備(例如pad/pc),可以更好的瀏覽本篇文章
今天我們開始「商品系統」的篇章。本文分為如下五大模塊:
需求分析
架構設計
Spu和Sku的故事
數據模型設計
接口設計
第一篇我們主要看看一個入門的電商平臺(B2C)如何去構建自己的基礎商品信息,其實這個事情很簡單,想想我們的現實生活,商家擺放商品到貨架,客戶從貨架挑選商品,客戶把挑選好的商品放入購物車(籃),最后客戶去收銀臺結賬。
需求分析對于一個電商平臺來講,我們怎么理解上面的簡單示例呢?接著,我們來拆分上面這個簡單的事情:
商家擺放商品到貨架,客戶從貨架挑選商品,客戶把挑選好的商品放入購物車(籃),最后客戶去收銀臺結賬
商家是誰:電商平臺
擺放是什么意思:上架
貨架在哪:前臺系統(web/app/...)
挑選:瀏覽前臺系統
放入:點擊前臺系統「加入購物車按鈕」
...(暫不多說了)
備注:本篇文章主要來看看1、2、3、4步該如何去設計。
通過上面的分析我們可以得出下面的信息:
我們需要一個「電商平臺」,電商平臺里面需要有個商品后臺系統。
我們上架什么東西呢?商品!所以商品后臺系統需要具備創建和發布商品到前臺系統的功能。
我們需要一個前臺系統(比如網頁),前臺系統具備商品列表和商品詳情的頁面,可供用戶瀏覽。
前臺系統的數據怎么來?所以我們需要一個接口網關(對外統一提供服務能力,企業總線)和商品服務
整理之后得到如下的需求點:
需求點 | 功能點 | 項目命名 | 技術棧 |
---|---|---|---|
商品后臺系統 | 1.創建商品 2.發布商品到前臺系統 | Temporal Backend | PHP |
前臺系統 | 1.商品列表 2.商品詳情 | Skr Frontend | Vue |
接口網關 | 企業總線 | Skr Gateway | kong |
商品服務 | 1.創建商品接口 2.商品狀態變更接口 2.商品列表接口 3. 商品詳情接口 | Temporal Service | Golang |
通過上面的需求分析,再加上之前的《電商設計手冊之用戶體系》中的用戶體系和《支付開發,不得不了解的國內、國際第三方支付流程》中的支付服務,我們規劃出以下的架構圖。
Spu和Sku的故事
對我們程序猿來講「商品系統」剛開始的樣子就是如下三點:
創建商品功能:首先我們會有一張商品表,每創建一個商品我們會的到一個goods_id,如果商品存在父子的關系,加一個parent_id的字段就搞定了。
商品列表接口:商品表分頁查詢商品。
商品詳情接口:商品表按goods_id索引查詢商品信息。
很簡單是吧,基本一張表就搞定了,看起來也是沒什么問題的。但是呢,程序設計的巧妙之處就在于抽象能力,電商行業把goods_id進行了進一步的抽象,產生了Spu和Sku概念,在了解Spu和Sku定義之前,我們還得了解下銷售屬性的含義,舉個例子便于理解:
想想我們的現實生活,假如我們去批發市場上了一批AJ1球鞋,批發商會給我們不同配色、大小的AJ1球鞋。我們在店里銷售這些商品時都會詢問客戶:“您是需要什么顏色和大小的AJ1球鞋呢?”。這里的顏色和大小就是所謂的銷售屬性,因為不同顏色和大小的AJ1球鞋可能價格不同、庫存數量不同,現實生活中是不是如此,不同顏色或大小的AJ1都有差別巨大的價格。
接著,我們來看看Spu和Sku定義:
名稱 | 概念 | 解釋 |
---|---|---|
Spu | standard product unit 標準產品單位 | goods_id剝離銷售屬性的部分,例如:小米8。商品列表我們展示Spu列表。 |
Sku | stock keeping unit 庫存量單位 | 就是你想買的那個商品真正的編號,這個編號對應的庫存就是你想買的那個商品的庫存量。Spu+一或多個銷售屬性對應一個Sku,例如:小米8黑128G,其中黑和128G就是銷售屬性,小米8就是一個Spu。 |
搞清楚了么?
數據模型設計所以最后簡單的商品表就拆成了spu表和sku表,接著我們還抽象出來了可復用的銷售屬性表和銷售屬性值表。除此之外
我們應該還有品牌表、類別表、簡單的sku庫存表(目前簡單設計此表,后期具體業務重構此表)。接著我們列下這些表的明細:
表名稱 | 表名 |
---|---|
品牌表 | product_brands |
類別表 | product_category |
spu表 | product_spu |
sku表 | product_sku |
銷售屬性表 | product_attr |
銷售屬性值 | product_attr_value |
sku庫存表 | product_sku_stock |
除了上面的表之外,我又加了另一張表 關聯關系冗余表 product_spu_sku_attr_map,為什么呢?顧名思義,冗余用的,有了這張表,我們可以很高效的得到:
spu下 有哪些sku
spu下 有那些銷售屬性
spu下 每個銷售屬性對應的銷售屬性值(一對多)
spu下 每個銷售屬性值對應的sku(一對多)
具體表結構如下所示:
-- 品牌表 product_brands CREATE TABLE `product_brands` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT "品牌ID", `name` varchar(255) unsigned NOT NULL DEFAULT "" COMMENT "品牌名稱", `desc` varchar(255) unsigned NOT NULL DEFAULT "" COMMENT "品牌描述", `logo_url` varchar(255) unsigned NOT NULL DEFAULT "" COMMENT "品牌logo圖片", `create_at` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "創建時間", `create_by` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "創建人staff_id", `update_at` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "更新時間", `update_by` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "修改人staff_id", `status` tinyint(1) unsigned NOT NULL DEFAULT "0" COMMENT "狀態 1:enable, 0:disable, -1:deleted", PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT="品牌表"; -- 類別表 product_category CREATE TABLE `product_category` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT "分類ID", `pid` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "父ID", `name` varchar(255) unsigned NOT NULL DEFAULT "" COMMENT "分類名稱", `desc` varchar(255) unsigned NOT NULL DEFAULT "" COMMENT "分類描述", `pic_url` varchar(255) unsigned NOT NULL DEFAULT "" COMMENT "分類圖片", `path` varchar(255) unsigned NOT NULL DEFAULT "" COMMENT "分類地址{pid}-{child_id}-...", `create_at` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "創建時間", `create_by` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "創建人staff_id", `update_at` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "更新時間", `update_by` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "修改人staff_id", `status` tinyint(1) unsigned NOT NULL DEFAULT "0" COMMENT "狀態 1:enable, 0:disable, -1:deleted", PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT="類別表"; -- spu表 product_spu -- spu: standard product unit 標準產品單位 CREATE TABLE `product_spu` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT "SPU ID", `brand_id` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "品牌ID", `category_id` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "分類ID", `name` varchar(255) unsigned NOT NULL DEFAULT "" COMMENT "spu名稱", `desc` varchar(255) unsigned NOT NULL DEFAULT "" COMMENT "spu描述", `selling_point` varchar(255) unsigned NOT NULL DEFAULT "" COMMENT "賣點", `unit` varchar(255) unsigned NOT NULL DEFAULT "" COMMENT "spu單位", `banner_url` text COMMENT "banner圖片 多個圖片逗號分隔", `main_url` text COMMENT "商品介紹主圖 多個圖片逗號分隔", `price_fee` int unsigned NOT NULL DEFAULT 0 COMMENT "售價,整數方式保存", `price_scale` tinyint unsigned NOT NULL DEFAULT 0 COMMENT "售價,金額對應的小數位數", `market_price_fee` int unsigned NOT NULL DEFAULT 0 COMMENT "市場價,整數方式保存", `market_price_scale` tinyint unsigned NOT NULL DEFAULT 0 COMMENT "市場價,金額對應的小數位數", `create_at` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "創建時間", `create_by` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "創建人staff_id", `update_at` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "更新時間", `update_by` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "修改人staff_id", `status` tinyint(1) unsigned NOT NULL DEFAULT "0" COMMENT "狀態 1:enable, 0:disable, -1:deleted", PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT AUTO_INCREMENT=666666 CHARSET=utf8mb4 COMMENT="spu表"; -- sku表 product_sku -- sku: stock keeping unit 庫存量單位 CREATE TABLE `product_sku` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT "SKU ID", `spu_id` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "SPU ID", `attrs` text COMMENT "銷售屬性值{attr_value_id}-{attr_value_id} 多個銷售屬性值逗號分隔", `banner_url` text COMMENT "banner圖片 多個圖片逗號分隔", `main_url` text COMMENT "商品介紹主圖 多個圖片逗號分隔", `price_fee` int unsigned NOT NULL DEFAULT 0 COMMENT "售價,整數方式保存", `price_scale` tinyint unsigned NOT NULL DEFAULT 0 COMMENT "售價,金額對應的小數位數", `market_price_fee` int unsigned NOT NULL DEFAULT 0 COMMENT "市場價,整數方式保存", `market_price_scale` tinyint unsigned NOT NULL DEFAULT 0 COMMENT "市場價,金額對應的小數位數", `create_at` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "創建時間", `create_by` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "創建人staff_id", `update_at` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "更新時間", `update_by` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "修改人staff_id", `status` tinyint(1) unsigned NOT NULL DEFAULT "0" COMMENT "狀態 1:enable, 0:disable, -1:deleted", PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT AUTO_INCREMENT=666666 CHARSET=utf8mb4 COMMENT="sku表"; -- 銷售屬性表 product_attr CREATE TABLE `product_attr` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT "銷售屬性ID", `name` varchar(255) unsigned NOT NULL DEFAULT "" COMMENT "銷售屬性名稱", `desc` varchar(255) unsigned NOT NULL DEFAULT "" COMMENT "銷售屬性描述", `create_at` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "創建時間", `create_by` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "創建人staff_id", `update_at` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "更新時間", `update_by` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "修改人staff_id", `status` tinyint(1) unsigned NOT NULL DEFAULT "0" COMMENT "狀態 1:enable, 0:disable, -1:deleted", PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT="銷售屬性表"; -- 銷售屬性值 product_attr_value CREATE TABLE `product_attr_value` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT "銷售屬性值ID", `attr_id` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "銷售屬性ID", `value` varchar(255) unsigned NOT NULL DEFAULT "" COMMENT "銷售屬性值", `desc` varchar(255) unsigned NOT NULL DEFAULT "" COMMENT "銷售屬性值描述", `create_at` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "創建時間", `create_by` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "創建人staff_id", `update_at` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "更新時間", `update_by` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "修改人staff_id", `status` tinyint(1) unsigned NOT NULL DEFAULT "0" COMMENT "狀態 1:enable, 0:disable, -1:deleted", PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT="銷售屬性值"; -- 關聯關系冗余表 product_spu_sku_attr_map -- 1. spu下 有哪些sku -- 2. spu下 有那些銷售屬性 -- 3. spu下 每個銷售屬性對應的銷售屬性值(一對多) -- 4. spu下 每個銷售屬性值對應的sku(一對多) CREATE TABLE `product_spu_sku_attr_map` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT "自增ID", `spu_id` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "SPU ID", `sku_id` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "SKU ID", `attr_id` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "銷售屬性ID", `attr_name` varchar(255) NOT NULL DEFAULT "0" COMMENT "銷售屬性名稱", `attr_value_id` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "銷售屬性值ID", `attr_value_name` varchar(255) NOT NULL DEFAULT "0" COMMENT "銷售屬性值", `create_at` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "創建時間", `create_by` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "創建人staff_id", `status` tinyint(1) unsigned NOT NULL DEFAULT "0" COMMENT "狀態 1:enable, 0:disable, -1:deleted", PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT="關聯關系冗余表"; -- sku庫存表 product_sku_stock CREATE TABLE `product_sku_stock` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT "自增ID", `sku_id` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "SKU ID", `quantity` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "庫存", `create_at` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "創建時間", `create_by` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "創建人staff_id", `update_at` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "更新時間", `update_by` int(11) unsigned NOT NULL DEFAULT "0" COMMENT "修改人staff_id", `status` tinyint(1) unsigned NOT NULL DEFAULT "0" COMMENT "狀態 1:enable, 0:disable, -1:deleted", PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT="sku庫存表";接口設計
關于接口設計目前很簡單,無非列表和詳情。但是這里我做了一個很好的設計動靜分離,例如庫存的動態的數據,多帶帶提供接口,其他列表和詳情數據完全靜態化,把流量打到CDN去,這里又會說到我們下步計劃的基礎服務體系里的「靜態資源服務」,這個服務的主要功能就是把我們的接口數據靜態化。具體的V1.0版的接口設計如下:
1、spu詳情 GET {version}/product/spu/{spu_id}
請求參數:
字段 | 類型 | 是否必傳 | 描述 |
---|---|---|---|
spu_id | number | yes | spu ID |
響應內容:
{ "code": "200", "msg": "OK", "result": { "brand_info": { "id": "number, 品牌ID", "name": "string, 品牌名稱", "desc": "string, 品牌描述", "logo_url": "string, 品牌logo圖片", }, "category_info": { "id": "number, 分類ID", "name": "string, 品牌名稱", "desc": "string, 品牌描述", "pic_url": "string, 分類圖片", "path": "string, 分類地址{pid}-{child_id}-...", }, "spu_info": { "id": "number, spu id", "name": "string, spu名稱", "desc": "string, spu描述", "selling_point": "string, 賣點", "unit": "string, spu單位", "banner_url": [ "string, banner 圖片url", "string, banner 圖片url", ], "main_url": [ "string, 商品介紹主圖 圖片url", "string, 商品介紹主圖 圖片url", ], "price": "string, 售價", "market_price": "string, 市場價", "attrs": [ // 有那些銷售屬性 { "id": "銷售屬性ID", "name": "string, 銷售屬性名稱", "desc": "string, 銷售屬性描述", "values": [ // 每個銷售屬性對應的銷售屬性值(一對多) { "id": "銷售屬性值ID", "name": "string, 銷售屬性值", "desc": "string, 銷售屬性值描述", // 每個銷售屬性值對應的sku(一對多) // 頁面初始化時,按鈕不可點擊邏輯判斷: 如果該銷售屬性值下所有sku沒有庫存,則該銷售屬性按鈕不可點擊 // 選擇銷售屬性值時,按鈕不可點擊邏輯判斷:銷售屬性構成雙向鏈表,每個銷售屬性又是一個單向鏈表存改銷售屬性對應的所有銷售屬性值。每當選擇一個銷售屬性值時先前和后一個銷售屬性遍歷,執銷售屬性值下所有sku售罄的按鈕不可點擊,且當前銷售屬性值map記錄key為當前點擊的銷售屬性值ID,值統一標示一下就行,目的記錄是由于選擇了哪個銷售屬性值使得當前的銷售屬性值為售罄狀態 // 取消選擇銷售屬性值時,按鈕不可點擊邏輯恢復判斷:數據結構同上,遍歷,記錄的map刪除key為當前取消選中的銷售屬性值,并判斷是否還有別的key使得該銷售屬性值為售罄狀態,如果沒有則恢復未售罄狀態 "skus": [ "number, sku id", "number, sku id", ], } ], } ], "skus": [ // 有哪些sku "number, sku id", "number, sku id", ], "skus_map": { "{attr_value_id}-{attr_value_id}-...": "number, sku id", "{attr_value_id}-{attr_value_id}-...": "number, sku id", "{attr_value_id}-{attr_value_id}-...": "number, sku id", "{attr_value_id}-{attr_value_id}-...": "number, sku id", "{attr_value_id}-{attr_value_id}-...": "number, sku id", "{attr_value_id}-{attr_value_id}-...": "number, sku id", } } } }
2、獲取spu下所有skus庫存 GET {version}/stock/spu/{spu_id}
請求參數:
字段 | 類型 | 是否必傳 | 描述 |
---|---|---|---|
spu_id | number | yes | spu ID |
響應內容:
{ "code": "200", "msg": "OK", "result": { "skus_stock": { "int, sku id": { "quantity": "int, 剩余庫存數量" } } } } }
3、sku詳情 GET {version}/product/sku/{sku_id}
請求參數:
字段 | 類型 | 是否必傳 | 描述 |
---|---|---|---|
sku | number | yes | sku ID |
響應內容:
{ "code": "200", "msg": "OK", "result": { "id": "number, sku id", "name": "string, sku名稱", "desc": "string, sku描述", "unit": "string, sku單位", "banner_url": [ "string, banner 圖片url", "string, banner 圖片url", ], "main_url": [ "string, 商品介紹主圖 圖片url", "string, 商品介紹主圖 圖片url", ], "price": "string, 售價", "market_price": "string, 市場價", } }
4、spu列表 GET {version}/product/spu/list
請求參數:
字段 | 類型 | 是否必傳 | 描述 |
---|
響應內容:
{ "code": "200", "msg": "OK", "result": { "list": [ { "id": "number, spu id", "name": "string, spu名稱", "desc": "string, spu描述", "unit": "string, spu單位", "banner_url": [ "string, banner 圖片url", "string, banner 圖片url", ], "price": "string, 售價", "market_price": "string, 市場價", } ] } }結語
最后,如果有寫的不對或者不完善的地方,希望大家多多評論,互相學習互相進步~
項目地址: https://github.com/skr-shop/m...
下篇預告下篇文章我們主要專注到基礎商品信息的前端交互設計,比如Spu詳情頁面多銷售屬性的選擇如何聯動等,盡情期待。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/30057.html
摘要:前言這是電商系統設計系列在商品設計這塊的最后一篇文章。電商系統商品相關的文章已經到了尾聲如果有其他商品相關的文章需要編寫可以私信聯系我畢竟我也是公司員工寫這些文章并不是我的工作,只是記錄我的職業生涯。 showImg(https://segmentfault.com/img/bVbePdh?w=1260&h=628); 前言 這是電商系統設計系列在商品設計這塊的最后一篇文章。以下是其他...
摘要:驗證碼安全參考信息重放登錄注冊找密等入口,可能通過短信驗證碼郵箱驗證碼之類的進行確認操作,如果末對操作進行次數及頻率上的限制,則會產生大量的重放攻擊。高并發缺陷交易類重放攻擊,高并發的情況下末對用戶操作行為加鎖,導致購買限制的繞過。 showImg(https://segmentfault.com/img/bVBVVR); 業務安全從流程設計維度可劃分為賬戶體系安全、交易體系安全、支付...
摘要:可擴展性百度百科的定義是設計良好的代碼允許更多的功能在必要時可以被插入到適當的位置中。正常購物車商品優惠券都是獨立的系統及功能,不要看做商品在購物車內。可維護性百度百科的定義是系統的可維護性是衡量一個系統的可修復恢復性和可改進性的難易程度。 showImg(https://segmentfault.com/img/bVbcqJE?w=506&h=326); 本章適合初級工程師及中級工程...
摘要:致謝感謝你們看到這里,下一篇我會講一下關于電商系統的商品設計的部分。 showImg(https://segmentfault.com/img/bVbclTs?w=500&h=329); 電商大伙每天都在用,類似某貓,某狗等。電商系統設計看似復雜又很簡單,看似簡單又很復雜本章適合初級工程師及中級工程師細看,大佬請隨意 前言 設計以以下為工具講起 PHP為開發語言 基于Laravel框...
摘要:當前,很多學者和研究機構都嘗試基于深度學習進行服裝檢索技術的探究與創新。下文將回顧三篇基于深度學習來解決跨域服裝檢索問題的文章。總的來說,以上深度學習方法的探索與創新都將為商品檢索技術趨 摘要商品檢索是一門綜合了物體檢測、 圖像分類以及特征學習的技術。 近期, 很多研究者成功地將深度學習方法應用到這個領域。 本文對這些方法進行了總結, 然后概括地提出了商品特征學習框架以及垂類數據挖掘方式, ...
閱讀 2562·2021-09-02 15:40
閱讀 1565·2019-08-30 15:54
閱讀 1079·2019-08-30 12:48
閱讀 3398·2019-08-29 17:23
閱讀 1046·2019-08-28 18:04
閱讀 3664·2019-08-26 13:54
閱讀 606·2019-08-26 11:40
閱讀 2390·2019-08-26 10:15