SpingBoot的项目实战--模拟电商【3.购物车模块】

发布时间:2024年01月03日

🥳🥳Welcome Huihui's Code World ! !🥳🥳

接下来看看由辉辉所写的关于SpringBoot电商项目的相关操作吧?

目录

🥳🥳Welcome Huihui's Code World ! !🥳🥳

一.功能需求

二.代码编写

1.商品详情的显示

2.加入购物车

3.参数解析器

4.购物车的前端优化

5.购物车的删除【单个&批量】


一.功能需求

①商品详情的显示(根据id查询单个商品)

②加入购物车(redis+cookie+数据库)

③需要通过用户信息来获取购物车【参数解析器】

④前端的显示【商品数量,小计】

⑤购物车的删除【全选与全不选,单个删除与批量删除】

二.代码编写

1.商品详情的显示

首页的商品点击跳转到商品详情页

<a href="${ctx}/goods/selectOne?gid=${g.gid}">
<!DOCTYPE html>
<html>
<head lang="en">
	<#include "common/head.html">
	<link rel="stylesheet" type="text/css" href="css/public.css"/>
	<link rel="stylesheet" type="text/css" href="css/index.css" />
</head>
<body>
<!------------------------------head------------------------------>
<#include "common/top.html">

<!-------------------------banner--------------------------->
<div class="block_home_slider">
	<div id="home_slider" class="flexslider">
		<ul class="slides">
			<li>
				<div class="slide">
					<img src="img/banner2.jpg"/>
				</div>
			</li>
			<li>
				<div class="slide">
					<img src="img/banner1.jpg"/>
				</div>
			</li>
		</ul>
	</div>
</div>

<!------------------------------thImg------------------------------>
<div class="thImg">
	<div class="clearfix">
		<a href="${ctx}/page/vase_proList.html"><img src="img/i1.jpg"/></a>
		<a href="${ctx}/page/proList.html"><img src="img/i2.jpg"/></a>
		<a href="#2"><img src="img/i3.jpg"/></a>
	</div>
</div>

<!------------------------------news------------------------------>
<div class="news">
	<div class="wrapper">
		<h2><img src="img/ih1.jpg"/></h2>
		<div class="top clearfix">
			<a href="${ctx}/page/proDetail.html"><img src="img/n1.jpg"/><p></p></a>
			<a href="${ctx}/page/proDetail.html"><img src="img/n2.jpg"/><p></p></a>
			<a href="${ctx}/page/proDetail.html"><img src="img/n3.jpg"/><p></p></a>
		</div>
		<div class="bott clearfix">
			<a href="${ctx}/page/proDetail.html"><img src="img/n4.jpg"/><p></p></a>
			<a href="${ctx}/page/proDetail.html"><img src="img/n5.jpg"/><p></p></a>
			<a href="${ctx}/page/proDetail.html"><img src="img/n6.jpg"/><p></p></a>
		</div>
		<h2><img src="img/ih2.jpg"/></h2>
	<#list p1 as p>
		<div class="flower clearfix tran">
			<#list p as g>
			<a href="${ctx}/goods/selectOne?gid=${g.gid}"  class="clearfix">
				<dl>
					<dt>
						<span class="abl"></span>
						<img src="${g.goodsImg}"/>
						<span class="abr"></span>
					</dt>
					<dd>${g.goodsTitle}</dd>
					<dd><span>¥${g.goodsPrice}</span></dd>
				</dl>
			</a>
		</#list>
		</div>
		</#list>

	</div>
</div>

<!------------------------------ad------------------------------>
<a href="#" class="ad"><img src="img/ib1.jpg"/></a>

<!------------------------------people------------------------------>
<div class="people">
	<div class="wrapper">
		<h2><img src="img/ih3.jpg"/></h2>
		<#list p2 as p>
		<div class="pList clearfix tran">
				<#list p as g>
			<a href="${ctx}/goods/selectOne?gid=${g.gid}">
					<dl>
						<dt>
							<span class="abl"></span>
							<img src="${g.goodsImg}"/>
							<span class="abr"></span>
						</dt>
						<dd>${g.goodsTitle}</dd>
						<dd><span>¥${g.goodsPrice}</span></dd>
					</dl>
				</a>
			</#list>
		</div>
	</#list>
		</div>

	</div>
</div>

<#include "common/footer.html"/>

<script src="js/public.js" type="text/javascript" charset="utf-8"></script>
<script src="js/nav.js" type="text/javascript" charset="utf-8"></script>
<script src="js/jquery.flexslider-min.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
	$(function() {
		$('#home_slider').flexslider({
			animation: 'slide',
			controlNav: true,
			directionNav: true,
			animationLoop: true,
			slideshow: true,
			slideshowSpeed:2000,
			useCSS: false
		});

	});
</script>
</body>
</html>

效果预览

2.加入购物车

前端

<a href="javascript:void(0);"><p class="cart fr" data-gid="${(good.gid)!}">加入购物车</p></a>

完整代码

<!DOCTYPE html>
<html>
	<head>
		<#include "common/head.html">
		<link rel="stylesheet" type="text/css" href="css/public.css"/>
		<link rel="stylesheet" type="text/css" href="css/proList.css"/>
	</head>
	<body>
		<!------------------------------head------------------------------>
		<#include "common/top.html">
		<!-----------------address------------------------------->
		<div class="address">
			<div class="wrapper clearfix">
				<a href="${ctx}/">首页</a>
				<span>/</span>
				<a href="${ctx}/page/flowerDer.html">装饰摆件</a>
				<span>/</span>
				<a href="${ctx}/page/proList.html">干花花艺</a>
				<span>/</span>
				<#--
				注意:
				1)${goods.goodsTitle!}:只能判断goodsTitle属性是否为空,不能判断goods对象是否为空
				2)${(goods.goodsTitle)!}:既可以判断goods对象是否为空,也可以判断goodsTitle属性是否为空
				-->
				<a href="#" class="on">${(good.goodsTitle)!}</a>
			</div>
		</div>
		<!-----------------------Detail------------------------------>
		<div class="detCon">
			<div class="proDet wrapper">
				<div class="proCon clearfix">
					<div class="proImg fl">
						<img class="det" src="${(good.goodsImg)!}" />
						<#--<div class="smallImg clearfix">]
							<img src="img/temp/proDet01.jpg" data-src="img/temp/proDet01_big.jpg">
							<img src="img/temp/proDet02.jpg" data-src="img/temp/proDet02_big.jpg">
							<img src="img/temp/proDet03.jpg" data-src="img/temp/proDet03_big.jpg">
							<img src="img/temp/proDet04.jpg" data-src="img/temp/proDet04_big.jpg">
						</div>-->
					</div>
					<div class="fr intro">
						<div class="title">
							<h4>${(good.goodsName)!}</h4>
							<p>${(good.goodsDetail)!}</p>
							<span>¥${(good.goodsPrice)!}</span>
						</div>
						<div class="proIntro">
							<p>颜色分类</p>
							<div class="smallImg clearfix categ">
								<p class="fl"><img src="img/temp/prosmall01.jpg" alt="白瓷花瓶+20支快乐花" data-src="img/temp/proBig01.jpg"></p>
								<p class="fl"><img src="img/temp/prosmall02.jpg" alt="白瓷花瓶+20支兔尾巴草" data-src="img/temp/proBig02.jpg"></p>
								<p class="fl"><img src="img/temp/prosmall03.jpg" alt="20支快乐花" data-src="img/temp/proBig03.jpg"></p>
								<p class="fl"><img src="img/temp/prosmall04.jpg" alt="20支兔尾巴草" data-src="img/temp/proBig04.jpg"></p>
							</div>
							<p>数量&nbsp;&nbsp;库存<span>${(good.goodsStock)!}</span>件</p>
							<div class="num clearfix">
								<img class="fl sub" src="img/temp/sub.jpg">
								<span class="fl" contentEditable="true">1</span>
								<img class="fl add" src="img/temp/add.jpg">
								<p class="please fl">请选择商品属性!</p>
							</div>
						</div>
						<div class="btns clearfix">
							<a href="#2"><p class="buy fl">立即购买</p></a>
							<a href="javascript:void(0);"><p class="cart fr" data-gid="${(good.gid)!}">加入购物车</p></a>
						</div>
					</div>
				</div>
			</div>
		</div>
		<div class="introMsg wrapper clearfix">
			<div class="msgL fl">
				<div class="msgTit clearfix">
					<a class="on">商品详情</a>
					<a>所有评价</a>
				</div>
				<div class="msgAll">
					<div class="msgImgs">
						<img src="img/temp/det01.jpg">
						<img src="img/temp/det02.jpg">
						<img src="img/temp/det03.jpg">
						<img src="img/temp/det04.jpg">
						<img src="img/temp/det05.jpg">
						<img src="img/temp/det06.jpg">
						<img src="img/temp/det07.jpg">
					</div>
					<div class="eva">
						<div class="per clearfix">
							<img class="fl" src="img/temp/per01.jpg">
							<div class="perR fl">
								<p>馨***呀</p>
								<p>不好意思评价晚了,产品很好,价格比玻璃品便宜,没有我担心的杂色,发货快,包装好,全5分</p>
								<div class="clearfix">
									<p><img src="img/temp/eva01.jpg"></p>
									<p><img src="img/temp/eva02.jpg"></p>
									<p><img src="img/temp/eva03.jpg"></p>
									<p><img src="img/temp/eva04.jpg"></p>
									<p><img src="img/temp/eva05.jpg"></p>
								</div>
								<p><span>2016年12月27日08:31</span><span>颜色分类:大中小三件套(不含花)</span></p>
							</div>
						</div>
						<div class="per clearfix">
							<img class="fl" src="img/temp/per02.jpg">
							<div class="perR fl">
								<p>么***周</p>
								<p>花瓶超级棒,我看图以为是光面的,收货发现是磨砂,但感觉也超有质感,很喜欢。磨砂上面还有点纹路,不过觉得挺自然的,不影响美观。包装也很好,绝对不会磕碎碰坏,好评!</p>
								<p><span>2016年12月27日08:31</span><span>颜色分类:大中小三件套(不含花)</span></p>
							</div>
						</div>
						<div class="per clearfix">
							<img class="fl" src="img/temp/per01.jpg">
							<div class="perR fl">
								<p>馨***呀</p>
								<p>不好意思评价晚了,产品很好,价格比玻璃品便宜,没有我担心的杂色,发货快,包装好,全5分</p>
								<div class="clearfix">
									<p><img src="img/temp/eva01.jpg"></p>
									<p><img src="img/temp/eva02.jpg"></p>
									<p><img src="img/temp/eva03.jpg"></p>
									<p><img src="img/temp/eva04.jpg"></p>
									<p><img src="img/temp/eva05.jpg"></p>
								</div>
								<p><span>2016年12月27日08:31</span><span>颜色分类:大中小三件套(不含花)</span></p>
							</div>
						</div>
						<div class="per clearfix">
							<img class="fl" src="img/temp/per02.jpg">
							<div class="perR fl">
								<p>么***周</p>
								<p>花瓶超级棒,我看图以为是光面的,收货发现是磨砂,但感觉也超有质感,很喜欢。磨砂上面还有点纹路,不过觉得挺自然的,不影响美观。包装也很好,绝对不会磕碎碰坏,好评!</p>
								<p><span>2016年12月27日08:31</span><span>颜色分类:大中小三件套(不含花)</span></p>
							</div>
						</div>
						<div class="per clearfix">
							<img class="fl" src="img/temp/per01.jpg">
							<div class="perR fl">
								<p>馨***呀</p>
								<p>不好意思评价晚了,产品很好,价格比玻璃品便宜,没有我担心的杂色,发货快,包装好,全5分</p>
								<div class="clearfix">
									<p><img src="img/temp/eva01.jpg"></p>
									<p><img src="img/temp/eva02.jpg"></p>
									<p><img src="img/temp/eva03.jpg"></p>
									<p><img src="img/temp/eva04.jpg"></p>
									<p><img src="img/temp/eva05.jpg"></p>
								</div>
								<p><span>2016年12月27日08:31</span><span>颜色分类:大中小三件套(不含花)</span></p>
							</div>
						</div>
						<div class="per clearfix">
							<img class="fl" src="img/temp/per02.jpg">
							<div class="perR fl">
								<p>么***周</p>
								<p>花瓶超级棒,我看图以为是光面的,收货发现是磨砂,但感觉也超有质感,很喜欢。磨砂上面还有点纹路,不过觉得挺自然的,不影响美观。包装也很好,绝对不会磕碎碰坏,好评!</p>
								<p><span>2016年12月27日08:31</span><span>颜色分类:大中小三件套(不含花)</span></p>
							</div>
						</div>
						<div class="per clearfix">
							<img class="fl" src="img/temp/per01.jpg">
							<div class="perR fl">
								<p>馨***呀</p>
								<p>不好意思评价晚了,产品很好,价格比玻璃品便宜,没有我担心的杂色,发货快,包装好,全5分</p>
								<div class="clearfix">
									<p><img src="img/temp/eva01.jpg"></p>
									<p><img src="img/temp/eva02.jpg"></p>
									<p><img src="img/temp/eva03.jpg"></p>
									<p><img src="img/temp/eva04.jpg"></p>
									<p><img src="img/temp/eva05.jpg"></p>
								</div>
								<p><span>2016年12月27日08:31</span><span>颜色分类:大中小三件套(不含花)</span></p>
							</div>
						</div>
						<div class="per clearfix">
							<img class="fl" src="img/temp/per02.jpg">
							<div class="perR fl">
								<p>么***周</p>
								<p>花瓶超级棒,我看图以为是光面的,收货发现是磨砂,但感觉也超有质感,很喜欢。磨砂上面还有点纹路,不过觉得挺自然的,不影响美观。包装也很好,绝对不会磕碎碰坏,好评!</p>
								<p><span>2016年12月27日08:31</span><span>颜色分类:大中小三件套(不含花)</span></p>
							</div>
						</div>
						<div class="per clearfix">
							<img class="fl" src="img/temp/per01.jpg">
							<div class="perR fl">
								<p>馨***呀</p>
								<p>不好意思评价晚了,产品很好,价格比玻璃品便宜,没有我担心的杂色,发货快,包装好,全5分</p>
								<div class="clearfix">
									<p><img src="img/temp/eva01.jpg"></p>
									<p><img src="img/temp/eva02.jpg"></p>
									<p><img src="img/temp/eva03.jpg"></p>
									<p><img src="img/temp/eva04.jpg"></p>
									<p><img src="img/temp/eva05.jpg"></p>
								</div>
								<p><span>2016年12月27日08:31</span><span>颜色分类:大中小三件套(不含花)</span></p>
							</div>
						</div>
						<div class="per clearfix">
							<img class="fl" src="img/temp/per02.jpg">
							<div class="perR fl">
								<p>么***周</p>
								<p>花瓶超级棒,我看图以为是光面的,收货发现是磨砂,但感觉也超有质感,很喜欢。磨砂上面还有点纹路,不过觉得挺自然的,不影响美观。包装也很好,绝对不会磕碎碰坏,好评!</p>
								<p><span>2016年12月27日08:31</span><span>颜色分类:大中小三件套(不含花)</span></p>
							</div>
						</div>
					</div>
				</div>
			</div>
			<div class="msgR fr">
				<h4>为你推荐</h4>
				<div class="seeList">
					<a href="#">
						<dl>
							<dt><img src="img/temp/see01.jpg"></dt>
							<dd>【最家】复古文艺风玻璃花瓶</dd>
							<dd>¥193.20</dd>
						</dl>
					</a>
					<a href="#">
						<dl>
							<dt><img src="img/temp/see02.jpg"></dt>
							<dd>【最家】复古文艺风玻璃花瓶</dd>
							<dd>¥193.20</dd>
						</dl>
					</a>
					<a href="#">
						<dl>
							<dt><img src="img/temp/see03.jpg"></dt>
							<dd>【最家】复古文艺风玻璃花瓶</dd>
							<dd>¥193.20</dd>
						</dl>
					</a>
					<a href="#">
						<dl>
							<dt><img src="img/temp/see04.jpg"></dt>
							<dd>【最家】复古文艺风玻璃花瓶</dd>
							<dd>¥193.20</dd>
						</dl>
					</a>
				</div>
				
			</div>
		</div>
		<div class="like">
			<h4>猜你喜欢</h4>
			<div class="bottom">
				<div class="hd">
					<span class="prev"><img src="img/temp/prev.png"></span>
					<span class="next"><img src="img/temp/next.png"></span>
				</div>
				<div class="imgCon bd">
					<div class="likeList clearfix">
						<div>
							<a href="${ctx}/page/proDetail.html">
								<dl>
									<dt><img src="img/temp/like01.jpg"></dt>
									<dd>【最家】复古文艺风玻璃花瓶</dd>
									<dd>¥193.20</dd>
								</dl>
							</a>
							<a href="${ctx}/page/proDetail.html">
								<dl>
									<dt><img src="img/temp/like02.jpg"></dt>
									<dd>【最家】复古文艺风玻璃花瓶</dd>
									<dd>¥193.20</dd>
								</dl>
							</a>
							<a href="${ctx}/page/proDetail.html">
								<dl>
									<dt><img src="img/temp/like03.jpg"></dt>
									<dd>【最家】复古文艺风玻璃花瓶</dd>
									<dd>¥193.20</dd>
								</dl>
							</a>
							<a href="${ctx}/page/proDetail.html">
								<dl>
									<dt><img src="img/temp/like04.jpg"></dt>
									<dd>【最家】复古文艺风玻璃花瓶</dd>
									<dd>¥193.20</dd>
								</dl>
							</a>
							<a href="${ctx}/page/proDetail.html" class="last">
								<dl>
									<dt><img src="img/temp/like05.jpg"></dt>
									<dd>【最家】复古文艺风玻璃花瓶</dd>
									<dd>¥193.20</dd>
								</dl>
							</a>
						</div>
						<div>
							<a href="${ctx}/page/proDetail.html">
								<dl>
									<dt><img src="img/temp/like01.jpg"></dt>
									<dd>【最家】复古文艺风玻璃花瓶</dd>
									<dd>¥193.20</dd>
								</dl>
							</a>
							<a href="${ctx}/page/proDetail.html">
								<dl>
									<dt><img src="img/temp/like02.jpg"></dt>
									<dd>【最家】复古文艺风玻璃花瓶</dd>
									<dd>¥193.20</dd>
								</dl>
							</a>
							<a href="${ctx}/page/proDetail.html">
								<dl>
									<dt><img src="img/temp/like03.jpg"></dt>
									<dd>【最家】复古文艺风玻璃花瓶</dd>
									<dd>¥193.20</dd>
								</dl>
							</a>
							<a href="${ctx}/page/proDetail.html">
								<dl>
									<dt><img src="img/temp/like04.jpg"></dt>
									<dd>【最家】复古文艺风玻璃花瓶</dd>
									<dd>¥193.20</dd>
								</dl>
							</a>
							<a href="${ctx}/page/proDetail.html" class="last">
								<dl>
									<dt><img src="img/temp/like05.jpg"></dt>
									<dd>【最家】复古文艺风玻璃花瓶</dd>
									<dd>¥193.20</dd>
								</dl>
							</a>
						</div>
					</div>
				</div>
			</div>
		</div>
		<!--返回顶部-->
		<#include "common/footer.html">
		<script src="js/jquery.SuperSlide.2.1.1.js" type="text/javascript" charset="utf-8"></script>
		<script src="js/public.js" type="text/javascript" charset="utf-8"></script>
		<script src="js/nav.js" type="text/javascript" charset="utf-8"></script>
		<script src="js/pro.js" type="text/javascript" charset="utf-8"></script>
		<script src="js/cart.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			jQuery(".bottom").slide({titCell:".hd ul",mainCell:".bd .likeList",autoPage:true,autoPlay:false,effect:"leftLoop",autoPlay:true,vis:1});
		</script>
	</body>
</html>

效果预览

js

/****************************proDetail 加入购物车*******************************/
	$(".btns .cart").click(function(){
		//获得需要添加到购物车中的商品id
		let gid=this.dataset.gid
		//获得添加的商品的数量
		let num=$("div.num span.fl").text()
		//ajax请求
		$.post('/cart/add',{gid,num},resp=>{
		if(resp.code===200){
			alert("添加成功")
		}
		},'json')
	});

service

package com.wh.easyshop.service;


import com.wh.easyshop.model.User;
import com.wh.easyshop.vo.CartVo;

import java.util.List;

public interface IRedisService {

    /**
     * 将购物车对象保存到Redis中
     */
    void saveCart(User user, CartVo cartVo);

}

将购物车数据加到redis时,需要注意使用的类型,我把购物车的数据放到redis中的使用的是hash的数据类型,

因为购物车的数据是来自于多个用户的,这样的话肯定需要用一个标识去标识出特定的用户的数据

,其次用户的购物车数据肯定也是多条的,这样也需要用一个特殊的字段去拿到特定的购物车信息

【键:{键:值}】?【用户标识:{商品id:商品信息}】,hash的数据类型就很符合这样的存储格式,【特别适合于存储具有多个成员的结构体或对象

serviceimpl

package com.wh.easyshop.service;

import com.wh.easyshop.model.User;
import com.wh.easyshop.util.Constants;
import com.wh.easyshop.vo.CartVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class RedisServiceImpl implements IRedisService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 将购物车数据存入缓存中
     * @param user
     * @param cartVo
     */
    @Override
    public void saveCart(User user, CartVo cartVo) {
        //获取操Redi中hash类型数据对象--通过其将购物车存入到缓存中
        HashOperations<String, String , CartVo> rediscart = redisTemplate.opsForHash();
        //大键【hash的键】
        String hashKey=Constants.REDIS_CART_PREFIX + user.getId();
        //小键【hash中键值对的键】--存入的商品id
        String ValueKey=cartVo.getGid().toString();
        //判断购物车中是否有这个【大键+小键】--去拿到键对应的购物车中的商品
        Boolean hascart = rediscart.hasKey(hashKey, ValueKey);
        if(hascart){
            //edit【购物车中有这个商品】
            //拿到键对应的购物车中的商品
            CartVo cart= rediscart.get(hashKey, ValueKey);
            cart.setNum(cart.getNum()+cartVo.getNum());
        }
        //add【购物车中没有这个商品】
        //往缓存中加入数据
        rediscart.put(hashKey,ValueKey,cartVo);
    }

}

controller

package com.wh.easyshop.controller;

import com.wh.easyshop.model.Goods;
import com.wh.easyshop.model.User;
import com.wh.easyshop.resp.JsonResponseBody;
import com.wh.easyshop.service.IGoodsService;
import com.wh.easyshop.service.IRedisService;
import com.wh.easyshop.util.CookieUtils;
import com.wh.easyshop.vo.CartVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.jws.WebParam;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 购物车 前端控制器
 * </p>
 *
 * @author wh
 * @since 2024-1-2
 */
@Controller
@RequestMapping("/cart")
public class CartController {
    @Autowired
    IRedisService redisService;
    @Autowired
    IGoodsService goodsService;

    @RequestMapping("/add")
    @ResponseBody
    public JsonResponseBody<?> addCart(CartVo cartVo, HttpServletRequest request) {
        //拿到cookie中的用户令牌
        String userToken = CookieUtils.getCookieValue(request, "UserToken");
        //通过令牌拿到用户对象
        User userByToken = redisService.getUserByToken(userToken);
        //将当前登录用户的购物车信息保存到redis中
        redisService.saveCart(userByToken,cartVo);
        return JsonResponseBody.success() ;
    }


}

把购物车的数据加到redis中时,我只加了商品的id以及商品的数量,又因为goods这个实体类中没有商品数量的这个字段,所以建了一个vo类

vo

package com.wh.easyshop.vo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;

import java.io.Serializable;
import java.math.BigDecimal;

/**
 * @author是辉辉啦
 * @create 2024-01-02-15:14
 */
@Data
public class CartVo  implements Serializable {
    /**
     * 商品ID
     */
    private Long gid;

    /**
     * 商品数量
     */
    private  Integer num;
}

如果把其他的数据字段都加入到redis中的话,会降低效率,所以后面还需要从数据库中拿一次数据显示到购物车的页面。

service

package com.wh.easyshop.service;


import com.wh.easyshop.model.User;
import com.wh.easyshop.vo.CartVo;

import java.util.List;

public interface IRedisService {


    /**
     * 根据大键【user:用户的id】拿出redis中的购物车对象
     * @param user
     * @return
     */
    List<CartVo> loadCart(User user);

}

serviceimpl

package com.wh.easyshop.controller;

import com.wh.easyshop.model.Goods;
import com.wh.easyshop.model.User;
import com.wh.easyshop.resp.JsonResponseBody;
import com.wh.easyshop.service.IGoodsService;
import com.wh.easyshop.service.IRedisService;
import com.wh.easyshop.util.CookieUtils;
import com.wh.easyshop.vo.CartVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.jws.WebParam;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 购物车 前端控制器
 * </p>
 *
 * @author wh
 * @since 2024-1-2
 */
@Controller
@RequestMapping("/cart")
public class CartController {
    @Autowired
    IRedisService redisService;
    @Autowired
    IGoodsService goodsService;

    @RequestMapping("/toCart")
    public String index (HttpServletRequest request, Model model) {
        //拿到cookie中的用户令牌
        String userToken = CookieUtils.getCookieValue(request, "UserToken");
        //通过令牌拿到用户对象
        User userByToken = redisService.getUserByToken(userToken);
        //拿出对应用户的购物车中的所有的商品
        List<CartVo> cartVos = redisService.loadCart(userByToken);
        //拿出所有的购物车中的商id--集合
        List<Long> ids = cartVos.stream().map(CartVo::getGid).collect(Collectors.toList());
        //根据这个id集合查询所有对应的商品
        List<Goods> goods = goodsService.listByIds(ids);
        //遍历集合 赋值给对应的对象
        for (Goods g : goods) {
            //找到对应id相同的元素
            CartVo vo = cartVos.stream()
                    .filter(v -> Objects.equals(v.getGid(), g.getGid()))
                    .findFirst()
                    .get();
            //将商品g的属性赋值给vo【这样vo中的属性就有数据了】
            BeanUtils.copyProperties(g,vo);
        }
        model.addAttribute("cart",cartVos);
        return "cart";
    }


}

controller

package com.wh.easyshop.controller;

import com.wh.easyshop.model.Goods;
import com.wh.easyshop.model.User;
import com.wh.easyshop.resp.JsonResponseBody;
import com.wh.easyshop.service.IGoodsService;
import com.wh.easyshop.service.IRedisService;
import com.wh.easyshop.util.CookieUtils;
import com.wh.easyshop.vo.CartVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.jws.WebParam;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 购物车 前端控制器
 * </p>
 *
 * @author wh
 * @since 2024-1-2
 */
@Controller
@RequestMapping("/cart")
public class CartController {
    @Autowired
    IRedisService redisService;
    @Autowired
    IGoodsService goodsService;

    @RequestMapping("/toCart")
    public String index (HttpServletRequest request, Model model) {
        //拿到cookie中的用户令牌
        String userToken = CookieUtils.getCookieValue(request, "UserToken");
        //通过令牌拿到用户对象
        User userByToken = redisService.getUserByToken(userToken);
        //拿出对应用户的购物车中的所有的商品
        List<CartVo> cartVos = redisService.loadCart(userByToken);
        //拿出所有的购物车中的商id--集合
        List<Long> ids = cartVos.stream().map(CartVo::getGid).collect(Collectors.toList());
        //根据这个id集合查询所有对应的商品
        List<Goods> goods = goodsService.listByIds(ids);
        //遍历集合 赋值给对应的对象
        for (Goods g : goods) {
            //找到对应id相同的元素
            CartVo vo = cartVos.stream()
                    .filter(v -> Objects.equals(v.getGid(), g.getGid()))
                    .findFirst()
                    .get();
            //将商品g的属性赋值给vo【这样vo中的属性就有数据了】
            BeanUtils.copyProperties(g,vo);
        }
        model.addAttribute("cart",cartVos);
        return "cart";
    }


}

在购物车页面显示相应数据

这里还需要在首页的地方将跳转购物车页面的路径连接写好

 <a href="${ctx}/cart/toCart"><img src="img/gwc.png"/></a>
<script type="text/javascript" src="js/jquery-1.12.4.min.js"></script>
<script>
    $(function(){
        let nickname=getCookie("nickname");
        if(null!=nickname&&''!=nickname&&undefined!=nickname) {
            //设置昵称
            $('#nickname').text("您好,"+nickname);
            //隐藏登录注册按钮
            $('p.fl>span:eq(1)').css("display","none");
            //显示昵称和退出按钮
            $('p.fl>span:eq(0)').css("display","block");
        }else{
            //隐藏昵称
            $('#nickname').text("");
            //显示登录注册按钮
            $('p.fl>span:eq(1)').css("display","block");
            //隐藏昵称和退出按钮
            $('p.fl>span:eq(0)').css("display","none");
        }
    });

    function getCookie(cname) {
        var name = cname + "=";
        var decodedCookie = decodeURIComponent(document.cookie);
        var ca = decodedCookie.split(';');
        for(var i = 0; i <ca.length; i++) {
            var c = ca[i];
            while (c.charAt(0) == ' ') {
                c = c.substring(1);
            }
            if (c.indexOf(name) == 0) {
                return c.substring(name.length, c.length);
            }
        }
        return "";
    }
</script>
<div class="head">
    <div class="wrapper clearfix">
        <div class="clearfix" id="top">
            <h1 class="fl"><a href="${ctx}/"><img src="img/logo.png"/></a></h1>
            <div class="fr clearfix" id="top1">
                <p class="fl">
                    <span>
                        <span id="nickname"></span>
                        <a href="${ctx}/user/userLogout">退出</a>
                    </span>
                    <span style="display: none">
                        <a href="${ctx}/page/login.html" id="login">登录</a>
                        <a href="${ctx}/page/reg.html" id="reg">注册</a>
                    </span>
                </p>
                <form action="#" method="get" class="fl">
                    <input type="text" placeholder="热门搜索:干花花瓶" />
                    <input type="button" />
                </form>
                <div class="btn fl clearfix">
                    <a href="${ctx}/page/mygxin.html"><img src="img/grzx.png"/></a>
                    <a href="#" class="er1"><img src="img/ewm.png"/></a>
                    <a href="${ctx}/cart/toCart"><img src="img/gwc.png"/></a>
                    <p><a href="#"><img src="img/smewm.png"/></a></p>
                </div>
            </div>
        </div>
        <ul class="clearfix" id="bott">
            <li><a href="${ctx}/">首页</a></li>
            <li>
                <a href="#">所有商品</a>
                <div class="sList">
                    <div class="wrapper  clearfix">
                        <a href="${ctx}/page/paint.html">
                            <dl>
                                <dt><img src="img/nav1.jpg"/></dt>
                                <dd>浓情欧式</dd>
                            </dl>
                        </a>
                        <a href="${ctx}/page/paint.html">
                            <dl>
                                <dt><img src="img/nav2.jpg"/></dt>
                                <dd>浪漫美式</dd>
                            </dl>
                        </a>
                        <a href="${ctx}/page/paint.html">
                            <dl>
                                <dt><img src="img/nav3.jpg"/></dt>
                                <dd>雅致中式</dd>
                            </dl>
                        </a>
                        <a href="${ctx}/page/paint.html">
                            <dl>
                                <dt><img src="img/nav6.jpg"/></dt>
                                <dd>简约现代</dd>
                            </dl>
                        </a>
                        <a href="${ctx}/page/paint.html">
                            <dl>
                                <dt><img src="img/nav7.jpg"/></dt>
                                <dd>创意装饰</dd>
                            </dl>
                        </a>
                    </div>
                </div>
            </li>
            <li>
                <a href="${ctx}/page/flowerDer.html">装饰摆件</a>
                <div class="sList2">
                    <div class="clearfix">
                        <a href="${ctx}/page/proList.html">干花花艺</a>
                        <a href="${ctx}/page/vase_proList.html">花瓶花器</a>
                    </div>
                </div>
            </li>
            <li>
                <a href="${ctx}/page/decoration.html">布艺软饰</a>
                <div class="sList2">
                    <div class="clearfix">
                        <a href="${ctx}/page/zbproList.html">桌布罩件</a>
                        <a href="${ctx}/page/bzproList.html">抱枕靠垫</a>
                    </div>
                </div>
            </li>
            <li><a href="${ctx}/page/paint.html">墙式壁挂</a></li>
            <li><a href="${ctx}/page/perfume.html">蜡艺香薰</a></li>
            <li><a href="${ctx}/page/idea.html">创意家居</a></li>
        </ul>
    </div>
</div>

然后就是显示购物车的内容

<!DOCTYPE html>
<html>
	<head lang="en">
		<#include "common/head.html">
		<link rel="stylesheet" type="text/css" href="css/public.css"/>
		<link rel="stylesheet" type="text/css" href="css/proList.css" />
	</head>
	<body>
		<!--------------------------------------cart--------------------->
		<div class="head ding">
			<div class="wrapper clearfix">
				<div class="clearfix" id="top">
					<h1 class="fl"><a href="${ctx}/"><img src="img/logo.png"/></a></h1>
					<div class="fr clearfix" id="top1">
						<form action="#" method="get" class="fl">
							<input type="text" placeholder="搜索" />
							<input type="button" />
						</form>
					</div>
				</div>
			</div>
		</div>
		<div class="cart mt">
			<!-----------------logo------------------->
			<!--<div class="logo">
				<h1 class="wrapper clearfix">
					<a href="${ctx}/"><img class="fl" src="img/temp/logo.png"></a>
					<img class="top" src="img/temp/cartTop01.png">
				</h1>
			</div>-->
			<!-----------------site------------------->
			<div class="site">
				<p class=" wrapper clearfix">
					<span class="fl">购物车</span>
					<img class="top" src="img/temp/cartTop01.png">
					<a href="${ctx}/" class="fr">继续购物&gt;</a>
				</p>
			</div>
			<!-----------------table------------------->
			<div class="table wrapper">
				<div class="tr">
					<div>商品</div>
					<div>单价</div>
					<div>数量</div>
					<div>小计</div>
					<div>操作</div>
				</div>
				<#list cart as c >
				<div class="th">
					<div class="pro clearfix">
						<label class="fl">
							<input type="checkbox"/>
							<span></span>
						</label>
						<a class="fl" href="#">
							<dl class="clearfix">
								<dt class="fl"><img src="${(c.goodsImg)!}" style="width: 120px; height: 120px;"></dt>
								<dd class="fl">
									<p >${(c.goodsTitle)!}</p>
								</dd>
							</dl>
						</a>
					</div>
					<div class="price" style="margin-left:100px;">${(c.goodsPrice)!}</div>
					<div class="number">
						<p class="num clearfix">
							<img class="fl sub" src="img/temp/sub.jpg">
							<span class="fl">1</span>
							<img class="fl add" src="img/temp/add.jpg">
						</p>
					</div>
					<div class="price sAll" style="margin-left:80px;">¥20.00</div>
					<div class="price"><a class="del" href="#2"  style="margin-left:40px;">删除</a></div>
				</div>
				</#list>
				<div class="goOn">空空如也~<a href="${ctx}/">去逛逛</a></div>
				<div class="tr clearfix">
					<label class="fl">
						<input class="checkAll" type="checkbox"/>
						<span></span>
					</label>
					<p class="fl">
						<a href="javascript:void(0);">全选</a>
						<a href="javascript:void(0);" class="del">删除</a>
					</p>
					<p class="fr">
						<span>共<small id="sl">0</small>件商品</span>
						<span>合计:&nbsp;<small id="all">¥0.00</small></span>
						<a class="count">结算</a>
					</p>
				</div>
			</div>
		</div>
		<div class="mask"></div>
		<div class="tipDel">
			<p>确定要删除该商品吗?</p>
			<p class="clearfix">
				<a class="fl cer" href="javascript:void(0);">确定</a>
				<a class="fr cancel" href="javascript:void(0);">取消</a>
			</p>
		</div>
		<!--返回顶部-->
		<#include "common/footer.html">
		<!----------------mask------------------->
		<div class="mask"></div>
		<!-------------------mask内容------------------->
		<div class="proDets">
			<img class="off" src="img/temp/off.jpg" />
			<div class="proCon clearfix">
				<div class="proImg fr">
					<img class="list" src="img/temp/proDet.jpg"  />
					<div class="smallImg clearfix">
						<img src="img/temp/proDet01.jpg" data-src="img/temp/proDet01_big.jpg">
						<img src="img/temp/proDet02.jpg" data-src="img/temp/proDet02_big.jpg">
						<img src="img/temp/proDet03.jpg" data-src="img/temp/proDet03_big.jpg">
						<img src="img/temp/proDet04.jpg" data-src="img/temp/proDet04_big.jpg">
					</div>
				</div>
				<div class="fl">
					<div class="proIntro change">
						<p>颜色分类</p>
						<div class="smallImg clearfix">
							<p class="fl on"><img src="img/temp/prosmall01.jpg" alt="白瓷花瓶+20支快乐花" data-src="img/temp/proBig01.jpg"></p>
							<p class="fl"><img src="img/temp/prosmall02.jpg" alt="白瓷花瓶+20支兔尾巴草" data-src="img/temp/proBig02.jpg"></p>
							<p class="fl"><img src="img/temp/prosmall03.jpg" alt="20支快乐花" data-src="img/temp/proBig03.jpg"></p>
							<p class="fl"><img src="img/temp/prosmall04.jpg" alt="20支兔尾巴草" data-src="img/temp/proBig04.jpg"></p>
						</div>
					</div>
					<div class="changeBtn clearfix">
						<a href="#2" class="fl"><p class="buy">确认</p></a>
						<a href="#2" class="fr"><p class="cart">取消</p></a>
					</div>
				</div>
			</div>
		</div>
		<div class="pleaseC">
			<p>请选择宝贝</p>
			<img class="off" src="img/temp/off.jpg" />
		</div>
		<script src="js/public.js" type="text/javascript" charset="utf-8"></script>
		<script src="js/pro.js" type="text/javascript" charset="utf-8"></script>
		<script src="js/cart.js" type="text/javascript" charset="utf-8"></script>
	</body>
</html>

3.参数解析器

先说明一下参数解析器说发挥的作用

参数解析器:它的主要作用是处理请求中的参数,无论是获取Cookie中的值,Header中的值,JSON参数解析器的主要作用是处理请求中的参数,无论是获取Cookie中的值,Header中的值,JSON格式的数据,URI中的值,还是请求体中的数据,都可以通过相应的参数解析器来提取。

其中我们的代码中,是将用户的数据放到了redis以及cookie中,用户的数据又需要再很多的地方获取到【购物车,订单...】,所以我们可以专门写一个user的参数解析器

package com.wh.easyshop.util;

import com.wh.easyshop.model.User;
import com.wh.easyshop.service.IRedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.HttpServletRequest;

/**
 * 用户参数解析器,用于从请求中获取User对象
 */
@Component
public class UserArgumentResolver implements HandlerMethodArgumentResolver {

    @Autowired
    private IRedisService redisService;

    /**
     * 判断是否支持该类型的参数解析
     * @param parameter 方法参数
     * @return 如果支持返回true,否则返回false
     */
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterType() == User.class;
    }

    /**
     * 解析请求中的参数,并返回User对象
     * @param parameter 方法参数
     * @param mavContainer ModelAndView容器
     * @param webRequest NativeWebRequest对象
     * @param binderFactory WebDataBinderFactory对象
     * @return User对象
     * @throws Exception 解析过程中可能出现的异常
     */
    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
        // 从cookie中获得userToken
        String token = CookieUtils.getCookieValue(request, "UserToken");
        // 使用Redis服务加载User对象
        User user = redisService.getUserByToken(token);
        return user;
    }
}

为了让参数解析器生效,我们还需要一个配置类

package com.wh.easyshop.util;
import com.wh.easyshop.util.UserArgumentResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

/**
 * WebConfig类,用于配置Spring MVC的参数解析器
 */
@Component
public class WebConfig implements WebMvcConfigurer {

    // 注入UserArgumentResolver实例
    @Autowired
    private UserArgumentResolver userArgumentResolver;

    /**
     * 重写addArgumentResolvers方法,将UserArgumentResolver添加到参数解析器列表中
     * @param resolvers 参数解析器列表
     */
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(userArgumentResolver);
    }

}

现在就可以使用参数解析器了

package com.wh.easyshop.controller;

import com.wh.easyshop.model.Goods;
import com.wh.easyshop.model.User;
import com.wh.easyshop.resp.JsonResponseBody;
import com.wh.easyshop.service.IGoodsService;
import com.wh.easyshop.service.IRedisService;
import com.wh.easyshop.util.CookieUtils;
import com.wh.easyshop.vo.CartVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.jws.WebParam;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 购物车 前端控制器
 * </p>
 *
 * @author wh
 * @since 2024-1-2
 */
@Controller
@RequestMapping("/cart")
public class CartController {
    @Autowired
    IRedisService redisService;
    @Autowired
    IGoodsService goodsService;

    @RequestMapping("/toCart")
    public String index (User user,HttpServletRequest request, Model model) {
        List<CartVo> cartVos = redisService.loadCart(user);//使用参数解析器
        //拿出所有的购物车中的商id--集合
        List<Long> ids = cartVos.stream().map(CartVo::getGid).collect(Collectors.toList());
        //根据这个id集合查询所有对应的商品
        List<Goods> goods = goodsService.listByIds(ids);
        //遍历集合 赋值给对应的对象
        for (Goods g : goods) {
            //找到对应id相同的元素
            CartVo vo = cartVos.stream()
                    .filter(v -> Objects.equals(v.getGid(), g.getGid()))
                    .findFirst()
                    .get();
            //将商品g的属性赋值给vo【这样vo中的属性就有数据了】
            BeanUtils.copyProperties(g,vo);
        }
        model.addAttribute("cart",cartVos);
        return "cart";
    }


}

4.购物车的前端优化

其中的小计和总计都还没有计算显示出来以及商品数量的加减,这里就把它优化一下

html

<!DOCTYPE html>
<html>
	<head lang="en">
		<#include "common/head.html">
		<link rel="stylesheet" type="text/css" href="css/public.css"/>
		<link rel="stylesheet" type="text/css" href="css/proList.css" />
	</head>
	<body>
		<!--------------------------------------cart--------------------->
		<div class="head ding">
			<div class="wrapper clearfix">
				<div class="clearfix" id="top">
					<h1 class="fl"><a href="${ctx}/"><img src="img/logo.png"/></a></h1>
					<div class="fr clearfix" id="top1">
						<form action="#" method="get" class="fl">
							<input type="text" placeholder="搜索" />
							<input type="button" />
						</form>
					</div>
				</div>
			</div>
		</div>
		<div class="cart mt">
			<!-----------------logo------------------->
			<!--<div class="logo">
				<h1 class="wrapper clearfix">
					<a href="${ctx}/"><img class="fl" src="img/temp/logo.png"></a>
					<img class="top" src="img/temp/cartTop01.png">
				</h1>
			</div>-->
			<!-----------------site------------------->
			<div class="site">
				<p class=" wrapper clearfix">
					<span class="fl">购物车</span>
					<img class="top" src="img/temp/cartTop01.png">
					<a href="${ctx}/" class="fr">继续购物&gt;</a>
				</p>
			</div>
			<!-----------------table------------------->
			<div class="table wrapper">
				<div class="tr">
					<div>商品</div>
					<div>单价</div>
					<div>数量</div>
					<div>小计</div>
					<div>操作</div>
				</div>
				<#list cart as c >
				<div class="th">
					<div class="pro clearfix">
						<label class="fl">
							<input type="checkbox" class="cartCheckBox"/>
							<span></span>
						</label>
						<a class="fl" href="#">
							<dl class="clearfix">
								<dt class="fl"><img src="${(c.goodsImg)!}" style="width: 100px; height: 100px;"></dt>
								<dd class="fl">
									<p >${(c.goodsTitle)!}</p>
								</dd>
							</dl>
						</a>
					</div>
					<div class="price myprice" style="">${(c.goodsPrice)!}</div>
					<div class="number">
						<p class="num clearfix">
							<img class="fl sub"  src="img/temp/sub.jpg">
							<span class="fl mynum" data-gid="${c.gid}">${c.num}</span>
							<img class="fl add"  src="img/temp/add.jpg">
						</p>
					</div>
					<div class="price sAll" >¥${(c.xj())!}</div>
					<div class="price"><a class="del"  data-gid="${c.gid}" >删除</a></div>
				</div>
				</#list>
				<div class="goOn">空空如也~<a href="${ctx}/">去逛逛</a></div>
				<div class="tr clearfix">
					<label class="fl">
						<input class="checkAll" type="checkbox"/>
						<span></span>
					</label>
					<p class="fl">
						<a href="javascript:void(0);">全选</a>
						<a  class="del" >删除</a>
					</p>
					<p class="fr">
						<span>共<small id="sl">0</small>件商品</span>
						<span>合计:&nbsp;<small id="all">¥0.00</small></span>
						<a class="count">结算</a>
					</p>
				</div>
			</div>
		</div>
		<div class="mask"></div>
		<div class="tipDel">
			<p>确定要删除该商品吗?</p>
			<p class="clearfix">
				<a class="fl cer" href="javascript:void(0);">确定</a>
				<a class="fr cancel" href="javascript:void(0);">取消</a>
			</p>
		</div>
		<!--返回顶部-->
		<#include "common/footer.html">
		<!----------------mask------------------->
		<div class="mask"></div>
		<!-------------------mask内容------------------->
		<div class="proDets">
			<img class="off" src="img/temp/off.jpg" />
			<div class="proCon clearfix">
				<div class="proImg fr">
					<img class="list" src="img/temp/proDet.jpg"  />
					<div class="smallImg clearfix">
						<img src="img/temp/proDet01.jpg" data-src="img/temp/proDet01_big.jpg">
						<img src="img/temp/proDet02.jpg" data-src="img/temp/proDet02_big.jpg">
						<img src="img/temp/proDet03.jpg" data-src="img/temp/proDet03_big.jpg">
						<img src="img/temp/proDet04.jpg" data-src="img/temp/proDet04_big.jpg">
					</div>
				</div>
				<div class="fl">
					<div class="proIntro change">
						<p>颜色分类</p>
						<div class="smallImg clearfix">
							<p class="fl on"><img src="img/temp/prosmall01.jpg" alt="白瓷花瓶+20支快乐花" data-src="img/temp/proBig01.jpg"></p>
							<p class="fl"><img src="img/temp/prosmall02.jpg" alt="白瓷花瓶+20支兔尾巴草" data-src="img/temp/proBig02.jpg"></p>
							<p class="fl"><img src="img/temp/prosmall03.jpg" alt="20支快乐花" data-src="img/temp/proBig03.jpg"></p>
							<p class="fl"><img src="img/temp/prosmall04.jpg" alt="20支兔尾巴草" data-src="img/temp/proBig04.jpg"></p>
						</div>
					</div>
					<div class="changeBtn clearfix">
						<a href="#2" class="fl"><p class="buy">确认</p></a>
						<a href="#2" class="fr"><p class="cart">取消</p></a>
					</div>
				</div>
			</div>
		</div>
		<div class="pleaseC">
			<p>请选择宝贝</p>
			<img class="off" src="img/temp/off.jpg" />
		</div>
		<script src="js/public.js" type="text/javascript" charset="utf-8"></script>
		<script src="js/pro.js" type="text/javascript" charset="utf-8"></script>
		<script src="js/cart.js" type="text/javascript" charset="utf-8"></script>
	</body>
</html>

js

$(function(){


	//计算总价&计算小计
	function jisuan(){
		//小计和总价他们都放在一个大的盒子(th)
		//所以去拿到这个大和盒子,遍历得到每个的价格和数量=>小计和总价
		let total=0;//计算总价
		$(".th").each((i,el)=>{
			//获得价格
			let price=$(el).find(".myprice").text().replace("¥","")
			//获得价格
			let count=$(el).find(".mynum").text()*1
			//计算小计
			$(el).find(".sAll").text("¥"+price*count)
			//子复选框--选中状态
			let flag =$(el).find('input[type=checkbox]').prop('checked')
			//如果元素被选择了
			if(flag){
				total+=price*count
			}
		})
		//把计算出来的总价给到相应的元素
		$("#all").text("¥"+total);
	}
	
	/**************数量加减***************/
	$(".num .sub").click(function () {
		update(this,-1)
	});

	$(".num .add").click(function () {
		update(this,1)
	});

	/**
	 * 更新购物车中指定商品的数量
	 * @param ele
	 * @param count
	 */
	function update(ele,count){
		//存放数量的元素【mynum是自己定义的】
		let el = $(ele).parent().find(".mynum")
		//拿到原来的内容
		let num = el.text()*1
		//加上变化的数量
		num+=count;
		//判断是否是正确数量
		if(num<=0) return
		//将数量改变到页面上去
		el.text(num)
		//获得数量
		let gid = el.attr('data-gid')
		//访问后端
		$.post('/cart/edit',{gid,num},resp=>{
			if(resp.code===200)
			jisuan()
		})
	}
})

更新数量的control后端处理

service

package com.wh.easyshop.service;


import com.wh.easyshop.model.User;
import com.wh.easyshop.vo.CartVo;

import java.util.List;

public interface IRedisService {

   

    /**
     * 修改购物车
     * @param user
     * @param cartVo
     */
    void editCart(CartVo cartVo,User user);


    void delCart(List<String> ids, User user);
}
package com.wh.easyshop.service;

import com.wh.easyshop.model.User;
import com.wh.easyshop.util.Constants;
import com.wh.easyshop.vo.CartVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class RedisServiceImpl implements IRedisService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;


    @Override
    public void editCart(CartVo cartVo,User user) {

        //获取操Redi中hash类型数据对象--通过其将购物车存入到缓存中
        HashOperations<String, String , CartVo> rediscart = redisTemplate.opsForHash();
        //大键【hash的键】
        String hashKey=Constants.REDIS_CART_PREFIX + user.getId();
        //小键【hash中键值对的键】--存入的商品id
        String ValueKey=cartVo.getGid().toString();
        //往缓存中加入数据(覆盖原来的数据)
        rediscart.put(hashKey,ValueKey,cartVo);
    }

   

}

controller

package com.wh.easyshop.controller;

import com.wh.easyshop.model.Goods;
import com.wh.easyshop.model.User;
import com.wh.easyshop.resp.JsonResponseBody;
import com.wh.easyshop.service.IGoodsService;
import com.wh.easyshop.service.IRedisService;
import com.wh.easyshop.util.CookieUtils;
import com.wh.easyshop.vo.CartVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.jws.WebParam;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 购物车 前端控制器
 * </p>
 *
 * @author wh
 * @since 2024-1-2
 */
@Controller
@RequestMapping("/cart")
public class CartController {
    @Autowired
    IRedisService redisService;
    @Autowired
    IGoodsService goodsService;


    @RequestMapping("/edit")
    @ResponseBody
    public JsonResponseBody<?> editCart(CartVo cartVo,User user) {
        //修改用户的购物车信息
        redisService.editCart(cartVo,user);
        return JsonResponseBody.success() ;
    }

}

以上代码中都写有注释,而且逻辑也比较清晰,在这里就没有做过多的解析了

5.购物车的删除【单个&批量】

html

<!DOCTYPE html>
<html>
	<head lang="en">
		<#include "common/head.html">
		<link rel="stylesheet" type="text/css" href="css/public.css"/>
		<link rel="stylesheet" type="text/css" href="css/proList.css" />
	</head>
	<body>
		<!--------------------------------------cart--------------------->
		<div class="head ding">
			<div class="wrapper clearfix">
				<div class="clearfix" id="top">
					<h1 class="fl"><a href="${ctx}/"><img src="img/logo.png"/></a></h1>
					<div class="fr clearfix" id="top1">
						<form action="#" method="get" class="fl">
							<input type="text" placeholder="搜索" />
							<input type="button" />
						</form>
					</div>
				</div>
			</div>
		</div>
		<div class="cart mt">
			<!-----------------logo------------------->
			<!--<div class="logo">
				<h1 class="wrapper clearfix">
					<a href="${ctx}/"><img class="fl" src="img/temp/logo.png"></a>
					<img class="top" src="img/temp/cartTop01.png">
				</h1>
			</div>-->
			<!-----------------site------------------->
			<div class="site">
				<p class=" wrapper clearfix">
					<span class="fl">购物车</span>
					<img class="top" src="img/temp/cartTop01.png">
					<a href="${ctx}/" class="fr">继续购物&gt;</a>
				</p>
			</div>
			<!-----------------table------------------->
			<div class="table wrapper">
				<div class="tr">
					<div>商品</div>
					<div>单价</div>
					<div>数量</div>
					<div>小计</div>
					<div>操作</div>
				</div>
				<#list cart as c >
				<div class="th">
					<div class="pro clearfix">
						<label class="fl">
							<input type="checkbox" class="cartCheckBox"/>
							<span></span>
						</label>
						<a class="fl" href="#">
							<dl class="clearfix">
								<dt class="fl"><img src="${(c.goodsImg)!}" style="width: 100px; height: 100px;"></dt>
								<dd class="fl">
									<p >${(c.goodsTitle)!}</p>
								</dd>
							</dl>
						</a>
					</div>
					<div class="price myprice" style="">${(c.goodsPrice)!}</div>
					<div class="number">
						<p class="num clearfix">
							<img class="fl sub"  src="img/temp/sub.jpg">
							<span class="fl mynum" data-gid="${c.gid}">${c.num}</span>
							<img class="fl add"  src="img/temp/add.jpg">
						</p>
					</div>
					<div class="price sAll" >¥${(c.xj())!}</div>
					<div class="price"><a class="del"  data-gid="${c.gid}" >删除</a></div>
				</div>
				</#list>
				<div class="goOn">空空如也~<a href="${ctx}/">去逛逛</a></div>
				<div class="tr clearfix">
					<label class="fl">
						<input class="checkAll" type="checkbox"/>
						<span></span>
					</label>
					<p class="fl">
						<a href="javascript:void(0);">全选</a>
						<a  class="del" >删除</a>
					</p>
					<p class="fr">
						<span>共<small id="sl">0</small>件商品</span>
						<span>合计:&nbsp;<small id="all">¥0.00</small></span>
						<a class="count">结算</a>
					</p>
				</div>
			</div>
		</div>
		<div class="mask"></div>
		<div class="tipDel">
			<p>确定要删除该商品吗?</p>
			<p class="clearfix">
				<a class="fl cer" href="javascript:void(0);">确定</a>
				<a class="fr cancel" href="javascript:void(0);">取消</a>
			</p>
		</div>
		<!--返回顶部-->
		<#include "common/footer.html">
		<!----------------mask------------------->
		<div class="mask"></div>
		<!-------------------mask内容------------------->
		<div class="proDets">
			<img class="off" src="img/temp/off.jpg" />
			<div class="proCon clearfix">
				<div class="proImg fr">
					<img class="list" src="img/temp/proDet.jpg"  />
					<div class="smallImg clearfix">
						<img src="img/temp/proDet01.jpg" data-src="img/temp/proDet01_big.jpg">
						<img src="img/temp/proDet02.jpg" data-src="img/temp/proDet02_big.jpg">
						<img src="img/temp/proDet03.jpg" data-src="img/temp/proDet03_big.jpg">
						<img src="img/temp/proDet04.jpg" data-src="img/temp/proDet04_big.jpg">
					</div>
				</div>
				<div class="fl">
					<div class="proIntro change">
						<p>颜色分类</p>
						<div class="smallImg clearfix">
							<p class="fl on"><img src="img/temp/prosmall01.jpg" alt="白瓷花瓶+20支快乐花" data-src="img/temp/proBig01.jpg"></p>
							<p class="fl"><img src="img/temp/prosmall02.jpg" alt="白瓷花瓶+20支兔尾巴草" data-src="img/temp/proBig02.jpg"></p>
							<p class="fl"><img src="img/temp/prosmall03.jpg" alt="20支快乐花" data-src="img/temp/proBig03.jpg"></p>
							<p class="fl"><img src="img/temp/prosmall04.jpg" alt="20支兔尾巴草" data-src="img/temp/proBig04.jpg"></p>
						</div>
					</div>
					<div class="changeBtn clearfix">
						<a href="#2" class="fl"><p class="buy">确认</p></a>
						<a href="#2" class="fr"><p class="cart">取消</p></a>
					</div>
				</div>
			</div>
		</div>
		<div class="pleaseC">
			<p>请选择宝贝</p>
			<img class="off" src="img/temp/off.jpg" />
		</div>
		<script src="js/public.js" type="text/javascript" charset="utf-8"></script>
		<script src="js/pro.js" type="text/javascript" charset="utf-8"></script>
		<script src="js/cart.js" type="text/javascript" charset="utf-8"></script>
	</body>
</html>

js

$(function(){


	
	/*****************商品全选--全选框***********************/
	$(".checkAll").on('click',function(){
			//当全选框被选中时,其他的子复选框也要被选中
			$(".cartCheckBox").prop("checked", $(".checkAll").prop("checked"));
		jisuan()
		});
	/*****************商品全选--子复选框***********************/
			//给子复选框添加点击事件
		$(".cartCheckBox").on('click',function() {
			// console.log($(".other").length)
			//如果被选中的子复选框的长度等于所有的已有的子复选框的长度
			if ($(".cartCheckBox:checked").length === $(".cartCheckBox").length) {
				//就把全选框设置为选中状态
				$(".checkAll").prop("checked", true);
			} else {
				//否则就把全选框设置为未选中状态
				$(".checkAll").prop("checked", false);
			}
			jisuan()
		})




	//删除购物车商品
	$('.del').click(function() {

		//获取id
		let gid=$(this).attr('data-gid')
		//用一个容器来存放所有的商品id
		let ids=[]
		//如果带了id过来就是删除单个,没有带的话就是批量删除
		if(gid){
		ids.push(gid)
		}else{
			$(".th").each((i,el)=>{
				//子复选框--选中状态
				let flag =$(el).find('input[type=checkbox]').prop('checked')
				//如果元素被选择了
				if(flag){
					let id=$(el).find('.mynum').attr('data-gid')
					ids.push(id)
				}
			})
		}
		if(ids.length>0){
			$.post('/cart/del',{ids},resp=>{
				if(resp.code===200){
					alert("删除成功")
				}
			},'json')
		}

	})
	
	
})

service

package com.wh.easyshop.service;


import com.wh.easyshop.model.User;
import com.wh.easyshop.vo.CartVo;

import java.util.List;

public interface IRedisService {

 

    void delCart(List<String> ids, User user);
}
package com.wh.easyshop.service;

import com.wh.easyshop.model.User;
import com.wh.easyshop.util.Constants;
import com.wh.easyshop.vo.CartVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class RedisServiceImpl implements IRedisService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

  

    /**
     * 删除购物车
     * @param ids
     * @param user
     */
    @Override
    public void delCart(List<String> ids, User user) {
        //获取操Redi中hash类型数据对象--通过其将购物车存入到缓存中
        HashOperations<String, String , CartVo> rediscart = redisTemplate.opsForHash();
        //大键【hash的键】
        String hashKey=Constants.REDIS_CART_PREFIX + user.getId();
        for (String id : ids) {
            rediscart.delete(hashKey,id);
        }
    }

}

controller

package com.wh.easyshop.controller;

import com.wh.easyshop.model.Goods;
import com.wh.easyshop.model.User;
import com.wh.easyshop.resp.JsonResponseBody;
import com.wh.easyshop.service.IGoodsService;
import com.wh.easyshop.service.IRedisService;
import com.wh.easyshop.util.CookieUtils;
import com.wh.easyshop.vo.CartVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.jws.WebParam;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 购物车 前端控制器
 * </p>
 *
 * @author wh
 * @since 2024-1-2
 */
@Controller
@RequestMapping("/cart")
public class CartController {
    @Autowired
    IRedisService redisService;
    @Autowired
    IGoodsService goodsService;



    @RequestMapping("/del")
    @ResponseBody
    public JsonResponseBody<?> delCart(@RequestParam("ids[]") List<String> ids, User user) {
        //删除用户的购物车信息
        redisService.delCart(ids,user);
        return JsonResponseBody.success() ;
    }


}

其中删除的时候,从前端带过来的数据格式是作用的👇

但是后端接受的数据是这样的,数据之间不一致,就会出现错误

为了成功的接受的前端的数据,我们可以使用一个注解

@RequestParam("ids[]")

@RequestParam("ids[]")

????????是一个Java注解,用于将请求参数绑定到方法的参数上。在这个例子中,它指示控制器方法需要从请求参数中获取名为"ids[]"的值并将其绑定到一个List类型的方法参数上。

????????具体来说,当你在URL或表单中发送一个请求时,你可以通过在请求中包含名为"ids[]"的参数来传递一个ID列表。@RequestParam("ids[]")告诉Spring框架去查找这个参数,并将其值绑定到方法参数上。这样,在方法内部,你就可以像使用普通的Java List一样使用这个参数了。

????????需要注意的是,注解中的参数名称应该和请求参数的名称一致,这样Spring才能正确地将参数值绑定到方法参数上

好啦,今天的分享就到这了,希望能够帮到你呢!😊😊??

文章来源:https://blog.csdn.net/m0_74315688/article/details/135339063
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。