Java's most complete shopping cart implementation!

Click on "Road to becoming a monkey" above and select "Put to Top Official Account"

Deliver it at the critical moment!

5 minutes to read this article

Link: http://www.cnblogs.com/wang-meng/

Author: romantic flower count

Regarding the shopping cart, here are four questions first:

1) The user does not log in the user name and password, add products, close the browser and open the  user name and password without logging in. Question: Are the products in the shopping cart still there? 

2) The user logs in the user name and password, adds the product, closes the browser and reopens it  without logging in the user name and password. Question: Are the shopping cart products still there?   

3) The user logs in the user name and password, adds the product, closes the browser, and then opens it again. Log in the user name and password.   Q: Are the products in the shopping cart still available?

4) The user logs in the user name and password, adds the product, closes the browser, and opens the browser to   log in the user name and password.  Q: Are the products in the shopping cart still available?

The above four questions are all based on JD.com, so everyone guess what the result is?
1) At
2) No longer
3) At
4)

If you can guess the answer, then you are really good, then how do you achieve these four points? (If you have a disapproved partner, you can use Jingdong Experiment)
Let’s explain the principle of the shopping cart, and finally talk about the specific code implementation.
1) If the user does not log in, add a product, the product at this time is added to the cookie of the browser, so when you visit again When (do not log in), the product is still in the cookie, so the product in the shopping cart still exists.
2) The user logs in and adds the product. At this time, the cookie and the product selected by the user will be added to the shopping cart, and then Delete the product in the Cookie. So when the user visits again (without logging in), the shopping cart product in the Cookie has been deleted at this time, so the product in the shopping cart is no longer there.
3) The user logs in and adds the product. The product is added to the database for persistent storage, and the login user name and password are opened again. The product selected by the user must still exist, so the product in the shopping cart still exists.
4) Reason 3)

Here, let’s talk about not logging in to save the product. The advantages of cookies and the comparison of saving to Session and database:

1: Cookie: Advantages: save the user's browser (don’t waste our company’s server) Disadvantages: Cookie is disabled, save is not provided
2: Session: (Redis: Waste a lot of server memory: implement, disable Cookie) Very fast
3: Database ( Mysql, Redis, SOlr) can persist but the database is too slow,

so what I want to talk about today is:

The user did not log in: the shopping cart was added to the cookie. The
user logged in: saved the shopping cart to Redis (without a database). The

overall idea diagram:


Next is the code example to implement the shopping cart function:
first we look at the shopping cart and shopping items Two JavaBean design:
shopping cart: 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 }

The @JsonIgonre annotation is used here because BuyerCart needs to be converted to Json format below, and these fields have only get methods, so they cannot be converted, and need to be used to ignore Json.

The following is a shopping item: 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. Add the product to the shopping cart

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

 

The parameters passed in here are skuId (the primary key of the inventory table, the product id, color, size, inventory and other information stored in the inventory table), the purchase quantity amount.

Then let's see how the Controller handles it:

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     }

Here is a knowledge point: Convert objects into json strings/json strings into objects.
Let's write a small demo here to demonstrate the mutual conversion between json and objects. Here, the ObjectMapper class in springmvc is used.

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 }

Execution result: 

Here we use Include.NON_NULL. If the attribute in TestTb is null, it will not be converted to Json. From object-->Json string is objectMapper.writeValue(). From Json string-->object The objectMapper.readValue() is used.
Return to the code in our project above, and this product will be added to the Cookie only when you are not logged in to add the product.

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);

We can see from the debug that

the object shopping cart object buyerCart has been converted into Json format. To
add a product to the shopping cart, whether it is logged in or not, you must first take out the shopping cart in the Cookie, and then change the currently selected product Add to the shopping cart.
Then log in to clear the shopping cart in the Cookie, and add the content of the shopping cart to Redis for persistent storage.
If you are not logged in, add the selected product to the Cookie.

Add the shopping cart The code to Redis: insertBuyerCartToRedis (this includes judging whether the added is the same paragraph)

1 //保存购物车到Redis中
 2     public void insertBuyerCartToRedis(BuyerCart buyerCart, String username){
 3         List<BuyerItem> items = buyerCart.getItems();
 4         if (items.size() > 0) {
 5             //redis中保存的是skuId 为key , amount 为value的Map集合
 6             Map<String, String> hash = new HashMap<String, String>();
 7             for (BuyerItem item : items) {
 8                 //判断是否有同款
 9                 if (jedis.hexists("buyerCart:"+username, String.valueOf(item.getSku().getId()))) {
10                     jedis.hincrBy("buyerCart:"+username, String.valueOf(item.getSku().getId()), item.getAmount());
11                 }else {
12                     hash.put(String.valueOf(item.getSku().getId()), String.valueOf(item.getAmount()));
13                 }
14             }
15             if (hash.size() > 0) {
16                 jedis.hmset("buyerCart:"+username, hash);
17             }
18         }
19        
20     }

Determine whether the user is logged in: String username = sessionProviderService.getAttributterForUsername(RequestUtils.getCSessionId(request, response));

1 public class RequestUtils {
 2 
 3     //获取CSessionID
 4     public static String getCSessionId(HttpServletRequest request, HttpServletResponse response){
 5         //1, 从Request中取Cookie
 6         Cookie[] cookies = request.getCookies();
 7         //2, 从Cookie数据中遍历查找, 并取CSessionID
 8         if (null != cookies && cookies.length > 0) {
 9             for (Cookie cookie : cookies) {
10                 if ("CSESSIONID".equals(cookie.getName())) {
11                     //有, 直接返回
12                     return cookie.getValue();
13                 }
14             }
15         }
16         //没有, 创建一个CSessionId, 并且放到Cookie再返回浏览器.返回新的CSessionID
17         String csessionid = UUID.randomUUID().toString().replaceAll("-", "");
18         //并且放到Cookie中
19         Cookie cookie = new Cookie("CSESSIONID", csessionid);
20         //cookie  每次都带来, 设置路径
21         cookie.setPath("/");
22         //0:关闭浏览器  销毁cookie. 0:立即消失.  >0 存活时间,秒
23         cookie.setMaxAge(-1);
24        
25         return csessionid;
26     }
27 }
1 //获取
 2     public String getAttributterForUsername(String jessionId){
 3         String value = jedis.get(jessionId + ":USER_NAME");
 4         if(null != value){
 5             //计算session过期时间是 用户最后一次请求开始计时.
 6             jedis.expire(jessionId + ":USER_NAME", 60*exp);
 7             return value;
 8         }
 9         return null;
10     }

========================================== 2, the shopping cart display page is the
last Go to the shopping cart display page: return "redirect:/shopping/toCart"; There are two ways to enter the settlement page:
1) Click on the product details page to add to the shopping cart.
2) Click the shopping cart button directly to enter the shopping cart settlement page.

Let's take a look at the code of the settlement page:

1 @Autowired
 2     private CartService cartService;
 3     //去购物车结算, 这里有两个地方可以直达: 1,在商品详情页 中点击加入购物车按钮  2, 直接点击购物车按钮
 4     @RequestMapping(value="/shopping/toCart")
 5     public String toCart(Model model, HttpServletRequest request,
 6             HttpServletResponse response) throws JsonParseException, JsonMappingException, IOException{
 7         //将对象转换成json字符串/json字符串转成对象
 8         ObjectMapper om = new ObjectMapper();
 9         om.setSerializationInclusion(Include.NON_NULL);
10         BuyerCart buyerCart = null;
11         //1,获取Cookie中的购物车
12         Cookie[] cookies = request.getCookies();
13         if (null != cookies && cookies.length > 0) {
14             for (Cookie cookie : cookies) {
15                 //
16                 if (Constants.BUYER_CART.equals(cookie.getName())) {
17                     //购物车 对象 与json字符串互转
18                     buyerCart = om.readValue(cookie.getValue(), BuyerCart.class);
19                     break;
20                 }
21             }
22         }
23        
24         //判断是否登录
25         String username = sessionProviderService.getAttributterForUsername(RequestUtils.getCSessionId(request, response));
26         if (null != username) {
27             //登录了
28             //2, 购物车 有东西, 则将购物车的东西保存到Redis中
29             if (null == buyerCart) {
30                 cartService.insertBuyerCartToRedis(buyerCart, username);
31                 //清空Cookie 设置存活时间为0, 立马销毁
32                 Cookie cookie = new Cookie(Constants.BUYER_CART, null);
33                 cookie.setPath("/");
34                 cookie.setMaxAge(-0);
35                 response.addCookie(cookie);
36             }
37             //3, 取出Redis中的购物车
38             buyerCart = cartService.selectBuyerCartFromRedis(username);
39         }
40        
41        
42         //4, 没有 则创建购物车
43         if (null == buyerCart) {
44             buyerCart = new BuyerCart();
45         }
46        
47         //5, 将购物车装满, 前面只是将skuId装进购物车, 这里还需要查出sku详情
48         List<BuyerItem> items = buyerCart.getItems();
49         if(items.size() > 0){
50             //只有购物车中有购物项, 才可以将sku相关信息加入到购物项中
51             for (BuyerItem buyerItem : items) {
52                 buyerItem.setSku(cartService.selectSkuById(buyerItem.getSku().getId()));
53             }
54         }
55        
56         //5,上面已经将购物车装满了, 这里直接回显页面
57         model.addAttribute("buyerCart", buyerCart);
58        
59         //跳转购物页面
60         return "cart";
61     }

Here is the cart details page display, It should be noted that if the same item is added continuously, is to be merged.
Shopping Cart page show details including two blocks, 1) Product Details 2) Total (the total amount of goods, freight)
which 1) The product details also include product size, product color, product purchase quantity, and availability.

Take out the shopping cart in Redis: buyerCart = cartService.selectBuyerCartFromRedis(username);

1     //取出Redis中购物车
 2     public BuyerCart selectBuyerCartFromRedis(String username){
 3         BuyerCart buyerCart = new BuyerCart();
 4         //获取所有商品, redis中保存的是skuId 为key , amount 为value的Map集合
 5         Map<String, String> hgetAll = jedis.hgetAll("buyerCart:"+username);
 6         Set<Entry<String, String>> entrySet = hgetAll.entrySet();
 7         for (Entry<String, String> entry : entrySet) {
 8             //entry.getKey(): skuId
 9             Sku sku = new Sku();
10             sku.setId(Long.parseLong(entry.getKey()));
11             BuyerItem buyerItem = new BuyerItem();
12             buyerItem.setSku(sku);
13             //entry.getValue(): amount
14             buyerItem.setAmount(Integer.parseInt(entry.getValue()));
15             //添加到购物车中
16             buyerCart.addItem(buyerItem);
17         }
18        
19         return buyerCart;
20     }

Fill the shopping cart, just put the skuId into the shopping cart before, here you need to find out the details of the sku: List<BuyerItem> items = buyerCart.getItems();
buyerItem.setSku(cartService.selectSkuById(buyerItem.getSku().getId ()));

1 //向购物车中的购物项 添加相应的数据, 通过skuId 查询sku对象, 颜色对象, 商品对象
2     public Sku selectSkuById(Long skuId){
3         Sku sku = skuDao.selectByPrimaryKey(skuId);
4         //颜色
5         sku.setColor(colorDao.selectByPrimaryKey(sku.getColorId()));
6         //添加商品信息
7         sku.setProduct(productDao.selectByPrimaryKey(sku.getProductId()));
8         return sku;
9     }

Then return to "cart.jsp", this is the shopping cart details display page.

================================================3, Going to the checkout page
here means that the user must log in, and there must be goods in the shopping cart.
So here you need to use the filtering function of springmvc, when the user clicks on the settlement, the user must log in first, if not logged in, the user will be prompted Login required.

1 //去结算
 2     @RequestMapping(value="/buyer/trueBuy")
 3     public String trueBuy(String[] skuIds, Model model, HttpServletRequest request, HttpServletResponse response){
 4         //1, 购物车必须有商品,
 5         //取出用户名  再取出购物车
 6         String username = sessionProviderService.getAttributterForUsername(RequestUtils.getCSessionId(request, response));
 7         //取出所有购物车
 8         BuyerCart buyerCart = cartService.selectBuyerCartFromRedisBySkuIds(skuIds, username);
 9         List<BuyerItem> items = buyerCart.getItems();
10         if (items.size() > 0) {
11             //购物车中有商品
12             //判断所勾选的商品是否都有货, 如果有一件无货, 那么就刷新页面.
13             Boolean flag = true;
14             //2, 购物车中商品必须有库存 且购买大于库存数量时视为无货. 提示: 购物车原页面不动. 有货改为无货, 加红提醒.
15             for (BuyerItem buyerItem : items) {
16                 //装满购物车的购物项, 当前购物项只有skuId这一个东西, 我们还需要购物项的数量去判断是否有货
17                 buyerItem.setSku(cartService.selectSkuById(buyerItem.getSku().getId()));
18                 //校验库存
19                 if (buyerItem.getAmount() > buyerItem.getSku().getStock()) {
20                     //无货
21                     buyerItem.setIsHave(false);
22                     flag = false;
23                 }
24                 if (!flag) {
25                     //无货, 原页面不动, 有货改成无货, 刷新页面.
26                     model.addAttribute("buyerCart", buyerCart);
27                     return "cart";
28                 }
29             }
30         }else {
31             //购物车没有商品
32             //没有商品: 1>原购物车页面刷新(购物车页面提示没有商品)
33             return "redirect:/shopping/toCart";
34         }
35        
36        
37         //3, 正常进入下一个页面
38         return "order";
39     }

Take out the specified shopping cart, because we will check the products we need to buy on the shopping cart details page before we settle, so here is to settle according to the checked products.
BuyerCart buyerCart = cartService.selectBuyerCartFromRedisBySkuIds(skuIds, username);
Take out the specified goods from the shopping cart:

1 //从购物车中取出指定商品
 2     public BuyerCart selectBuyerCartFromRedisBySkuIds(String[] skuIds, String username){
 3         BuyerCart buyerCart = new BuyerCart();
 4         //获取所有商品, redis中保存的是skuId 为key , amount 为value的Map集合
 5         Map<String, String> hgetAll = jedis.hgetAll("buyerCart:"+username);
 6         if (null != hgetAll && hgetAll.size() > 0) {
 7             Set<Entry<String, String>> entrySet = hgetAll.entrySet();
 8             for (Entry<String, String> entry : entrySet) {
 9                 for (String skuId : skuIds) {
10                     if (skuId.equals(entry.getKey())) {
11                         //entry.getKey(): skuId
12                         Sku sku = new Sku();
13                         sku.setId(Long.parseLong(entry.getKey()));
14                         BuyerItem buyerItem = new BuyerItem();
15                         buyerItem.setSku(sku);
16                         //entry.getValue(): amount
17                         buyerItem.setAmount(Integer.parseInt(entry.getValue()));
18                         //添加到购物车中
19                         buyerCart.addItem(buyerItem);
20                     }
21                 }
22             }
23         }
24        
25         return buyerCart;
26     }

1) When only one item of the goods we buy is out of stock, then refresh the shopping cart details page to return the out-of-stock status. 
2) When the shopping cart is noon, refresh the current page. There

are so many things in the shopping cart , There may be missing or wrong points in the explanation, everyone is welcome to point out.

END

Friends who like this article, please click on the picture to follow the subscription account and watch more exciting content!

Recommended reading:

Click to see and then go!

Guess you like

Origin blog.csdn.net/qq_39507327/article/details/103900645