1. 程式人生 > >購物車的原理及實現.(仿京東實現原理)

購物車的原理及實現.(仿京東實現原理)

2017年7月14日更新: 
有很多小夥伴想要專案資料和原始碼, 我重新整理了一份傳了上來: 

這次更新的為專案全套視訊及所有原始碼資料:
連結: https://pan.baidu.com/s/1hseNP9U 密碼: ugey

今天來開始寫一下關於購物車的東西, 這裡首先丟擲四個問題:

1)使用者沒登陸使用者名稱和密碼,新增商品, 關閉瀏覽器再開啟後 不登入使用者名稱和密碼 問:購物車商品還在嗎? 

2)使用者登陸了使用者名稱密碼,新增商品,關閉瀏覽器再開啟後 不登入使用者名稱和密碼 :購物車商品還在嗎?   

3)使用者登陸了使用者名稱密碼,新增商品, 關閉瀏覽器,然後再開啟,登陸使用者名稱和密碼

  :購物車商品還在嗎?

4)使用者登陸了使用者名稱密碼,新增商品, 關閉瀏覽器 外地老家開啟瀏覽器  登陸使用者名稱和密碼 問:購物車商品還在嗎?

上面四個問題都是以京東為模板, 那麼大家猜猜結果是什麼呢?
1)在
2)不在了
3)在
4)在

如果你能夠猜到答案, 那麼說明你真的很棒, 那麼關於這四點是怎麼實現的呢? (如果有不認可的小夥伴可以用京東實驗一下)
下面我們就來講解下購物車的原理,最後再來說下具體的code實現.
1)使用者沒有登入, 新增商品, 此時的商品是被新增到了瀏覽器的Cookie中, 所以當再次訪問時(不登入),商品仍然在Cookie中, 所以購物車中的商品還是存在的.
2)使用者登入了,新增商品, 此時會將Cookie中和使用者選擇的商品都新增到購物車中, 然後刪除Cookie中的商品. 所以當用戶再次訪問(不登入),此時Cookie中的購物車商品已經被刪除了, 所以此時購物車中的商品不在了.
3)使用者登入, 新增商品,此時商品被新增到資料庫做了持久化儲存, 再次開啟登入使用者名稱和密碼, 該使用者選擇的商品肯定還是存在的, 所以購物車中的商品還是存在的.
4)理由3)


這裡再說下 沒登入 儲存商品到Cookie的優點以及儲存到Session和資料庫的對比:


1:Cookie: 優點: 儲存使用者瀏覽器(不用浪費我們公司的伺服器) 缺點:Cookie禁用,不提供儲存
2:Session:(Redis : 浪費大量伺服器記憶體:實現、禁用Cookie) 速度很快
3:資料庫(Mysql、Redis、SOlr) 能持久化的就資料庫 速度太慢

那麼我今天要講的就是:

使用者沒登陸:購物車新增到Cookie中
使用者登陸: 儲存購物車到Redis中 (不用資料庫)

整體的思路圖解:


接下來就是程式碼例項來實現 購物車的功能了:
首先我們看下購物車和購物項兩個JavaBean的設計:
購物車: buyerCart.java

複製程式碼
 1 public class BuyerCart implements
Serializable{ 2 3 /** 4 * 購物車 5 */ 6 private static final long serialVersionUID = 1L; 7 8 //商品結果集 9 private List<BuyerItem> items = new ArrayList<BuyerItem>(); 10 11 //新增購物項到購物車 12 public void addItem(BuyerItem item){ 13 //判斷是否包含同款 14 if (items.contains(item)) { 15 //追加數量 16 for (BuyerItem buyerItem : items) { 17 if (buyerItem.equals(item)) { 18 buyerItem.setAmount(item.getAmount() + buyerItem.getAmount()); 19 } 20 } 21 }else { 22 items.add(item); 23 } 24 25 } 26 27 public List<BuyerItem> getItems() { 28 return items; 29 } 30 31 public void setItems(List<BuyerItem> items) { 32 this.items = items; 33 } 34 35 36 //小計 37 //商品數量 38 @JsonIgnore 39 public Integer getProductAmount(){ 40 Integer result = 0; 41 //計算 42 for (BuyerItem buyerItem : items) { 43 result += buyerItem.getAmount(); 44 } 45 return result; 46 } 47 48 //商品金額 49 @JsonIgnore 50 public Float getProductPrice(){ 51 Float result = 0f; 52 //計算 53 for (BuyerItem buyerItem : items) { 54 result += buyerItem.getAmount()*buyerItem.getSku().getPrice(); 55 } 56 return result; 57 } 58 59 //運費 60 @JsonIgnore 61 public Float getFee(){ 62 Float result = 0f; 63 //計算 64 if (getProductPrice() < 79) { 65 result = 5f; 66 } 67 68 return result; 69 } 70 71 //總價 72 @JsonIgnore 73 public Float getTotalPrice(){ 74 return getProductPrice() + getFee(); 75 } 76 77 }
複製程式碼

這裡使用了@JsonIgonre註解是因為下面需要將BuyerCart 轉換成Json格式, 而這幾個欄位只有get 方法, 所以不能轉換, 需要使用忽略Json.

下面是購物項: buyerItem.java

複製程式碼
 1 public class BuyerItem implements Serializable{
 2 
 3     private static final long serialVersionUID = 1L;
 4 
 5     //SKu物件
 6     private Sku sku;
 7     
 8     //是否有貨
 9     private Boolean isHave = true;
10     
11     //購買的數量
12     private Integer amount = 1;
13 
14     public Sku getSku() {
15         return sku;
16     }
17 
18     public void setSku(Sku sku) {
19         this.sku = sku;
20     }
21 
22     public Boolean getIsHave() {
23         return isHave;
24     }
25 
26     public void setIsHave(Boolean isHave) {
27         this.isHave = isHave;
28     }
29 
30     public Integer getAmount() {
31         return amount;
32     }
33 
34     public void setAmount(Integer amount) {
35         this.amount = amount;
36     }
37 
38     @Override
39     public int hashCode() {
40         final int prime = 31;
41         int result = 1;
42         result = prime * result + ((sku == null) ? 0 : sku.hashCode());
43         return result;
44     }
45 
46     @Override
47     public boolean equals(Object obj) {
48         if (this == obj) //比較地址
49             return true;
50         if (obj == null)
51             return false;
52         if (getClass() != obj.getClass())
53             return false;
54         BuyerItem other = (BuyerItem) obj;
55         if (sku == null) {
56             if (other.sku != null)
57                 return false;
58         } else if (!sku.getId().equals(other.sku.getId()))
59             return false;
60         return true;
61     }
62 }
複製程式碼

1,將商品加入購物車中

1 //加入購物車
2 function  addCart(){
3       //  + skuId
4       window.location.href="/shopping/buyerCart?skuId="+skuId+"&amount="+$("#buy-num").val();
5 }

這裡傳入的引數是skuId(庫存表的主鍵, 庫存表儲存的商品id,顏色,尺碼,庫存等資訊), 購買數量amount.

接著我們來看Controller是如何來處理的:

複製程式碼
 1 //加入購物車
 2     @RequestMapping(value="/shopping/buyerCart")
 3     public <T> String buyerCart(Long skuId, Integer amount, HttpServletRequest request,
 4             HttpServletResponse response) throws JsonParseException, JsonMappingException, IOException{
 5         //將物件轉換成json字串/json字串轉成物件
 6         ObjectMapper om = new ObjectMapper();
 7         om.setSerializationInclusion(Include.NON_NULL);
 8         BuyerCart buyerCart = null;
 9         //1,獲取Cookie中的購物車
10         Cookie[] cookies = request.getCookies();
11         if (null != cookies && cookies.length > 0) {
12             for (Cookie cookie : cookies) {
13                 //
14                 if (Constants.BUYER_CART.equals(cookie.getName())) {
15                     //購物車 物件 與json字串互轉
16                     buyerCart = om.readValue(cookie.getValue(), BuyerCart.class);
17                     break;
18                 }
19             }
20         }
21         
22         //2,Cookie中沒有購物車, 建立購物車物件
23         if (null == buyerCart) {
24             buyerCart = new BuyerCart();
25         }
26         
27         //3, 將當前款商品追加到購物車
28         if (null != skuId && null != amount) {
29             Sku sku = new Sku();
30             sku.setId(skuId);
31             BuyerItem buyerItem = new BuyerItem();
32             buyerItem.setSku(sku);
33             //設定數量
34             buyerItem.setAmount(amount);
35             //新增購物項到購物車
36             buyerCart.addItem(buyerItem);
37         }
38         
39         //排序  倒序
40         List<BuyerItem> items = buyerCart.getItems();
41         Collections.sort(items, new Comparator<BuyerItem>() {
42 
43             @Override
44             public int compare(BuyerItem o1, BuyerItem o2) {
45                 return -1;
46             }
47             
48         });
49         
50         //前三點 登入和非登入做的是一樣的操作, 在第四點需要判斷
51         String username = sessionProviderService.getAttributterForUsername(RequestUtils.getCSessionId(request, response));
52         if (null != username) {
53             //登入了
54             //4, 將購物車追加到Redis中
55             cartService.insertBuyerCartToRedis(buyerCart, username);
56             //5, 清空Cookie 設定存活時間為0, 立馬銷燬
57             Cookie cookie = new Cookie(Constants.BUYER_CART, null);
58             cookie.setPath("/");
59             cookie.setMaxAge(-0);
60             response.addCookie(cookie);
61         }else {
62             //未登入
63             //4, 儲存購物車到Cookie中
64             //將物件轉換成json格式
65             Writer w = new StringWriter();
66             om.writeValue(w, buyerCart);
67             Cookie cookie = new Cookie(Constants.BUYER_CART, w.toString());
68             //設定path是可以共享cookie
69             cookie.setPath("/");
70             //設定Cookie過期時間: -1 表示關閉瀏覽器失效  0: 立即失效  >0: 單位是秒, 多少秒後失效
71             cookie.setMaxAge(24*60*60);
72             //5,Cookie寫會瀏覽器
73             response.addCookie(cookie);
74         }
75         
76         //6, 重定向
77         return "redirect:/shopping/toCart";
78     }
複製程式碼

這裡設計一個知識點: 將物件轉換成json字串/json字串轉成物件
我們在這裡先寫一個小的Demo來演示json和物件之間的互轉, 這裡使用到了springmvc中的ObjectMapper類.

複製程式碼
 1 public class TestJson {
 2 
 3     @Test
 4     public void testAdd() throws Exception {
 5         TestTb testTb = new TestTb();
 6         testTb.setName("范冰冰");
 7         ObjectMapper om = new ObjectMapper();
 8         om.setSerializationInclusion(Include.NON_NULL);
 9         //將物件轉換成json字串
10         Writer wr = new StringWriter();
11         om.writeValue(wr, testTb);
12         System.out.println(wr.toString());
13         
14         //轉回物件
15         TestTb r = om.readValue(wr.toString(), TestTb.class);
16         System.out.println(r.toString());
17     }
18     
19 }
複製程式碼

執行結果: 

這裡我們使用了Include.NON_NULL, 如果TestTb 中屬性為null 的就不給轉換成Json, 從物件-->Json字串  用的是 objectMapper.writeValue(). 從Json字串-->物件使用的是objectMapper.readValue().
迴歸上面我們專案中的程式碼, 只有未登入 新增商品時才會將此商品新增到Cookie中.

複製程式碼
 1 //未登入
 2             //4, 儲存購物車到Cookie中
 3             //將物件轉換成json格式
 4             Writer w = new StringWriter();
 5             om.writeValue(w, buyerCart);
 6             Cookie cookie = new Cookie(Constants.BUYER_CART, w.toString());
 7             //設定path是可以共享cookie
 8             cookie.setPath("/");
 9             //設定Cookie過期時間: -1 表示關閉瀏覽器失效  0: 立即失效  >0: 單位是秒, 多少秒後失效
10             cookie.setMaxAge(24*60*60);
11             //5,Cookie寫會瀏覽器
12             response.addCookie(cookie);
複製程式碼

我們debug 可以看到:

這裡已經將物件購物車物件buyerCart轉換成了Json格式.
將商品新增到購物車, 不管是登入還是未登入, 都要先取出Cookie中的購物車, 然後將當前選擇的商品追加到購物車中.
然後登入的話  就把Cookie中的購物車清空, 並將購物車的內容新增到Redis中做持久化儲存.
如果未登入, 將選擇的商品追加到Cookie中.

將購物車追加到Redis中的程式碼:insertBuyerCartToRedis(這裡麵包含了判斷新增的是否是同款)

 View Code

判斷使用者是否登入: String username = sessionProviderService.getAttributterForUsername(RequestUtils.getCSessionId(request, response));

 View Code  sessionProviderService


==========================================2,購物車展示頁面
最後 重定向到購物車展示頁: return "redirect:/shopping/toCart"; 這裡進入結算頁有兩種方式:
1) 在商品詳情頁 點選加入購物車.
2) 直接點選購物車按鈕 進入購物車結算頁.


下面來看下結算頁的程式碼:

複製程式碼

相關推薦

購物車原理實現.(仿京東實現原理)

2017年7月14日更新:  有很多小夥伴想要專案資料和原始碼, 我重新整理了一份傳了上來:  這次更新的為專案全套視訊及所有原始碼資料: 連結: https://pan.baidu.com/s/1hseNP9U 密碼: ugey 今天來開始寫一下關於購物車的東西,

購物車實現原理(仿京東實現原理)

關於購物車的東西, 這裡首先丟擲四個問題: 1)使用者沒登陸使用者名稱和密碼,新增商品, 關閉瀏覽器再開啟後 不登入使用者名稱和密碼 問:購物車商品還在嗎?  2)使用者登陸了使用者名稱密碼,新增商品,關閉瀏覽器再開啟後 不登入使用者名稱和密碼 問:購物車商品還在嗎?  

RAID原理軟RAID的實現方式

rand mdadm 磁盤陣列 軟raid 共享熱備盤   1. 什麽是RAID  2. RAID的實現方式  3. RAID的級別及特點  4. 軟RAID的實現方式 1. 什麽是RAID ??RAID全稱

LSI(LSA)潛在語義索引原理sklearn中的實現

想要了解潛在語義索引的原理推薦以下三個連結,仔細看下就能基本掌握LSI的原理: 1.文字主題模型之潛在語義索引(LSI) 2.奇異值分解(SVD)原理與在降維中的應用 3.latent semantic analysis via the singular value decompos

BT Tracker的原理.Net Core簡單實現Tracker Server

最近很忙,自上次Blog被盜 帖子全部丟失後也很少時間更新Blog了,閒暇在外國站點查閱資料正好看到一些Tracker 的協議資料,也就今天記錄並實踐了下,再次分享給大家希望可以幫到需要的小夥伴。 首先我們來了解下BT Tracker 一、做種       現在

順序表的刪除操作原理C語言完整實現

前面講過,順序表的實現使用的是陣列,換句話說,順序表中刪除元素問題可以轉換成如何在陣列中實現刪除元素的操作。 在陣列中刪除元素時,只需將該元素所在位置後的所有資料元素整體前移 1 個位置即可。因為前移的過程中,被刪除元素會被後一個元素覆蓋掉,間接實現了刪除元素的目的。 實現程式碼: table delTa

Adaboost原理簡單的Python實現

原理 Adaboost原理方面網上早已汗牛充棟,李航的《統計學習方法》中寫的簡單易懂,這裡直接搬過來。 即每次訓練一個弱分類器,之後為每個弱分類器分錯的樣本增大權重,為每個分對的樣本減少權重,然後訓練新的分類器。最後對分類器進行加權平均。 實現 這裡直接採用李航書中

FIR濾波器和IIR濾波器原理Xilinx System Generator實現

1.FIR數字濾波器 有限衝激響應(FIR)濾波器是對N個取樣資料執行加權和平均的處理。處理過程公式為: 如三抽頭FIR濾波器結構: 一個低通濾波器結構: 設計濾波器就是選取合適的濾波器係數W,使濾波器達到設計的要求。 一階微分濾波器結構: 當低頻

【演算法學習】AVL平衡二叉搜尋樹原理各項操作程式設計實現(C++)

AVLTree即(Adelson-Velskii-Landis Tree),是加了額外條件的二叉搜尋樹。其平衡條件的建立是為了確保整棵樹的深度為O(nLogn)。平衡條件是任何節點的左右子樹的高度相差不超過1. 在下面的程式碼中,程式設計實現了AVL樹的建立、查詢、插入、

[C++][執行緒池][完整實現] 轉:執行緒池原理建立(C++實現

文章的主要框架是參考這篇文件的,http://jacky-dai.iteye.com/blog/1090285, 關於作者  張中慶,西安交通大學軟體所,在讀碩士,目前研究方向為分散式網路與移動中介軟體,對Linux極其愛好,可以通過[email protecte

梯度下降原理線性迴歸程式碼實現(python/java/c++)

“梯度下降”顧名思義通過一步一步迭代逼近理想結果,當達到一定的精度或者超過迭代次數才退出,所以所獲得的結果是一個近似值。在其他部落格上面基本都有一個通俗的比喻:從山頂一步步下山。下面將用到幾個概念: - 步長:移動一步的長度。 - 維度:一個空間的表示方式,

Android Plugin插樁式實現外掛化開發(一)-實現原理Activity外掛化實現

1. 前言在現在一些大型的Android應用中都採用了外掛化的開發方式,比如美團,支付寶及我們常用的微信等採用了插修的化的開發方式來進行開發的,既然國內一流的網際網路公司都採用這樣的方式來開發那它一定能帶給開發部署大型應用帶來很大的便捷,那麼外掛化的優勢在哪裡呢?1.1 外掛

Socket介面原理用C#語言實現

首先從原理上解釋一下采用Socket介面的網路通訊,這裡以最常用的C/S模式作為範例,首先,服務端有一個程序(或多個程序)在指定的埠等待客戶來連線,服務程式等待客戶的連線資訊,一旦連線上之後,就可以按設計的資料交換方法和格式進行資料傳輸。客戶端在需要的時刻發出向服務端的連

快速排序演算法原理java遞迴實現

快速排序 對氣泡排序的一種改進,若初始記錄序列按關鍵字有序或基本有序,蛻化為氣泡排序。使用的是遞迴原理,在所有同數量級O(n longn) 的排序方法中,其平均效能最好。就平均時間而言,是目前被認為最好的一種內部排序方法基本思想是:通過一躺排序將要排序的資料分割成獨立的兩部

DIV+CSS實現仿京東商城導航條效果

1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 2 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 3 <html xml

使用Recyclerview實現仿京東分類

主佈局 ​​​​ <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"   &n

popwin實現仿京東 商品列表 彈窗 條件篩選 列表彈窗

有需求就有加班寫一個仿照京東的條件篩選彈窗,按道理講 Drawerlayout, dialog  ,彈窗activity  ,popwin  都可以實現的,看自己擅長什麼,或者專案適合什麼 就用什麼寫就OK;我是選擇用popwin寫的, 因為正好之前別的寫了彈窗選擇的對話方塊

Android 實現GridView的橫向滾動,實現仿京東秒殺效果

實現GridView的橫向滾動 效果如下圖: 具體實現的程式碼 1. 主介面佈局程式碼:activity_main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:and

hibernate工作原理作用 JAVA Hibernate工作原理為什麼要用

轉載自 http://www.cnblogs.com/dashi/p/3597969.html#commentform JAVA Hibernate工作原理及為什麼要用 hibernate 簡介:hibernate是一個開源框架,它是物件關聯關係對映的框架,它對JDBC做了輕量級的封裝,而我們j

瀏覽器渲染原理解剖瀏覽器內部工作原理

1、簡單地說,頁面渲染就是瀏覽器將html程式碼根據CSS定義的規則顯示在瀏覽器視窗中的這個過程。先來大致瞭解一下瀏覽器都是怎麼工作的:   1. 使用者輸入網址(假設是個html頁面,並且是第一次訪問),瀏覽器向伺服器發出請求,伺服器返回html檔案;   2.