✅P244_商城业务-购物车-获取并合并购物车

gong_yz大约 4 分钟谷粒商城

一、开篇

购物车列表展示逻辑

  • 若用户未登录,则使用user-key获取Redis中购物车数据
  • 若用户登录,则使用userId获取Redis中购物车数据,并将user-key 对应的临时购物车数据用户购物车数据合并且删除临时购物车

二、业务实现

2.1 Controller

cfmall-cart/src/main/java/com/gyz/cfmall/controller/CartController.java

    /**
     * 去购物车页面的请求
     * 浏览器有一个cookie:user-key 标识用户的身份,一个月过期
     * 如果第一次使用jd的购物车功能,都会给一个临时的用户身份:
     * 浏览器以后保存,每次访问都会带上这个cookie;
     * <p>
     * 登录:session有
     * 没登录:按照cookie里面带来user-key来做
     * 第一次,如果没有临时用户,自动创建一个临时用户
     *
     * @return
     */
    @GetMapping(value = "/cart.html")
    public String cartListPage(Model model) throws ExecutionException, InterruptedException {
        //快速得到用户信息:id,user-key
        // UserInfoTo userInfoTo = CartInterceptor.toThreadLocal.get();

        CartVo cartVo = cartService.getCart();
        model.addAttribute("cart", cartVo);
        return "cartList";
    }

2.2 Service

    @Override
    public CartVo getCart() throws ExecutionException, InterruptedException {

        CartVo cartVo = new CartVo();
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        if (userInfoTo.getUserId() != null) {
            //1、登录
            String cartKey = CART_PREFIX + userInfoTo.getUserId();
            //临时购物车的键
            String temptCartKey = CART_PREFIX + userInfoTo.getUserKey();

            //2、如果临时购物车的数据还未进行合并
            List<CartItemVo> tempCartItems = getCartItemList(temptCartKey);
            if (tempCartItems != null) {
                //临时购物车有数据需要进行合并操作
                for (CartItemVo item : tempCartItems) {
                    this.addCartItem(item.getSkuId(), item.getCount());
                }
                //清除临时购物车的数据
                this.clearCartInfo(temptCartKey);
            }

            //3、获取登录后的购物车数据【包含合并过来的临时购物车的数据和登录后购物车的数据】
            List<CartItemVo> cartItems = this.getCartItemList(cartKey);
            cartVo.setItems(cartItems);

        } else {
            //没登录
            String cartKey = CART_PREFIX + userInfoTo.getUserKey();
            //获取临时购物车里面的所有购物项
            List<CartItemVo> cartItems = this.getCartItemList(cartKey);
            cartVo.setItems(cartItems);
        }

        return cartVo;
    }

	/**
     * 获取购物车里所有商品数据
     *
     * @param tempUserKey
     * @return
     */
    public List<CartItemVo> getCartItemList(String tempUserKey) {
        BoundHashOperations<String, Object, Object> ops = stringRedisTemplate.boundHashOps(tempUserKey);
        List<Object> values = ops.values();
        if (values != null && values.size() > 0) {
            List<CartItemVo> cartItemList = values.stream().map(item -> {
                CartItemVo cartItemVo = JSON.parseObject((String) item, CartItemVo.class);
                return cartItemVo;
            }).collect(Collectors.toList());
            return cartItemList;
        }
        return null;
    }
    
    
    /**
     * 清空购物车的数据
     *
     * @param cartKey
     */
    @Override
    public void clearCartInfo(String cartKey) {
        stringRedisTemplate.delete(cartKey);
    }

三、前端页面

3.1 登录回显

cfmall-cart/src/main/resources/templates/success.html

<ul class="hd_wrap_right">
    <li class="forel">
    <li>
        <a th:if="${session.loginUser == null}" href="http://auth.cfmall.com/login.html" class="li_2">请登录</a>
        <a th:if="${session.loginUser != null}">欢迎, [[${session.loginUser.nickname}]]</a>
    </li>
    <li>
        <a th:if="${session.loginUser == null}" href="http://auth.cfmall.com/reg.html" style="color: red;">免费注册</a>
    </li>
    <li>
        <a href="/javascript:;">我的订单</a>
    </li>
</ul>

3.2 购物车页面

cfmall-cart/src/main/resources/templates/cartList.html

3.2.1 常规内容显示

<div class="One_ShopCon">
	<h1 th:if="${cart.items==null}">购物车还没有商品,<a href="http://cfmall.com/">去购物</a></h1>
	<ul  th:if="${cart.items!=null}">
		<li th:each="item:${cart.items}">
			<div></div>
			<div>
				<ol>
					<li><input type="checkbox" th:attr="skuId=${item.skuId}" class="itemCheck" th:checked="${item.check}"/></li>
					<li>
						<dt><img th:src="${item.image}" alt=""></dt>
						<dd style="width: 150px;">
							<p>
								<span th:text="${item.title}">TCL 55A950C 55英寸32核</span><br/>
								<span th:each="attr:${item.skuAttrValues}"
									  th:text="${attr}+''"></span>
							</p>
						</dd>
					</li>
					<li>
						<!-- #numbers.formatDecimal(变量, 整数位位数(不足前面补0), 保留小数位的数量) -->
						<p class="dj" th:text="'¥'+${#numbers.formatDecimal(item.price,3,2)}">4599.00</p>
					</li>
					<li>
						<p>
							<span>-</span>
							<span th:text="${item.count}">5</span>
							<span>+</span>
						</p>
					</li>
					<li style="font-weight:bold">
						<p class="zj">¥[[${#numbers.formatDecimal(item.totalPrice,3,2)}]]</p>
					</li>
					<li>
						<p class="deleteItemBtn" th:attr="skuId=${item.skuId}">删除</p>
					</li>
				</ol>
			</div>
		</li>
	</ul>
</div>

3.2.2 购物车总价&优惠价格显示

<div>
    <ol>
        <li>总价:<span style="color:#e64346;font-weight:bold;font-size:16px;" class="fnt">¥[[${#numbers.formatDecimal(cart.totalAmount, 3, 2)}]]</span></li>
        <li>优惠:¥[[${#numbers.formatDecimal(cart.reduce,1,2)}]]</li>
    </ol>
</div>

3.2.3 页面优化

cfmall-cart/src/main/resources/templates/cartList.html

<div class="one_search_load" th:if="${session.loginUser==null}">
	<img src="/static/cart/img/shop_07.jpg" class="one_load_wraing">
	<span>您还没有登录!登录后购物车的商品将保存到您账号中</span>
	<a href="#"><input type="button" onclick="login()" value="立即登录" class="one_load_btn"></a>
</div>
function login(){
	location.href = "http://auth.cfmall.com/login.html";
}

3.3 商城首页-我的购物车

实现:点击商城首页-“我的购物车”展示购物车列表数据,

修改获取购物车数据接口,

cfmall-product/src/main/resources/templates/index.html


四、测试