購物車功能:
1.加入購物車商品
2.更新購物車商品數量
3.查詢購物車商品數量
4.移除購物車商品
5.購物車商品單選/取消
6.購物車商品全選/取消
7.購物車列表
學習目標:
1.購物車模塊的設計思想
2.封裝一個高複用購物車核心方法
3.解決浮點型在商業運算中丟失精度問題(尤其是價格結計算)
數據表設計
接口設計
limitQuantity:兩種狀態
--LIMIT_NUM_SUCCESS限制數量成功
--LIMIT_NUM_ERROR限制數量失敗
如果是限制數量失敗,會自動的把購物車中的產品數量進行修改,修改成最大值,也就是最大可購買的數量.應用場景:假設商品可購買數量是100個,當我們直接輸入200的時候超出商品庫存,就會返回一個LIMIT_NUM_ERROR,並把數量強制改回最大可購買數量如當前的100,並按可購數量計算總價.
那麼前端就可以根據該字段提示,已超出庫存,請進行修改.
實現:
購物車需要在用戶登錄狀態下進行操作.
1.購物車計算通用方法-購物車接口只要涉及到數量的變化都需要經過該方法,主要是用於防止超過庫存等一些注意操作
這個方法返回前端時都需要去調用的,用於向前端用戶返回最新的購物車數據.
場景:當在購物車添加商品時,
參數:productId商品ID,count數量
邏輯:
a-select:添加之前,需要去查詢當前用戶下,該productId是否在當前購物車.如果是空,說明該商品不再購物車,我們就要就該商品新增到購物車中.
b-insert:插入購物車數據表中,要將userId,商品id,數量count,同時設置當前商品的選中狀態checked=1(1是選中狀態);
c-update:如果a步驟查詢的是該商品已在該用戶的購物車中,那麼就是將購物車原有的數量加上現在加入購物車數量,並更新購物車數據表(也可同時將check狀態更新爲1,看需求);
基本思想是這個,但是我們額外還需要做一些操作,比如計算庫存等操作,防止前端和後端數據不一致.封裝高複用的購物車方法:
購物車產品組合的VO對象-CartProductVO(即已購物車表爲基礎進行擴展的表,比如根據userId可擴展一些用戶模塊信息,根據productId可擴展一些商品模塊信息)
CartProductVO:
id,userId,productId,quantity,productName,productSubtitle,productMainImage,productPrice,productStatus,productTotalPrice,productStock,productChecked,limitQuantity根據庫存限制返回數量字段
並且在整合CartProductVO後,在專門用一個針對cart購物車返回前端的VO-cartVO,這裏面集成了cartProductVO,並補充了一些通用字段:
CartVO:
List<CartProductVO> cartProductVO;
BigDecimal cartTotal;
Boolean allChecked;
String imageHost;
----將上述兩個對象封裝組合一個高複用的方法,返回給前端的CartVO對象.
private CartVO getCartVOList(int userId){
//根據userID查詢當前用戶購物車狀態
}
private CartVo getCartVoLimit(Integer userId){
// 1 初始化返回前端的購物車VO對象
CartVo cartVo = new CartVo();
// 2 獲取該用戶購物車所有商品
List<Cart> cartList = cartMapper.selectCartByUserId(userId);
// 3 初始化cartProductVoList集合
List<CartProductVo> cartProductVoList = Lists.newArrayList();
// 4 處理浮點計算精度問題BigDecimal
BigDecimal cartTotalPrice = new BigDecimal("0");
// 5 用戶購物車不爲空時
if(CollectionUtils.isNotEmpty(cartList)){
// 6 取出該用戶購物車所有的商品,並放入CartProductVO對象重構
for(Cart cartItem : cartList){
// 6-1 購物車基本信息
CartProductVo cartProductVo = new CartProductVo();
cartProductVo.setId(cartItem.getId());
cartProductVo.setUserId(userId);
cartProductVo.setProductId(cartItem.getProductId());
// 6-2 購物車擴展數據-如商品對應的
Product product = productMapper.selectByPrimaryKey(cartItem.getProductId());
if(product != null){
cartProductVo.setProductMainImage(product.getMainImage());
cartProductVo.setProductName(product.getName());
cartProductVo.setProductSubtitle(product.getSubtitle());
cartProductVo.setProductStatus(product.getStatus());
cartProductVo.setProductPrice(product.getPrice());
cartProductVo.setProductStock(product.getStock());
// 6-2-1限制庫存,防止用戶加入購物車數量超過庫存數量
//並將該數量用於計算購物車總價,保證總價的準確性
int buyLimitCount = 0;
if(product.getStock() >= cartItem.getQuantity()){
//庫存充足的時候
buyLimitCount = cartItem.getQuantity();
cartProductVo.setLimitQuantity(Const.Cart.LIMIT_NUM_SUCCESS);
}else{
//超過庫存,那麼強制用戶加入購物車數量最大就是庫存數量
buyLimitCount = product.getStock();
//同時返回超出庫存提示
cartProductVo.setLimitQuantity(Const.Cart.LIMIT_NUM_FAIL);
//更新購物車中有效數量-確保前後端購物車數量一致性
Cart cartForQuantity = new Cart();
cartForQuantity.setId(cartItem.getId());
cartForQuantity.setQuantity(buyLimitCount);
cartMapper.updateByPrimaryKeySelective(cartForQuantity);
}
// 6-2-2將確認後的購物數量更新給前端,並用於計算商品總價
cartProductVo.setQuantity(buyLimitCount);
// 6-2-3計算當前商品總價
cartProductVo.setProductTotalPrice(BigDecimalUtil.mul(product.getPrice().doubleValue(),cartProductVo.getQuantity()));
cartProductVo.setProductChecked(cartItem.getChecked());
}
if(cartItem.getChecked() == Const.Cart.CHECKED){
//如果已經勾選,增加到整個的購物車總價中
cartTotalPrice = BigDecimalUtil.add(cartTotalPrice.doubleValue(),cartProductVo.getProductTotalPrice().doubleValue());
}
cartProductVoList.add(cartProductVo);
}
}
// 7 數據填充到cartVO對象中
cartVo.setCartTotalPrice(cartTotalPrice);
cartVo.setCartProductVoList(cartProductVoList);
// 是否全選
cartVo.setAllChecked(this.getAllCheckedStatus(userId));
cartVo.setImageHost(PropertiesUtil.getProperty("ftp.server.http.prefix"));
return cartVo;
}
//傳遞userId去購物車數據表查詢是否未被勾選的-有未勾選的則標記爲false
private boolean getAllCheckedStatus(Integer userId){
if(userId == null){
return false;
}
return cartMapper.selectCartProductCheckedStatusByUserId(userId) == 0;
}
Tips:處理科學計算出現的浮點精度問題
處理科學計算浮點型數據是出現的微小精度問題,如價格,在Java中使用BigDecimal的String構造器進行計算,如 BigDecimal a = new BigDecimal("0.5"),然後和另一個String類型的BigDecimal變量進行計算纔不會出現精度錯誤.
Tips:一定是String的BigDecimal類型,如果用默認的依然會出現精度問題-new BigDecimal(5)
BigDecimal工具類-BigDecimalUtil,之後所有的運算都通過這個工具類轉化成BigDecimal進行計算
2.購物車添加商品
參數:productId商品ID,count數量
邏輯:
a-select:添加之前,需要去查詢當前用戶下,該productId是否在當前購物車.如果是空,說明該商品不再購物車,我們就要就該商品新增到購物車中.
b-insert:插入購物車數據表中,要將userId,商品id,數量count,同時設置當前商品的選中狀態checked=1(1是選中狀態);
c-update:如果a步驟查詢的是該商品已在該用戶的購物車中,那麼就是將購物車原有的數量加上現在加入購物車數量,並更新購物車數據表(也可同時將check狀態更新爲1,看需求);
3.更新購物車某個商品的數據量
參數:productId,count
需要更新增商品一樣,去判斷當前購物車是否有該商品
4.移除購物車某個產品
參數:productIds(商品ID可能同時有多個,不需要傳遞數量,直接刪除就好)
5.購物車List列表
參數:無
6.全選/全反選--其實就是更新update操作
參數:無,根據userId查詢全部購物車
Tips:有兩個接口全選接口和全反選接口,即調用全選接口時,後臺統一設置成選中;調用反選接口時,統一設置成不選中.然後在調用獲取全部購物車的list方法,得到最新的購物車數據.
7.單選/單獨反選
參數:productId,相較於上面的全選和不全選就是多了一個productID邏輯一樣
8.查詢當前用戶購物車裏面的產品數量(用於未進入購物車等頁面顯示購物車的數量)
根據產品加入購物車份數的累加
參數:無,查詢當前用戶下
返回:數值
Tips:用戶未登錄,不能報錯,只要返回數值0即可,即這裏判斷session時 不能因爲session.user爲空,就報錯,要返回0.