本文原地址来自于我的个人博客:www.endless365.com,希望得到各位的关注。
本文详细地址出自于:http://www.endless365.com/article/get?type=tec&id=150
购物车是一个比较复杂的系统,一般会和订单、商品、库存、会员、促销等模块有关系,按照电子商城的功能需求,购物车模块可大可小,所以按照功能需求做的同时考虑后期的扩展,以下对一个比较简单购物车进行初步分析,如果有什么问题或者愿意和我交流的,请联系评论或者email我,我的email是[email protected]。
我从几个方面去分析:
1、什么是购物车。
2、购物车的入口。
3、购物车的出口。
4、购物车的状态和管理。
5、购物车的存储。
1、购物车
简单的理解,方便用户将自己心仪的商品放在一个可展示和保存的集合里面,在选购完以后用于集中处理购买。
2、购物车的入口
作为电子商务网站,最重要的目的就是诱导顾客购买自己的产品,所以恰当的购物车入口是非常重要的,常见的购物车入口有:商品详情页面、收藏夹页面、推荐商品页面、以购买成功的订单页面、已取消订单商品的页面、排行推荐的页面等。
3、购物车的出口
常见的购物车出口有:结算、删除、加入收藏等
4、购物车的状态和管理
状态:
登陆前购物车
价格,数量,是否过期,是否存在库存等
登陆后购物车
价格,数量,折扣,优惠券,是否过期,是否存在库存等
管理:
可以通过下图来表示:
5、购物车的存储。
在对购物车的代码实现方面这一块非常的重要。
按照我的里面,我将购物车分为登陆前购物车、登陆后购物车和登陆后两种购物车的合并。
对于存储当然就存在以下几个比较常见的疑问:
1、加入购物车后的商品,等到第二次登陆该网站的时候,商品却消失了?
2、为什么我还一台电脑,购物车的商品却没有了?
3、我没有往购物车添加商品,为什么我的购物车里面有了商品?
4、我在网站上将商品添加到了购物车,我下次登陆,或者更换电脑登陆是否同样能够看到我加入购物车的东西,不管我是否加入购物车有没有登陆?
......
根据以上几种疑问衍生出购物车商品的存储。
cookie存储,会话session存储,本地存储,数据库存储,本地数据库存储。
针对这些存储介绍一下他们的特点。
cookie存储:
大多数浏览器支持最大为 4096 字节的 Cookie;
浏览器还限制站点可以在用户计算机上存储的 Cookie 的数量。大多数浏览器只允许每个站点存储 20 个 Cookie;
如果试图存储更多 Cookie,则最旧的 Cookie 便会被丢弃。有些浏览器还会对它们将接受的来自所有站点的 Cookie 总数作出绝对限制,通常为 300 个;
Cookie默认情况都会随着Http请求发送到后台服务器,但并不是所有请求都需要Cookie的,比如:js、css、图片等请求则不需要cookie;
Cookie可以通过一些设置来管理他的过期时间等,一旦过期,所保存的信息将丢失
浏览器有可能禁止cookies。
会话session存储:
所有保存的信息都存放在session当中,一旦会话结束,下次再次登陆网站,保存信息将丢失
本地存储:
会话级别本地存储sessionStorage和永久本地存储localStorage
sessionStorage:通过此对象可以直接操作存储在浏览器中的会话级别的WebStorage。存储在sessionStorage中的数据首先是Key-Value形式的,另外就是它跟浏览器当前会话相关,当会话结束后,数据会自动清除,跟未设置过期时间的Cookie类似。
localStorage:便于用户存储永久存储的Web端的数据。而且数据不会随着Http请求发送到后台服务器,而且存储数据的大小机会不用考虑,因为在HTML5的标准中要求浏览器至少要支持到4MB.所以,这完全是颠覆了Cookie的限制,为Web应用在本地存储复杂的用户痕迹数据提供非常方便的技术支持。
数据库存储:
将所有的信息都存储在服务器数据库中,该种方式购物车信息被永久存储,但是需要额外的表进行存储并需要和服务器频繁的打交道。
本地数据库存储:
Html5提供了一个浏览器端的数据库支持,允许我们直接通JS的API在浏览器端创建一个本地的数据库,而且支持标准的SQL的CRUD操作,让离线的Web应用更加方便的存储结构化的数据。
根据这次开发的功能,我选择了localStorage来保存登陆前的购物车。
首先简单的介绍一下localStroage的使用:
localStorage存储数据类似于key-value形式,提供了四个方法来辅助我们进行对本地存储做相关操作。
(1)setItem(key,value):添加本地存储数据。两个参数,非常简单就不说了。
(2)getItem(key):通过key获取相应的Value。
(3)removeItem(key):通过key删除本地数据。
(4)clear():清空数据。
由于在开发过程中使用了百度ueditor进行商品信息的编辑,发现ueditor也将一些缓存信息和配置等放在了localStroage中,所以对于购物车的商品信息和其他应用存放在localStroage导致一些混淆,以至于localStorage不能只被购物车所使用,所有考虑了两种方法出去处理,一种是将购物车封装成一个独有key和数据value进行处理,这样所有的购物车信息都只存在于这个独有key的value中;另外一种方式就是给每一个购物车的key加上特有的标识,这样通过标识可以唯一的获取到购物车的信息。
以下是我对localStorage的一些操作。
//获取本地购物车的json字符串 function getLocalCartParam(){ var param = "["; var storage = window.localStorage; for (var i = 0, len = storage.length; i < len; i++) { var key = storage.key(i); if(key.indexOf("THX") == -1){ continue; } var item = storage.getItem(key); param += ("{\"productId\":" + key + ",\"count\":" + item + "},"); } param += "]"; return param; } //获取本地购物车的数量 function getLocalCartCount(){ var storage = window.localStorage; var count = 0; for (var i = 0, len = storage.length; i < len; i++) { var key = storage.key(i); if(key.indexOf("THX") != -1){ count ++; } } return count; } //保存商品到购物车中 function setLocalCart(productId){ var storage = window.localStorage; var bl = true; var tempProductId = "THX"+productId; for (var i = 0, len = storage.length; i < len; i++) { var key = storage.key(i); if (tempProductId == key) { var value = storage.getItem(key); localStorage.setItem(tempProductId, parseInt(value) + 1); bl = false; break; } } if (bl) { localStorage.setItem(tempProductId, 1); } var count = getLocalCartCount(); setCartNumber(count); }
登陆后,所有的购物车信息存储到数据库中
以下代码是对于购物车管理的serviceImpl的实现简单代码
package com.liveman.shop.service.impl; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.annotation.Resource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.liveman.shop.dao.order.CartMapper; import com.liveman.shop.entity.order.Cart; import com.liveman.shop.entity.order.CartJson; import com.liveman.shop.entity.order.CartVO; import com.liveman.shop.entity.product.Product; import com.liveman.shop.global.DateTool; import com.liveman.shop.service.CartService; import com.liveman.shop.service.ProductService; /** * * @author sunny * */ @Component("cartService") public class CartServiceImpl implements CartService{ @Resource CartMapper dao; @Autowired ProductService productService; @Override public int insertCart(Cart cart) { Cart temp = dao.findCartByProductId(cart); if(temp != null){ int productCount = temp.getProductCount(); temp.setProductCount(productCount+cart.getProductCount()); dao.updateCartById(temp); }else{ dao.insertCart(cart); } int count = dao.findCartCount(cart.getUserId()); return count; } @Override public void deleteCartByIds(List<Integer> ids) { if(ids.size()!=0){ dao.deleteCartByIds(ids); } } @Override public void updateCartById(int id, int count) { Cart temp = dao.findCartById(id); temp.setProductCount(count); dao.updateCartById(temp); } @Override public List<CartVO> findCartsByUserId(int userId) { List<CartVO> carts = dao.findCartsByUserId(userId); return carts; } @Override public void deleteAllCartsByUserId(int userId) { dao.deleteAllCartsByUserId(userId); } @Override public int getCartCount(int userId) { int count = dao.findCartCount(userId); return count; } @Override public List<CartVO> findCartsByProductIds(int userId, List<Integer> ids) { List<CartVO> vos = new ArrayList<>(); if(ids.size() !=0){ vos = dao.findCartsByProductIds(userId, ids); } return vos; } @Override public List<CartVO> findCartsByProductIds(String jsons) { if(jsons == null ||"".equals(jsons.trim())){ return new ArrayList<CartVO>(); } List<CartJson> cartJsons = jsonToList(jsons); List<Integer> productIds = new ArrayList<>(); for(CartJson json : cartJsons){ productIds.add(json.getProductId()); } Map<Integer,Product> maps = productService.getSimpleProductByIds(productIds); List<CartVO> vos = new ArrayList<>(); for(CartJson json : cartJsons){ CartVO vo = new CartVO(); Cart cart = new Cart(); cart.setProductId(json.getProductId()); cart.setProductCount(json.getCount()); vo.setCart(cart); vo.setProduct(maps.get(json.getProductId())); vos.add(vo); } return vos; } @Override public void mergeCart(int userId,String jsons) { if(jsons == null ||"".equals(jsons.trim())){ return; } List<CartJson> cartJsons = jsonToList(jsons); Cart cart = new Cart(); for(CartJson json : cartJsons){ cart.setCreateTime(DateTool.getCurrentDateCN()); cart.setUserId(userId); cart.setProductCount(json.getCount()); cart.setProductId(json.getProductId()); insertCart(cart); } } private List<CartJson> jsonToList(String jsons){ jsons = jsons.replace("THX", ""); jsons = jsons.substring(0, jsons.lastIndexOf(",")) +"]"; ObjectMapper mapper = new ObjectMapper(); List<CartJson> cartJsons = new ArrayList<>(); try { cartJsons = mapper.readValue(jsons, new TypeReference<List<CartJson>>() {}); } catch (Exception e) { e.printStackTrace(); } return cartJsons; } }
当用户登录的时候,牵扯到了未登录购物车和登陆购物车的合并,当用户登录后,将未登录购物车里面的信息合并到用户登录后购物车中,成功以后,清除localStorage里面的购物车信息。
我的实现思路是当数据合并后,通过springmvc的转向跳转到前台清理页面,清理完成以后跳转到需要的页面。
后台跳转代码: @RequestMapping(value = "/login", method = RequestMethod.POST) public ModelAndView login(HttpSession session, String email, String password,String hiddenCarts) { ReturnStatus rs = userService.login(email, password); if (rs.getCode() == 1) { User user = (User) rs.getUserData(); session.setAttribute("user", user); cartService.mergeCart(user.getId(), hiddenCarts); ModelAndView m = new ModelAndView("order/clearTempCart"); m.addObject("count",cartService.getCartCount(user.getId())); return m ; } else { ModelAndView m = new ModelAndView("login"); m.addObject("email", email); m.addObject("password", password); m.addObject("errorMessage", "邮箱或者密码不正确"); return m; } } 前台清理: <%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <script src="../js/jquery.min.js"></script> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Insert title here</title> <script> $(document).ready(function() { localStorage.clear(); location.href="/Shop"; }); </script> </head> <body> </body> </html>
在网络上看到一个购物车系统描述的比较好的图,贴出来大家可以参考:
以上总结算是自己对购物车的一点处理理解吧,如果有任何的问题,请大家指正!