html
購物車模塊的難點有如下幾點java
一、購物車促銷的顯示和價格計算redis
二、結算頁促銷的顯示和價格計算算法
三、計算和顯示邏輯複雜,還要時時判斷活動的有效性緩存
四、兩個地方的購物車顯示和計算,有同樣的邏輯的地方,也有差別的架構
五、促銷規則的多種多樣性能
接下來,咱們來詳細看一下Javashop電商系統中購物車的架構思路:ui
1、將存儲分爲兩部分:spa
sku原始數據3d
用戶選擇的促銷活動
每次購物車的顯示,都根據這些數據進行一次從新渲染和計算
2、將促銷規則的算法和計算分開
抽像出規則對象,由每一個活動根據原始數據去生成這些規則
而後統一將這些規則進行計算造成要顯示的效果和價格
3、把不可避免的耗性能的操做,放在加入購物車中完成,而不是在列表循環中完成
屬性 | 說明 | 備註 |
---|---|---|
skuList | 規格列表 | 對應CartSkuVO對象 |
sellerId | 賣家id | |
price | 價格對象 | 對應PriceDetailVO對象 |
ruleList | 促銷規則列表 | 對應PromotionRule對象 |
couponList | 優惠卷列表 | 對應CouponVO對象 |
giftList | 贈品列表 | 對應FullDiscountGiftDO |
giftCouponList | 贈送優惠卷列表 | 對應CouponVO對象 |
promotionNotice | 促銷提示 | 目前只有滿優惠提示 |
屬性 | 說明 | 備註 |
---|---|---|
name | 商品名稱 | |
skuId | skuid | |
specList | 規則列表 | 對應SpecValueVo對象 |
singleList | 單品活動列表 | 對應CartPromotionVo對象, 顯示在列表中供用戶選擇 |
groupList | 組合活動列表 | 對應CartPromotionVo對象 |
invalid | 是否失效 | |
errorMessage | 失效緣由 | |
originalPrice | 商品原價 | 用於計算優惠的基礎價格 |
purchasePrice | 成交價 | |
num | 數量 | |
subtotal | 小計 | |
promotionTags | 促銷標籤 | 顯示當前sku應用了何種優惠 |
屬性 | 說明 | 備註 |
---|---|---|
originalPrice | 原價 | |
goodsPrice | 成交價 | |
freightPrice | 運費 | |
totalPrice | 合計 | |
discountPrice | 總優惠價格 | |
cashBack | 返現金額 | 全部單品活動產生的優惠 |
fullMinus | 滿減金額 | |
couponPrice | 優惠卷抵扣金額 | 不計在返現中 |
isFreeFreight | 是否免運費 | |
exchangePoint | 用了多少積分 | 用於兌換此商品 |
屬性 | 說明 | 備註 |
---|---|---|
originalPrice | 原價 | |
goodsPrice | 成交價 | |
freightPrice | 運費 | |
totalPrice | 合計 | |
discountPrice | 總優惠價格 | |
cashBack | 返現金額 | 全部單品活動產生的優惠 |
fullMinus | 滿減金額 | |
couponPrice | 優惠卷抵扣金額 | 不計在返現中 |
isFreeFreight | 是否免運費 | |
exchangePoint | 用了多少積分 | 用於兌換此商品 |
屬性 | 說明 | 備註 |
---|---|---|
memberCouponId | 會員優惠卷id | 會員領取後的惟一id,取消時或使用時 要用此id |
couponId | 此優惠卷的id | 會員領取後,此值不變,不能作爲使用時調用 |
sellerId | 賣家id | |
amount | 面值 | |
endTime | 有效期 | 到秒的時間戳 |
useTerm | 使用條件 | 如:「滿100元可用」 |
selected | 是否選中 | 當用戶選擇此優惠卷時,會標記爲1,未選中時爲0 |
enable | 是否可用 | 當不可用時(不知足條件或已過時)爲0,可用爲1 |
屬性 | 說明 | 備註 |
---|---|---|
singlePromotionMap | 用戶選擇的單品活動 | |
couponMap | 用戶選擇的優惠卷 |
類型:Map
key是店鋪id ,對應此店鋪對應的促銷活動
類型:Map
key是店鋪id ,對應此店鋪使用的優惠卷
項 | 前綴 | 鏈接 | 存儲對象 |
---|---|---|---|
購物車原始數據 | CART_ORIGIN_DATA_PREFIX | buyer.uid | List\ |
購物車促銷 | CART_PROMOTION_PREFIX | buyer.uid | SelectedPromotionVo |
一、調用原始數據業務類(CartOriginDataManager)的添加方法
根據sku讀出商品數據,並造成CartSkuOriginVo
二、填充促銷信息
讀取此商品的促銷活動,填充到上述的Vo中
此時若是傳遞了要使用的活動id(須要使用活動的,見下面)
三、寫入緩存
造成list\並寫入redis
四、使用活動
若是傳遞了活動id,則調用CartPromotionManager 使用此活動
五、寫入緩存
在使用活動時,會將組合好的 singlePromotionMap 寫入redis
經過「建造者」模式來完成購物車的促銷信息渲染、價格計算的。
其中要建造的「產品」是CartView,包含一個List和一個price 對象(即列表和總價)
建造過程是一條流水線:
一、首先由SkuRenderer(Sku構建器)構建出全新的一個CartList
這個CartList是由緩存中OriginSku的skulist作爲物料生成出來的
二、接下來由促銷規則渲染器(PromotionRuleRenderer)構建出促銷規則(Promotion)
此時的物料是用戶選擇的Promotiont生成出來的,具體的製造過程參見《促銷規則的構建》
三、流水線中下一個製造環節是生產Price
此時的物料是上一步生產的Rule,按照必定的規則算法對價格進行計算:
具體的製造過程參見《價格的計算過程》
四、流水線是由CartBuilder來整體控制的,最終由他來組裝成品:CartView
調用時序以下:
根據需求,促銷規則主要有如下幾種:
組合促銷:滿減
單品促銷:第二件半價、單品立減、團購,秒殺等
優惠卷
其中組合促銷是應用在整個購物車中的,
單品促銷是應用在Sku上的,
優惠卷只有在結算頁才能使用和計算,並且不計算在返現金額中。
綜上所述,咱們分別針對如上的種類,定義了:
SkuPromotionRuleBuilder(Sku促銷規則構建器)
CartPromotionRuleBuilder(Cart促銷規則構建器)
CartCouponRuleBuilder(優惠卷促銷規則構建器)
用關係:
先調用CartPromotionManager 獲取已經選中的促銷
再分別調用各類構建器構建出Rule,
從流水線的控制上,優惠卷的構建是要被跳過的(由於購物車是不處理優惠卷的)
將Rule分別放在Cart和Sku中的Rule中
根據目前的單品促銷類型,實現了5個具體的構建器:
SeckillPluginNew 秒殺
GroupBuyGoodsPluginNew 團購
MinusPluginNew 單品立減
HalfPricePluginNew 第二件半件
ExchangePluginNew 積分兌換
具體調用哪一個構建器完build rule ,則由實現者的
getPromotionType(): PromotionTypeEnum
方法來決定
這是應用在購物車上的規則構建器,目前只有一個滿減的實現
目前只有一個默認實現
根據需求,在結算頁要計算運費和優惠卷,所以在流水線上要控制其製造流程:
在促銷規則的構建過程當中加入了優惠卷的構建
在計算價格以前加入了運費的計算
在最後加入了優惠卷的渲染CartVo中的CouponLIst
那麼最終購物車構建器整體類圖以下:
從上面的架構能夠看出,促銷規則的定義很是重要,能夠參見《PromotionRule》,即:
在這裏咱們定義了:
reducedTotalPrice是整體減的金額
reducedPrice:是單品減的金額
useCoupon:是要使用的優惠卷
invalid: 定義了是否失效了,好比加入購物車時活動還有效,但過了一會正好失效了。
invalidReason:
不光定義了失效的緣由,還有一些特殊狀況:好比加入購物車是商品活動售空數是5,買了5個,過了一會別人下單成功了,售後數是3個了,此時在這裏要提示用戶,但不失效,用戶能夠勾選改成3個繼續下單
價格計算統一面向規則,而無論規則的構建過程,從而實現了算法和計算的分離。
這是在CartPriceCalculator中來完成的,實現過程就比較簡單了:
易族智匯(javashop)原創文章