🥳🥳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>数量 库存<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(){//获得需要添加到购物车中的商品idlet 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 {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;/*** 将购物车数据存入缓存中* @param user* @param cartVo*/@Overridepublic 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中键值对的键】--存入的商品idString 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 {@AutowiredIRedisService redisService;@AutowiredIGoodsService goodsService;@RequestMapping("/add")@ResponseBodypublic 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 {@AutowiredIRedisService redisService;@AutowiredIGoodsService 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 {@AutowiredIRedisService redisService;@AutowiredIGoodsService 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">继续购物></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>合计: <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 {@Autowiredprivate IRedisService redisService;/*** 判断是否支持该类型的参数解析* @param parameter 方法参数* @return 如果支持返回true,否则返回false*/@Overridepublic 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 解析过程中可能出现的异常*/@Overridepublic Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();// 从cookie中获得userTokenString 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实例@Autowiredprivate UserArgumentResolver userArgumentResolver;/*** 重写addArgumentResolvers方法,将UserArgumentResolver添加到参数解析器列表中* @param resolvers 参数解析器列表*/@Overridepublic 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 {@AutowiredIRedisService redisService;@AutowiredIGoodsService 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">继续购物></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>合计: <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 {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;@Overridepublic 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中键值对的键】--存入的商品idString 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 {@AutowiredIRedisService redisService;@AutowiredIGoodsService goodsService;@RequestMapping("/edit")@ResponseBodypublic 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">继续购物></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>合计: <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() {//获取idlet gid=$(this).attr('data-gid')//用一个容器来存放所有的商品idlet 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 {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;/*** 删除购物车* @param ids* @param user*/@Overridepublic 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 {@AutowiredIRedisService redisService;@AutowiredIGoodsService goodsService;@RequestMapping("/del")@ResponseBodypublic 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才能正确地将参数值绑定到方法参数上
好啦,今天的分享就到这了,希望能够帮到你呢!😊😊