谷粒商城实战笔记-240~243-商城业务-购物车-页面环境搭建

news2024/11/16 21:27:32

文章目录

  • 一,页面调整
    • 1,详情页增加“加入购物车”按钮
  • 二,添加购物车后台实现
      • 详细步骤
      • 异步处理的优点
  • 三,解决加购重复提交问题

这部分的主要内容:

  • 从product模块的详情页点击加入购物车,发送请求到cart购物车模块,添加成功后,跳转到success页面。
  • 详情页点击和首页点击我的购物车,向购物车服务发送请求,挑战到cartItem页面。
  • success页面点击去购物车结算跳转到结算页(即购物车列表页)
  • 完成添加购物车的后台逻辑
  • 解决重复提交的问题
    在这里插入图片描述

包含下面课程:

  • 240-商城业务-购物车-页面环境搭建
  • 241-商城业务-购物车-添加购物车
  • 242-商城业务-购物车-添加购物车细节
  • 243-商城业务-购物车-RedirectAttribute

一,页面调整

1,详情页增加“加入购物车”按钮

在这里插入图片描述
点击按钮向购物车服务发生请求。

加购成功后,跳转到success界面。

二,添加购物车后台实现

后台Service了一个名为 addToCart 的方法,用于将指定的商品添加到用户的购物车中。

添加到购物车中的主要逻辑如下:

  • 判断是已登录用户还是临时用户,不同类型的用户的redis key不同
  • redis中查询是否已经存在该skuId对应的商品
  • 如果存在,把该商品的数量加上页面上的值
  • 如果不存在,要调用远程接口查询sku的基本信息和销售属性信息,然后以skuid为key保存到redis中
 public CartItemVo addToCart(Long skuId, Integer num) throws ExecutionException, InterruptedException {

        //拿到要操作的购物车信息
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();

        //判断Redis是否有该商品的信息
        String productRedisValue = (String) cartOps.get(skuId.toString());
        //如果没有就添加数据
        if (StringUtils.isEmpty(productRedisValue)) {

            //2、添加新的商品到购物车(redis)
            CartItemVo cartItemVo = new CartItemVo();
            //开启第一个异步任务
            CompletableFuture<Void> getSkuInfoFuture = CompletableFuture.runAsync(() -> {
                //1、远程查询当前要添加商品的信息
                R productSkuInfo = productFeignService.getInfo(skuId);
                SkuInfoVo skuInfo = productSkuInfo.getData("skuInfo", new TypeReference<SkuInfoVo>() {});
                //数据赋值操作
                cartItemVo.setSkuId(skuInfo.getSkuId());
                cartItemVo.setTitle(skuInfo.getSkuTitle());
                cartItemVo.setImage(skuInfo.getSkuDefaultImg());
                cartItemVo.setPrice(skuInfo.getPrice());
                cartItemVo.setCount(num);
            }, executor);

            //开启第二个异步任务
            CompletableFuture<Void> getSkuAttrValuesFuture = CompletableFuture.runAsync(() -> {
                //2、远程查询skuAttrValues组合信息
                List<String> skuSaleAttrValues = productFeignService.getSkuSaleAttrValues(skuId);
                cartItemVo.setSkuAttrValues(skuSaleAttrValues);
            }, executor);

            //等待所有的异步任务全部完成
            CompletableFuture.allOf(getSkuInfoFuture, getSkuAttrValuesFuture).get();

            String cartItemJson = JSON.toJSONString(cartItemVo);
            cartOps.put(skuId.toString(), cartItemJson);

            return cartItemVo;
        } else {
            //购物车有此商品,修改数量即可
            CartItemVo cartItemVo = JSON.parseObject(productRedisValue, CartItemVo.class);
            cartItemVo.setCount(cartItemVo.getCount() + num);
            //修改redis的数据
            String cartItemJson = JSON.toJSONString(cartItemVo);
            cartOps.put(skuId.toString(),cartItemJson);

            return cartItemVo;
        }
    }



  1. 获取购物车操作对象:

    • 使用 getCartOps() 方法获取 Redis 中购物车相关的 BoundHashOperations 对象,用于后续的读写操作。
  2. 检查商品是否已经在购物车中:

    • 从 Redis 中查询当前商品 skuId 是否已经存在于购物车中。
    • 如果商品不存在,则需要从远程服务获取商品信息并将其添加到购物车;如果存在,则直接更新商品的数量。
  3. 商品不在购物车中的处理流程:

    • 创建一个新的 CartItemVo 实例。
    • 异步调用远程服务获取商品的基本信息,并填充到 CartItemVo 中。
    • 异步调用远程服务获取商品的属性值列表,并填充到 CartItemVo 中。
    • 等待所有异步任务完成。
    • CartItemVo 序列化为 JSON 字符串并存入 Redis。
  4. 商品已在购物车中的处理流程:

    • 从 Redis 中读取已存在的 CartItemVo 并反序列化。
    • 更新商品的数量。
    • 将更新后的 CartItemVo 再次序列化为 JSON 字符串并存回 Redis。

详细步骤

  1. 获取购物车操作对象:

    • 调用 getCartOps() 方法获取购物车的 BoundHashOperations 对象。
  2. 检查商品是否存在:

    • 检查商品是否已经在 Redis 购物车中。
  3. 商品不存在时:

    • 创建 CartItemVo 实例。
    • 使用 CompletableFuture 异步获取商品信息和属性值。
    • 等待所有异步任务完成。
    • CartItemVo 序列化并存入 Redis。
  4. 商品已存在时:

    • 从 Redis 获取 CartItemVo
    • 修改商品的数量。
    • 将更新后的 CartItemVo 序列化并存入 Redis。

异步处理的优点

  • 提高性能:通过异步处理,减少了等待远程服务响应的时间,从而提高了整体性能。
  • 提高响应速度:由于异步处理不需要等待所有任务完成就可以返回结果,因此能更快地响应客户端。

三,解决加购重复提交问题

我们加购的提交的地址是:

http://cart.gulimall.com/addCartItem?skuId=1&num=2

这个请求发出后,后台执行加购逻辑,如果直接返回success页面。

	@GetMapping(value = "/addCartItem")
    public String addToCart() {
        return "success";
    }

会导致一个问题,如果用户刷新这个页面,就会重复提交加购请求,这个商品会被重复加购,导致不好的客户体验。

所以不能把这个地址暴露在浏览器的地址栏。

参考京东的做法,我们可以在用户点击加购请求后不直接返回success页面,而是让浏览器重定向到一个新的地址,这个地址会返回sucess页面,但是这个地址不会有其他的业务逻辑。

具体的逻辑是这样:

  • 用户点击加购,浏览器发出加购请求
  • 后台接收处理加购请求,让浏览器重定向到一个新的地址
  • 这个地址对应的接口会返回success页面,但不执行其他逻辑,用户刷新不会导致加购的重复提交

代码如下。

@GetMapping(value = "/addCartItem")
    public String addCartItem(@RequestParam("skuId") Long skuId,
                              @RequestParam("num") Integer num,
                              RedirectAttributes attributes) throws ExecutionException, InterruptedException {

        cartService.addToCart(skuId,num);

        attributes.addAttribute("skuId",skuId);
        return "redirect:http://cart.gulimall.com/addToCartSuccessPage.html";
    }


    /**
     * 跳转到添加购物车成功页面
     * @param skuId
     * @param model
     * @return
     */
    @GetMapping(value = "/addToCartSuccessPage.html")
    public String addToCartSuccessPage(@RequestParam("skuId") Long skuId,
                                       Model model) {
        //重定向到成功页面。再次查询购物车数据即可
        CartItemVo cartItemVo = cartService.getCartItem(skuId);
        model.addAttribute("cartItem",cartItemVo);
        return "success";
    }

如果addCartItem接口直接返回success界面,那么浏览器地址栏的地址就是:

http://cart.gulimall.com/addCartItem?skuId=1&num=2

用户刷新浏览器,就会提交一个加购请求。

如果addCartItem接口重定向到其他接口,那么浏览器显示的地址就是:

http://cart.gulimall.com/addToCartSuccessPage.html?skuId=1

用户刷新页面,并不会导致加购的重复提交。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2066717.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kubernetes服务发布基础

一、Service 1.service基本介绍 service为一组提供服务的pod提供抽象的稳定的网络访问地址&#xff0c;主要用于网络服务&#xff0c;通过service定义&#xff0c;为客户端提供访问地址和负载均衡&#xff0c;屏蔽endport的变化。 在 kubernetes 中,pod 的IP 地址是动态变…

大数据面试-Zookeeper

你对Zookeeper的选举机制了解吗&#xff1f;为什么zk节点个数推荐奇数台&#xff1f;zk第一次启动的选举的细节了解吗&#xff1f; ‌ZooKeeper的选举机制‌是基于Paxos算法的一种分布式选举算法&#xff0c;用于在ZooKeeper集群中选择一个节点作为Leader&#xff0c;负责处理…

做外贸如何判断国外采购商公司规模

判断客户公司的规模&#xff0c;对于业务员来说很重要&#xff0c;这样在谈价格以及其他条款的时候才能掌握主动。一般要怎么去判断客户公司的规模呢?我们都是做实事的&#xff0c;实际经验很重要&#xff0c;做过和没做过的看多了就知道。最基本的信息是公司的注册时间及相关…

【python】Python中通过WHL文件离线安装需要的包最全面讲解

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

【oracle】工具访问oracle提示-IO 错误: Got minus one from a read call

问题描述&#xff1a; 使用工具访问数据库时&#xff0c;提示IO 错误: Got minus one from a read call&#xff0c;在服务器上检查数据库正常&#xff0c;监听正常&#xff0c;连接数合理&#xff0c;防火墙没限制。最后定位sqlnet.ora配置限制了客户端访问。 解决&#xf…

四川财谷通信息技术有限公司解锁抖音小店新机遇

在数字经济蓬勃发展的今天&#xff0c;电商平台已成为推动商业创新、促进消费升级的重要力量。其中&#xff0c;抖音小店凭借其庞大的用户基础、精准的算法推荐以及高度活跃的社区氛围&#xff0c;迅速崛起为众多商家青睐的创业与营销新阵地。四川财谷通信息技术有限公司&#…

Groovy DSL从入门到项目实战(一)

Groovy是一门很灵活的Java扩展语言&#xff0c;支持弱类型、闭包、函数式编程等脚本语言的高级特性。因为小卷所在公司的船申报系统需要重构&#xff0c;对原先java硬编码的各种表单数据校验、后台业务校验使用规则脚本的形式进行剥离出来。而市面上像Jboss Drools这样的规则引…

docker-compose安装sentry

官方文档 https://develop.sentry.dev/self-hosted/ 一、前提 服务器配置至少4C16G&#xff0c;否则起不来 二、安装docker https://blog.csdn.net/weixin_45112997/article/details/134532660 三、安装docker-compose docker-compose版本有要求&#xff0c;必须大于2.…

ISO7841标准数字隔离器在现代电子系统中的作用

在快速发展的电子领域&#xff0c;隔离元件在确保各种系统的安全性、可靠性和性能方面发挥着关键作用。其中&#xff0c;光耦合器是提供电气隔离同时允许电路不同部分之间进行信号传输的关键设备。ISO7841数字隔离器尤其体现了现代电子设计所需的先进功能和多功能性。 ISO7841数…

刷题刷题刷题

89. 格雷编码 - 力扣&#xff08;LeetCode&#xff09; class Solution { public:vector<int> grayCode(int n) {vector<int> res;res.push_back(0);int head 1;for (int i 0; i < n; i) {for (int j res.size() - 1; j > 0; j--) {res.push_back(head r…

电脑录屏怎么录?强烈推荐这5款高清录屏软件

现在电脑录屏作为数字化生活的一项实用技能&#xff0c;正逐渐走进越来越多人的视野&#xff0c;无论是想要录制游戏直播的高光时刻&#xff0c;还是制作教学视频分享知识&#xff0c;亦或是记录会议内容以备不时之需&#xff0c;电脑录屏都能轻松满足我们的需求。 今天就给大家…

Leetcode 876.141.142.143 环形链表 C++实现

Leetcode 876. 链表的中间结点 问题&#xff1a;给你单链表的头结点 head &#xff0c;请你找出并返回链表的中间结点。如果有两个中间结点&#xff0c;则返回第二个中间结点。 、 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct L…

【MySQL进阶之路】oracle 9i的经典测试雇员信息表案例——多表查询

目录 引言 笛卡尔积 自连接 子查询 单行子查询 多行子查询 多列子查询 在from子句中使用子查询 合并查询 个人主页&#xff1a;东洛的克莱斯韦克-CSDN博客 引言 在数据库的实际开发中&#xff0c;多表查询是一项非常基础且重要的技能。它允许你将来自不同表的数据结合…

【git bash编码错误解决方案】启动conda环境时报错,其他terminal却正常

&#x1f50e;嘿&#xff0c;这里是慰慰&#x1f469;&#x1f3fb;‍&#x1f393;&#xff0c;会发各种类型的文章&#xff0c;智能专业&#xff0c;从事前端&#x1f43e; &#x1f389;如果有帮助的话&#xff0c;就点个赞叭&#xff0c;让我开心一下&#xff01;&#x1f…

Java中的IO流-最全最基础的IO流概述和简介

IO流简介 IO是什么 Java中的IO流是用于处理数据输入和输出的核心机制。通过应用IO流可以使Java程序能够与外部世界&#xff08;如磁盘文件、网络、硬件设备等&#xff09;进行数据交互。IO流的全称为输入/输出流&#xff08;Input/Output Stream&#xff09;&#xff0c;它是…

【Python】函数的定义和调用、形参和实参、函数的返回值、多元赋值、全局和局部变量

文章目录 函数的定义函数的调用形参和实参函数的返回值一个 return多个 return多元赋值 变量作用域函数内的变量全局变量和局部变量修改全局变量 函数的定义 函数的定义&#xff1a;分配任务 def 函数名(形参列表):函数体return 返回值def&#xff1a;define&#xff0c;定义…

2024“钉耙编程”中国大学生算法设计超级联赛(8)

&#x1f680;欢迎来到本文&#x1f680; &#x1f349;个人简介&#xff1a;陈童学哦&#xff0c;彩笔ACMer一枚。 &#x1f3c0;所属专栏&#xff1a;杭电多校集训 本文用于记录回顾总结解题思路便于加深理解。 不是哥们&#xff0c;怎么我tm什么都不会。 &#x1f4e2;&…

计算机Java项目|基于SpringBoot的医院药品管理系统

作者主页&#xff1a;编程指南针 作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、多年校企合作经验&#xff0c;被多个学校常年聘为校外企业导师&#xff0c;指导学生毕业设计并参…

大象机械臂myCobot 280 JN 2023和D435i相关环境配置

目录 一、安装Google拼音输入法二、安装CUDA 10.2三、安装conda管理环境四、配置D435i相机SDK五、安装realsense-ros 大象机器人的这款机械臂&#xff0c;用的Jetson nano做的主控&#xff0c;给的系统的ubuntu20&#xff0c;默认python版本是3.8。并且没有配置CUDA&#xff0c…

记录|SPC理解+SPC的监控看板

目录 前言一、Dashboard1.1 分布图1.2 控制图I-MR控制图&#xff1a;单值极差控制图Xbar-R图&#xff1a;均值极差控制图 1.3 趋势图 二、Xbar-R控制图判断异常的条件Xbar控制图R控制图 三、均值极差控制图【Xbar-R】3.1 基础理解XbarR最终绘制的Xbar-R图 3.2 如何看图看图顺序…