【项目学习】谷粒商城学习记录8 - 购物车
【项目学习】谷粒商城学习记录8 - 购物车
本节起将不对一些重复细节进行详细说明
一、环境搭建 & 准备工作
1.1. 创建新模块
- 注意java版本信息后面在pom.xml文件里修改
- 导入公共模块依赖
- 写配置信息
- 启动类加上注册发现和Feign功能
- 修改网关
- id: gulimall_cart_route uri: lb://gulimall-cart predicates: - Host=cart.gulimall.cn
1.2. 静态页面搭建
- 设置域名
- 将注册页面和登录页面放在服务资源目录下
- 登录、注册页面动静分离,将静态资源移到nginx下
- 修改页面内的路径
- 测试:
1.3. 数据存储结构:
1.4. 完善页面细节,实现页面跳转
二、ThreadLocal 用户身份鉴别
-
创建service.CartService和impl.CartServiceImpl
-
创建拦截器interceptor.CartInterceptor
-
实现拦截器在业务执行前的功能:
public class CartInterceptor implements HandlerInterceptor { public static ThreadLocal<UserInfoTo> threadLocal = new ThreadLocal<>(); /** * 目标方法执行之前 * @param request * @param response * @param handler * @return * @throws Exception */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { UserInfoTo userInfoTo = new UserInfoTo(); HttpSession session = request.getSession(); MemberRespVo member = (MemberRespVo) session.getAttribute(AuthServerConstant.LOGIN_USER); if(member != null) { //用户登录了 userInfoTo.setUserId(member.getId()); } Cookie[] cookies = request.getCookies(); if(cookies != null && cookies.length > 0) { for (Cookie cookie : cookies) { //user-key String name = cookie.getName(); if(name.equals(CartConstant.TEMP_USER_COOKIE_NAME)) { userInfoTo.setUserKey(cookie.getValue()); userInfoTo.setTempUser(true); } } } //如果没有临时用户一定分配一个临时用户 if(StringUtils.isEmpty(userInfoTo.getUserKey())) { String uuid = UUID.randomUUID().toString(); userInfoTo.setUserKey(uuid); } //目标方法执行之前 threadLocal.set(userInfoTo); return true; } }
-
ThreadLocal能够在整个线程内共享数据
-
测试:
-
实现拦截器在业务处理后的功能
/** * 业务执行之后,分配临时用户,让浏览器保存 * @param request * @param response * @param handler * @param modelAndView * @throws Exception */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { UserInfoTo userInfoTo = threadLocal.get(); if(!userInfoTo.isTempUser()) { Cookie cookie = new Cookie(CartConstant.TEMP_USER_COOKIE_NAME, userInfoTo.getUserKey()); cookie.setDomain("gulimall.com"); cookie.setMaxAge(CartConstant.TEMP_USER_COOKIE_TIMEOUT); response.addCookie(cookie); } }
-
测试:
三、实现添加购物车功能
-
商品详情页点击添加购物车后,将传递skuId和numInput两个参数
-
测试
登陆后不再使用临时用户
-
为了避免链接被多次刷新,使用页面重定向的方式。即添加后重定向到展示页面
- 代码
/** * 添加商品到购物车 * @return */ @GetMapping("/addToCart") public String addToCart(@RequestParam("skuId") Long skuId, @RequestParam("num") Integer num, RedirectAttributes ra) throws ExecutionException, InterruptedException { cartService.addToCart(skuId, num); ra.addAttribute("skuId", skuId); return "redirect:/addToCartSuccess.html"; } @GetMapping("/addToCartSuccess.html") public String addToCartSuccessPage(@RequestParam("skuId") Long skuId, Model model) { //重定向到成功页面,查询购物车数据 CartItem cartItem = cartService.getCartItem(skuId); model.addAttribute("item", cartItem); return "success"; }
getCartItem
方法具体实现@Override public CartItem getCartItem(Long skuId) { BoundHashOperations<String, Object, Object> cartOps = getCartOps(); String str = (String) cartOps.get(skuId.toString()); CartItem cartItem = JSON.parseObject(str, CartItem.class); return cartItem; }
- 代码
-
实现获取购物车,合并购物车功能
- 测试:
实现购物车合并成功
- 测试:
-
实现修改购物车状态
- 前端页面绑定点击事件
$(".itemCheck").click(function () { var skuId = $(this).attr("skuId"); var check = $(this).prop("checked"); location.href = "http://cart.gulimall.com/checkItem?skuId="+skuId+"&check="+(check ? 1 : 0); })
- controller层
/** * 修改购物项选择状态 * @param skuId * @param check * @return */ @GetMapping("/checkItem") public String checkItem(@RequestParam("skuId") Long skuId, @RequestParam("check") Integer check) { cartService.checkItem(skuId, check); return "redirect:http://cart.gulimall.com/cart.html"; }
- 具体实现
@Override public void checkItem(Long skuId, Integer check) { BoundHashOperations<String, Object, Object> cartOps = getCartOps(); CartItem cartItem = getCartItem(skuId); cartItem.setCheck(check == 1); String s = JSON.toJSONString(cartItem); cartOps.put(skuId.toString(), s); }
- 前端页面绑定点击事件
-
实现增减购物车选项数量
- 前端修改
$(".countOpsBtn").click(function () { var skuId = $(this).parent().attr("skuId"); var num = $(this).parent().find(".countOpsNum").text(); location.href = "http://cart.gulimall.com/countItem?skuId="+skuId+"&num="+num; })
- controller层
/** * 修改购物车选项数量 * @param skuId * @param num * @return */ @GetMapping("/countItem") public String countItem(@RequestParam("skuId") Long skuId, @RequestParam("num") Integer num) { cartService.changeItemCount(skuId, num); return "redirect:http://cart.gulimall.com/cart.html"; }
- 具体实现
/** * 修改购物选项数量 * @param skuId * @param num */ @Override public void changeItemCount(Long skuId, Integer num) { BoundHashOperations<String, Object, Object> cartOps = getCartOps(); CartItem cartItem = getCartItem(skuId); cartItem.setCount(num); String s = JSON.toJSONString(cartItem); cartOps.put(skuId.toString(), s); }
- 前端修改
-
实现删除购物车选项功能
- 前端修改:
var deleteId = 0; //删除购物项 function deleteItem() { location.href = "http://cart.gulimall.com/deleteItem?skuId="+deleteId; } $(".deleteItemBtn").click(function () { deleteId = $(this).attr("skuId"); })
- controller
/** * 删除购物车选项 * @param skuId * @return */ @GetMapping("/deleteItem") public String deleteItem(@RequestParam("skuId") Long skuId) { cartService.deleteItem(skuId); return "redirect:http://cart.gulimall.com/cart.html"; }
- 具体实现
/** * 删除购物车选项 * @param skuId */ @Override public void deleteItem(Long skuId) { BoundHashOperations<String, Object, Object> cartOps = getCartOps(); cartOps.delete(skuId.toString()); }
- 前端修改:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通