从0开始 独立完成企业级Java电商网站开发(服务端)笔记-购物车模块功能

购物车功能:

1.加入购物车商品

2.更新购物车商品数量

3.查询购物车商品数量

4.移除购物车商品

5.购物车商品单选/取消

6.购物车商品全选/取消

7.购物车列表

学习目标:

1.购物车模块的设计思想

2.封装一个高复用购物车核心方法

3.解决浮点型在商业运算中丢失精度问题(尤其是价格结计算)

数据表设计

接口设计

https://gitee.com/imooccode/happymmallwiki/wikis/%E9%97%A8%E6%88%B7_%E8%B4%AD%E7%89%A9%E8%BD%A6%E6%8E%A5%E5%8F%A3?sort_id=9919

limitQuantity:两种状态

--LIMIT_NUM_SUCCESS限制数量成功

--LIMIT_NUM_ERROR限制数量失败

如果是限制数量失败,会自动的把购物车中的产品数量进行修改,修改成最大值,也就是最大可购买的数量.应用场景:假设商品可购买数量是100个,当我们直接输入200的时候超出商品库存,就会返回一个LIMIT_NUM_ERROR,并把数量强制改回最大可购买数量如当前的100,并按可购数量计算总价.

那么前端就可以根据该字段提示,已超出库存,请进行修改.

实现:

购物车需要在用户登录状态下进行操作.

1.购物车计算通用方法-购物车接口只要涉及到数量的变化都需要经过该方法,主要是用于防止超过库存等一些注意操作

这个方法返回前端时都需要去调用的,用于向前端用户返回最新的购物车数据.

场景:当在购物车添加商品时,

参数:productId商品ID,count数量

逻辑:

a-select:添加之前,需要去查询当前用户下,该productId是否在当前购物车.如果是空,说明该商品不再购物车,我们就要就该商品新增到购物车中.

b-insert:插入购物车数据表中,要将userId,商品id,数量count,同时设置当前商品的选中状态checked=1(1是选中状态);

c-update:如果a步骤查询的是该商品已在该用户的购物车中,那么就是将购物车原有的数量加上现在加入购物车数量,并更新购物车数据表(也可同时将check状态更新为1,看需求);

基本思想是这个,但是我们额外还需要做一些操作,比如计算库存等操作,防止前端和后端数据不一致.封装高复用的购物车方法:

购物车产品组合的VO对象-CartProductVO(即已购物车表为基础进行扩展的表,比如根据userId可扩展一些用户模块信息,根据productId可扩展一些商品模块信息)

CartProductVO:

id,userId,productId,quantity,productName,productSubtitle,productMainImage,productPrice,productStatus,productTotalPrice,productStock,productChecked,limitQuantity根据库存限制返回数量字段

并且在整合CartProductVO后,在专门用一个针对cart购物车返回前端的VO-cartVO,这里面集成了cartProductVO,并补充了一些通用字段:

CartVO:

List<CartProductVO> cartProductVO;

BigDecimal cartTotal;

Boolean allChecked;

String imageHost;

----将上述两个对象封装组合一个高复用的方法,返回给前端的CartVO对象.

private CartVO getCartVOList(int userId){

//根据userID查询当前用户购物车状态

}

private CartVo getCartVoLimit(Integer userId){
		// 1 初始化返回前端的购物车VO对象
        CartVo cartVo = new CartVo();
		// 2 获取该用户购物车所有商品
        List<Cart> cartList = cartMapper.selectCartByUserId(userId);
		// 3 初始化cartProductVoList集合
        List<CartProductVo> cartProductVoList = Lists.newArrayList();
		// 4 处理浮点计算精度问题BigDecimal
        BigDecimal cartTotalPrice = new BigDecimal("0");
		// 5 用户购物车不为空时
        if(CollectionUtils.isNotEmpty(cartList)){
			// 6 取出该用户购物车所有的商品,并放入CartProductVO对象重构 
            for(Cart cartItem : cartList){
				// 6-1 购物车基本信息
                CartProductVo cartProductVo = new CartProductVo();
                cartProductVo.setId(cartItem.getId());
                cartProductVo.setUserId(userId);
                cartProductVo.setProductId(cartItem.getProductId());
				// 6-2 购物车扩展数据-如商品对应的
                Product product = productMapper.selectByPrimaryKey(cartItem.getProductId());
                if(product != null){
                    cartProductVo.setProductMainImage(product.getMainImage());
                    cartProductVo.setProductName(product.getName());
                    cartProductVo.setProductSubtitle(product.getSubtitle());
                    cartProductVo.setProductStatus(product.getStatus());
                    cartProductVo.setProductPrice(product.getPrice());
                    cartProductVo.setProductStock(product.getStock());
                    // 6-2-1限制库存,防止用户加入购物车数量超过库存数量
					//并将该数量用于计算购物车总价,保证总价的准确性
                    int buyLimitCount = 0;
                    if(product.getStock() >= cartItem.getQuantity()){
                        //库存充足的时候
                        buyLimitCount = cartItem.getQuantity();
                        cartProductVo.setLimitQuantity(Const.Cart.LIMIT_NUM_SUCCESS);
                    }else{
						//超过库存,那么强制用户加入购物车数量最大就是库存数量
                        buyLimitCount = product.getStock();
						//同时返回超出库存提示
                        cartProductVo.setLimitQuantity(Const.Cart.LIMIT_NUM_FAIL);
                        //更新购物车中有效数量-确保前后端购物车数量一致性
                        Cart cartForQuantity = new Cart();
                        cartForQuantity.setId(cartItem.getId());
                        cartForQuantity.setQuantity(buyLimitCount);
                        cartMapper.updateByPrimaryKeySelective(cartForQuantity);
                    }
					// 6-2-2将确认后的购物数量更新给前端,并用于计算商品总价
                    cartProductVo.setQuantity(buyLimitCount);
                    // 6-2-3计算当前商品总价
                    cartProductVo.setProductTotalPrice(BigDecimalUtil.mul(product.getPrice().doubleValue(),cartProductVo.getQuantity()));
                    cartProductVo.setProductChecked(cartItem.getChecked());
                }

                if(cartItem.getChecked() == Const.Cart.CHECKED){
                    //如果已经勾选,增加到整个的购物车总价中
                    cartTotalPrice = BigDecimalUtil.add(cartTotalPrice.doubleValue(),cartProductVo.getProductTotalPrice().doubleValue());
                }
                cartProductVoList.add(cartProductVo);
            }
        }
		// 7 数据填充到cartVO对象中
        cartVo.setCartTotalPrice(cartTotalPrice);
        cartVo.setCartProductVoList(cartProductVoList);
		// 是否全选
        cartVo.setAllChecked(this.getAllCheckedStatus(userId));
        cartVo.setImageHost(PropertiesUtil.getProperty("ftp.server.http.prefix"));
        return cartVo;
    }

	//传递userId去购物车数据表查询是否未被勾选的-有未勾选的则标记为false
    private boolean getAllCheckedStatus(Integer userId){
        if(userId == null){
            return false;
        }
        return cartMapper.selectCartProductCheckedStatusByUserId(userId) == 0;

    }

Tips:处理科学计算出现的浮点精度问题

处理科学计算浮点型数据是出现的微小精度问题,如价格,在Java中使用BigDecimal的String构造器进行计算,如 BigDecimal a = new BigDecimal("0.5"),然后和另一个String类型的BigDecimal变量进行计算才不会出现精度错误.

Tips:一定是String的BigDecimal类型,如果用默认的依然会出现精度问题-new BigDecimal(5)

BigDecimal工具类-BigDecimalUtil,之后所有的运算都通过这个工具类转化成BigDecimal进行计算

2.购物车添加商品

参数:productId商品ID,count数量

逻辑:

a-select:添加之前,需要去查询当前用户下,该productId是否在当前购物车.如果是空,说明该商品不再购物车,我们就要就该商品新增到购物车中.

b-insert:插入购物车数据表中,要将userId,商品id,数量count,同时设置当前商品的选中状态checked=1(1是选中状态);

c-update:如果a步骤查询的是该商品已在该用户的购物车中,那么就是将购物车原有的数量加上现在加入购物车数量,并更新购物车数据表(也可同时将check状态更新为1,看需求);

3.更新购物车某个商品的数据量

参数:productId,count

需要更新增商品一样,去判断当前购物车是否有该商品

4.移除购物车某个产品

参数:productIds(商品ID可能同时有多个,不需要传递数量,直接删除就好)

5.购物车List列表

参数:无

6.全选/全反选--其实就是更新update操作

参数:无,根据userId查询全部购物车

Tips:有两个接口全选接口和全反选接口,即调用全选接口时,后台统一设置成选中;调用反选接口时,统一设置成不选中.然后在调用获取全部购物车的list方法,得到最新的购物车数据.

7.单选/单独反选

参数:productId,相较于上面的全选和不全选就是多了一个productID逻辑一样

8.查询当前用户购物车里面的产品数量(用于未进入购物车等页面显示购物车的数量)

根据产品加入购物车份数的累加

参数:无,查询当前用户下

返回:数值

Tips:用户未登录,不能报错,只要返回数值0即可,即这里判断session时 不能因为session.user为空,就报错,要返回0.

发布了64 篇原创文章 · 获赞 110 · 访问量 28万+

猜你喜欢

转载自blog.csdn.net/godot06/article/details/104686886