电商项目day16(购物车实现)
今日目标:
理解购物车的思路
购物车登陆后存储到redis中
一.需求分析
数据结构分析:
购物车与商家相关联
我们由京东的案列,就是可以看出,不登录,也可以实现购物车的添加,不过天猫不可以,必须登陆后才能进行,添加到购物车
购物车列表中有多个购物车:[
京东自营(购物车对象){
商家id, sellerId
商家名称:sellerName
购物车商品明细列表:
[
购物车明细对象(展示商品信息){
荣耀9i
华为p20
}
]
}
疆界互联旗舰店:[
和京东自营存储数据结构相同
]
]
上面就是常用的购物车的存储结构
二.实现思路以及解决方案
添加商品到购物车,登陆和未登陆都能实现添加购物车
未登陆时:
1.存储到cookie中,这个方法有个弊端,就是只能存4kb
2.localStorge 储存能达到5kb 是基于html5存储数据对象的
JSON.stringify();
JSON.parse();
3.缓存到redis中作为key-value储存
登陆后:
1.缓存到redis中
登陆后:用户名 作为redis存储购物车的可以
登陆后将购物车列表中的商品提交生成订单后,在清除购物车中的数据
三.未登陆时,购物车功能实现
首先搭建购物车的工程 cart_web cart_service cart_interface
工程搭建完毕,分析后端添加购物车的逻辑思路:
非常重要:
首先根据商品的id查询 该商家是否存在于购物车中
1.商家对应的购物车不存在,购物车列表中
创建购物车对象,在存入购物车列表中
创建购物车对象时,指定该购物车的商家信息,以及构建购物车明细对象和购物车明细列表
将购物车的明细对象添加到购物车明细列表中,将购物车明细列表添加到购物车对象,在将
购物车对象添加到购物车列表中
2.商家对应的购物车对象存在于购物车列表中
判断该商品是否存在于该购物车商品的明细列表中
1.如果该商品不存在购物车明细列表中
则创建购物车明细对象,在添加到购物车明细里列表中
2.如果该商品存在购物车明细列表中
修改购物车明细对象的数量和小计金额
首先我们先编写未登陆时,的接口方法
/*** 添加商品到购物车*/public List<Cart> addItemToCartList(List<Cart> cartList, Long itemId, Integer num);/*** 根据sessionId获得购物车列表* @param sessionId* @return*/List<Cart> selectCartListFromRedis(String sessionId);/*** 保存该sessionid 的 cartList 购物车列表* @param sessionId* @param cartList*/void saveCartListToRedis(String sessionId, List<Cart> cartList);/*** 合并添加前购物车的数据到登陆后的购物车列表* @param cartList_sessionId* @param cartList_username* @return*/List<Cart> mergeCartList(List<Cart> cartList_sessionId, List<Cart> cartList_username);/*** 删除之前未登陆的购物车的列表数据* @param cartList_sessionId*/void deleteCartList(List<Cart> cartList_sessionId);
service实现的所有的功能,主要是:购物车的添加,以及通过sessionid获取购物车列表,还有就是,未登陆时,购物车列表的数据,在登陆后会跟新到redis数据库中,通过username的作为key值保存,然后删除登陆前购物车的数据
package com.pinyougou.cart.service.impl;import com.alibaba.dubbo.config.annotation.Service;
import com.pinyougou.cart.service.CartService;
import com.pinyougou.groupentity.Cart;
import com.pinyougou.mapper.TbItemMapper;
import com.pinyougou.pojo.TbItem;
import com.pinyougou.pojo.TbOrderItem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;@Service
@Transactional
public class CartServiceImpl implements CartService {@Autowiredprivate TbItemMapper itemMapper;@Autowiredprivate RedisTemplate redisTemplate;/*** 添加商品到购物车* @param cartList* @param itemId* @param num* @return* 首先根据商品的id查询 该商家是否存在于购物车中1.商家对应的购物车不存在,购物车列表中创建购物车对象,在存入购物车列表中创建购物车对象时,指定该购物车的商家信息,以及构建购物车明细对象和购物车明细列表将购物车的明细对象添加到购物车明细列表中,将购物车明细列表添加到购物车对象,在将购物车对象添加到购物车列表中2.商家对应的购物车对象存在于购物车列表中判断该商品是否存在于该购物车商品的明细列表中1.如果该商品不存在购物车明细列表中则创建购物车明细对象,在添加到购物车明细里列表中2.如果该商品存在购物车明细列表中修改购物车明细对象的数量和小计金额*/@Overridepublic List<Cart> addItemToCartList(List<Cart> cartList, Long itemId, Integer num) {//首先根据商品的id查询 该商家是否存在于购物车中TbItem item = itemMapper.selectByPrimaryKey(itemId);//优化操作,添加购物车的时候,刚好该商品下架了if(item==null){throw new RuntimeException("商品不存在");}//如果商品的状态不为1则无效if (!item.getStatus().equals("1")){throw new RuntimeException("商品无效");}String sellerId = item.getSellerId();//在购物车列表中基于商品id 查询购物车对象Cart cart = searchCartBySellerId(cartList,sellerId);//判断购物车是否在空if (cart==null){//购物车为空//创建购物车对象,cart = new Cart();//指定该购物车的商家信息,以及构建购物车明细对象和购物车明细列表cart.setSellerId(sellerId);cart.setSellerName(item.getSeller());//以及构建购物车明细对象和购物车明细列表List<TbOrderItem> orderItemList = new ArrayList<>();//构建商品明细对象TbOrderItem orderItem = createOrderItem(item,num);//购物车的明细对象添加到购物车明细列表中orderItemList.add(orderItem);//购物车明细列表添加到购物车对象cart.setOrderItemList(orderItemList);//购物车对象添加到购物车列表中cartList.add(cart);}else{//该商品的存在//先通过购物车获取当前购物车的商品明细对象List<TbOrderItem> orderItemList = cart.getOrderItemList();//判断该商品是否存在于该购物车商品的明细列表中TbOrderItem orderItem = searchOrderIdByItemId(orderItemList,itemId);if (orderItem==null){//在商品列表中不存在//如果该商品不存在购物车明细列表中//则创建购物车明细对象,在添加到购物车明细里列表中orderItem = createOrderItem(item,num);//在添加到购物车明细里列表中orderItemList.add(orderItem);}else{//存在于商品列表中//修改购物车明细对象的数量和小计金额orderItem.setNum(orderItem.getNum()+num);//小计金额orderItem.setTotalFee(new BigDecimal(orderItem.getPrice().doubleValue()*orderItem.getNum()));//如果商品数量小于1 则删除该商品if(orderItem.getNum()<1){orderItemList.remove(orderItem);}//如果购物车商品明细列表中没有商品了, 则直接从购物车里列表中移除if (orderItemList.size()<=0){cartList.remove(cart);}}}return cartList;}//判断该商品是否存在于该购物车商品的明细列表中private TbOrderItem searchOrderIdByItemId(List<TbOrderItem> orderItems, Long itemId) {for (TbOrderItem orderItem : orderItems) {if(orderItem.getItemId().longValue()==itemId.longValue()){//存在商品列表中return orderItem;}}return null;}//创建商品的明细对象private TbOrderItem createOrderItem(TbItem item, Integer num) {//优化操作//创建商品的数量如果为负数if(num<1){throw new RuntimeException("新添加商品到购物车,商品数量不能小于1");}/*`item_id` bigint(20) NOT NULL COMMENT '商品id',`goods_id` bigint(20) DEFAULT NULL COMMENT 'SPU_ID',`title` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '商品标题',`price` decimal(20,2) DEFAULT NULL COMMENT '商品单价',`num` int(10) DEFAULT NULL COMMENT '商品购买数量',`total_fee` decimal(20,2) DEFAULT NULL COMMENT '商品总金额',`pic_path` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '商品图片地址',`seller_id` varchar(100) COLLATE utf8_bin DEFAULT NULL,*/TbOrderItem orderItem = new TbOrderItem();orderItem.setItemId(item.getId());orderItem.setGoodsId(item.getGoodsId());orderItem.setTitle(item.getTitle());orderItem.setPrice(item.getPrice());orderItem.setNum(num);orderItem.setTotalFee(new BigDecimal(item.getPrice().doubleValue()*num));orderItem.setPicPath(item.getImage());orderItem.setSellerId(item.getSellerId());return orderItem;}//根据商品的id查询是否存在购物车对象private Cart searchCartBySellerId(List<Cart> cartList, String sellerId) {for (Cart cart : cartList) {if (cart.getSellerId().equals(sellerId)){return cart;}}return null;}//通过sessionid获得购物车列表@Overridepublic List<Cart> selectCartListFromRedis(String sessionId) {//从redis中获取List<Cart> cartList = (List<Cart>) redisTemplate.boundValueOps(sessionId).get();//判断cartList是否为空,因为你要返回一个list列表,如果为空,前台就不能通过fastJson解析了if (cartList==null){//为空我们可以直接从新创建一个新的arrayListcartList = new ArrayList<>();}return cartList;}//保存购物车列表到redis中@Overridepublic void saveCartListToRedis(String sessionId, List<Cart> cartList) {redisTemplate.boundValueOps(sessionId).set(cartList,7L, TimeUnit.DAYS);}//合并登陆前购物车的数据到登陆后的购物车数据中@Overridepublic List<Cart> mergeCartList(List<Cart> cartList_sessionId, List<Cart> cartList_username) {//注意我们只需要构建我们需要添加的数据,因为我们在上面已经做过判断,我们只需要,拼装数据即可for (Cart cart : cartList_sessionId) {//获取购车列表List<TbOrderItem> itemList = cart.getOrderItemList();for (TbOrderItem orderItem : itemList) {//获取num和ItemId的值Integer num = orderItem.getNum();Long itemId = orderItem.getItemId();//购物车列表我们直接用登陆的就可以了cartList_username= addItemToCartList(cartList_username,itemId,num);}}return cartList_username;}//删除登陆前购物车的数据@Overridepublic void deleteCartList(List<Cart> cartList_sessionId) {redisTemplate.delete(cartList_sessionId);}
}
controller层:
思路分析:我们主要做两件事 1.购物车列表数据的展示 2.添加商品到购物车列表中 还有一个非常重要就是获取sessionid的方法,我们浏览器的存在的cookie是一次会话,我们想要用户的商品存储一周,我们必须后台进行,重新创建cookie,设置为一周过期,通过一个工具类
CookieUtil来获取和存储
@RestController
@RequestMapping("/cart")
public class CartController {@Autowiredprivate HttpSession session;@Autowiredprivate HttpServletRequest request;@Autowiredprivate HttpServletResponse response;@Referenceprivate CartService cartService;/*** 获得sessionid的方法*/private String getSessionId(){//先尝试从"cartCookie"中获得sessionId信息String sessionId = CookieUtil.getCookieValue(request, "cartList", "utf-8");if (sessionId==null){//在从浏览器中获取sessionidsessionId = session.getId();//将浏览器获取的sessionId保存一周CookieUtil.setCookie(request,response,"cartList",sessionId,3600*24*7,"utf-8");}return sessionId;}/*** 展示购物车列表数据*/@RequestMapping("/findCartList")public List<Cart> findCartList(){//获取登陆人用户名String username = SecurityContextHolder.getContext().getAuthentication().getName();//未登陆时,基于sessionid从redis中获取购物车数据列表String sessionId = getSessionId();//从redis中获取List<Cart> cartList_sessionId = cartService.selectCartListFromRedis(sessionId);if ("anonymousUser".equals(username)){//未登陆System.out.println("selectCartListFromRedis by sessionId....");return cartList_sessionId;}else{//已登录System.out.println("selectCartListFromRedis by username....");List<Cart> cartList_username = cartService.selectCartListFromRedis(username);//用户登录前,如果已经添加商品到购物车列表中。if(cartList_sessionId!=null&&cartList_sessionId.size()>0){//说明添加前已经存在商品了//登陆后,将登陆前的购物车列表数据合并到登陆后的购物车列表中cartList_username = cartService.mergeCartList(cartList_sessionId,cartList_username);//将合并后的结果从新放到缓存中cartService.saveCartListToRedis(username,cartList_username);//清除合并前的购物车列表数据cartService.deleteCartList(cartList_sessionId);}return cartList_username;}}/*** 添加商品到购物车*/@RequestMapping("/addItemToCartList")public Result addItemToCartList(Long itemId, Integer num){try {//获取登陆人用户名String username = SecurityContextHolder.getContext().getAuthentication().getName();System.out.println(username);//获取sessionIdString sessionId = getSessionId();//1.查询购物车列表List<Cart> cartList = findCartList();if ("anonymousUser".equals(username)){//未登陆System.out.println("saveCartListToRedis by sessionId.....");//2.添加商品到购物车cartList = cartService.addItemToCartList(cartList,itemId, num);//3.保存购物车列表到redis中cartService.saveCartListToRedis(sessionId,cartList);}else{//已登录System.out.println("saveCartListToRedis by username.....");cartService.saveCartListToRedis(username,cartList);}return new Result(true,"添加购物车成功");} catch (RuntimeException e) {e.printStackTrace();return new Result(false,e.getMessage());}catch (Exception e) {e.printStackTrace();return new Result(false,"添加购物车失败");}}}
前台实现:
service层:
//服务层
app.service('cartService',function($http){//查找购物车列表数据this.findCartList=function(){return $http.get('cart/findCartList.do');}//查找购物车列表数据this.addItemToCartList=function (itemId,num) {return $http.get('cart/addItemToCartList.do?itemId='+itemId+'&num='+num)}});
controller层:
//控制层
app.controller('cartController' ,function($scope,$controller ,cartService){$controller('baseController',{$scope:$scope});//继承//读取列表数据绑定到表单中 $scope.findCartList=function(){cartService.findCartList().success(function(response){$scope.cartList=response;sum();} );}//添加商品到购物车$scope.addItemToCartList=function (itemId,num) {cartService.addItemToCartList(itemId,num).success(function (response) {if (response.success){//添加购物车工程$scope.findCartList();}else{//添加购物车失败alert(response.message)}})}//统计商品的数量和总计sum=function () {//总数量 和总金额$scope.totalNum = 0;$scope.totalMoney=0.00;//遍历购物车列表for (var i = 0;i<$scope.cartList.length;i++){//获取购物车对象var cart = $scope.cartList[i];var orderItemList = cart.orderItemList;//获取商品明细列表//遍历商品购物车明细列表for(var j = 0;j<orderItemList.length;j++){$scope.totalNum = orderItemList[i].num;$scope.totalMoney= orderItemList[i].totalFee;}}}});
1.页面的设置:
注意:如果我们未登陆,则要添加购物车,我们需要获取用户名:则通过一个spring-security.xml的配置
//之前增加的放行,删掉,否则所有访问cart下的访问都不进入到springSecurity中
<http pattern="/cart/*.do" security="none"></http>
//但是我们需要购物车可以不登录也能增加到购物车中的操作,IS_AUTHENTICATED_ANONYMOUSLY和上面的配置区别在于,可以匿名访问springSecurity(加在入口点引用中,注意拦截规则小范围的在上面)
<intercept-url pattern="/cart/*.do" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
//在此拦截器上<intercept-url pattern="/**" access="ROLE_USER"/>
2.页面跳转的问题
思路分析:我们设置一个login.html页面这个页面就做一件事,就是用于转发跳转到cart.html页面,因为我们在spring-sceurity.xml中没有放行,所以会先进入cas登陆界面,我们登陆后,会转发到cart.html页面
代码如下:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>跳转页面</title><script type="text/javascript">location.href="cart.html";</script>
</head>
<body></body>
</html>
电商项目day16(购物车实现)相关推荐
- 关于电商项目的购物车总结和购物车实现
关于电商项目的购物车总结和购物车实现 本文中简述的购物车模仿京东的模式,用户没有登录,也可进行购物车的操作,如果用户登录了,则在数据库中操作购物车.我们基于存放在cookies里面. 先看添加到购物车 ...
- SpringBoot电商项目之购物车下单(沙箱支付)
目录 一.购物车结算前端功能实现 二.购物车结算后端功能实现 1.从session中获取购物车对象 2.筛选出要结算的订单项列表集合 3.订单页前台展示 三.结算页的下单前端 生成订单 1.前端相关处 ...
- 电商项目之购物车设计
购物车 购物车数据的储存 购物车设计是每个电商项目中必不可缺的一环,不管登录与否,购物车都可以使用.那么购物车的数据我们存在哪里呢? 登录时,购物车的数据理所应当的存在redis数据库中,可是未登录时 ...
- 【愚公系列】2022年10月 微信小程序-电商项目-商品购物车功能实现
文章目录 前言 一.商品购物车功能实现 二.效果 前言 在电商的核心交易流程中,购物车是其中非常重要的一环,它承担商品加购.价格计算.促销活动展示等功能,与会员系统.商品系统.库存系统.订单系统等紧密 ...
- Vue3电商项目实战-购物车模块2【04-头部购物车-商品列表-本地、05-头部购物车-删除操作-本地、06-购物车页面-基础布局】
文章目录 04-头部购物车-商品列表-本地 05-头部购物车-删除操作-本地 06-购物车页面-基础布局 04-头部购物车-商品列表-本地 目的:根据本地存储的商品获取最新的库存价格和有效状态. 大致 ...
- 电商项目实战测试流程
寰球优品电商项目内-购物车的功能需求分析 01 寰球优品电商项目的核心业务流程 注册登录>浏览商品>添加购物车>提交订单>订单支付>查看订单 02 软件测试点分析基本原则 ...
- JavaEE大型分布式电商项目 上海淘淘商城 29期
上海29期_张志君老师_淘淘商城_大型分布式电商项目 JavaEE大型分布式电商项目 淘淘商城 29期 需要的加qq:350226234,备注:程序员学习视频 ==================== ...
- Java项目:网上电商项目(前后端分离+java+vue+Springboot+ssm+mysql+maven+redis)
源码获取:博客首页 "资源" 里下载! 一.项目简述 本系统功能包括: 一款基于Springboot+Vue的电商项目,前后端分离项目,前台后台都有,前台商品展示购买,购物车分类, ...
- 大数据 互联网架构阶段 电商项目简介
电商项目简介 零.目录 电商项目特点 电商项目技术难点 电商项目简介 开发工具 电商项目架构 开发环境 一.电商项目特点 分布式 数十台服务器,甚至百台.千台.万台,包括:Nigix负载均衡集群.To ...
最新文章
- sqlite-1.0.0源码执行的基本流程概述
- 使用自变分原理改进正则化核回归:通过变分法推导和推广Nadaraya-Watson估计
- python文件选择:tkFileDialog 基础
- Python模块之XlsxWriter
- 任老爷子退休以后,华为谁最有可能接手,为什么?
- css将空的div撑开,如何使用css将空的浮动div伸展到可用的全高度?
- tp3.2 volist标签
- 【电路仿真】基于simulink模拟锁相环设计【含Matlab源码 339期】
- Java抽签小程序(可控制抽几个人)(利用随机数与数组想结合)
- [深度学习] Python人脸识别库face_recognition使用教程
- linux glibc升级
- 计算机论文如何加字数,发表论文的字数是如何计算的?
- 零基础云开发一个投票小程序
- 计算机开机自检时,电脑开机启动时出现DHCP自检怎么办
- 把自己的电脑作为网络代理服务器
- VB→C++→C#→VB.NET,语言的共性和个性
- 软件设计证书倒数50天-软件工程重要的证书
- 未明学院:管培生刚入职就被裁?校招的管培生真的那么高大上吗?
- 《越狱》中的项目管理——两个版本的对比
- 自定义icon,在iconfont.css中引入自定义图标