本文原地址来自于我的个人博客: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 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 findCartsByUserId(int userId) {
List 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 findCartsByProductIds(int userId, List ids) {
List vos = new ArrayList<>();
if(ids.size() !=0){
vos = dao.findCartsByProductIds(userId, ids);
}
return vos;
}
@Override
public List findCartsByProductIds(String jsons) {
if(jsons == null ||"".equals(jsons.trim())){
return new ArrayList();
}
List cartJsons = jsonToList(jsons);
List productIds = new ArrayList<>();
for(CartJson json : cartJsons){
productIds.add(json.getProductId());
}
Map maps = productService.getSimpleProductByIds(productIds);
List 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 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 jsonToList(String jsons){
jsons = jsons.replace("THX", "");
jsons = jsons.substring(0, jsons.lastIndexOf(",")) +"]";
ObjectMapper mapper = new ObjectMapper();
List cartJsons = new ArrayList<>();
try {
cartJsons = mapper.readValue(jsons, new TypeReference>() {});
} 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"%>
Insert title here
在网络上看到一个购物车系统描述的比较好的图,贴出来大家可以参考:
以上总结算是自己对购物车的一点处理理解吧,如果有任何的问题,请大家指正!