商城业务:购物车

news2024/11/28 20:50:37

人生在世如身处荆棘之中,心不动,人不妄动,不动则不伤;如心动则人妄动,伤其身痛其骨,于是体会到世间诸般痛苦。

1、购物车需求

1)、需求描述:

- 用户可以在登录状态下将商品添加到购物车【用户购物车/在线购物车】

- 放入数据库

- mongodb

- 放入 redis(采用)

登录以后,会将临时购物车的数据全部合并过来,并清空临时购物车;

- 用户可以在未登录状态下将商品添加到购物车【游客购物车/离线购物车/临时购物车】

- 放入 localstorage(客户端存储,后台不存)

- cookie - WebSQL

- 放入 redis(采用)

浏览器即使关闭,下次进入,临时购物车数据都在

- 用户可以使用购物车一起结算下单

- 给购物车添加商品

- 用户可以查询自己的购物车

- 用户可以在购物车中修改购买商品的数量。

- 用户可以在购物车中删除商品。

- 选中不选中商品

- 在购物车中展示商品优惠信息

- 提示购物车商品价格变化

2)、数据结构 

因此每一个购物项信息,都是一个对象,基本字段包括: 

另外,购物车中不止一条数据,因此最终会是对象的数组。即: 

Redis 有 5 种不同数据结构,这里选择哪一种比较合适呢?

- 首先不同用户应该有独立的购物车,因此购物车应该以用户的作为 key 来存储,Value 是 用户的所有购物车信息。这样看来基本的`k-v`结构就可以了。

- 但是,我们对购物车中的商品进行增、删、改操作,基本都需要根据商品 id 进行判断, 为了方便后期处理,我们的购物车也应该是`k-v`结构,key 是商品 id,value 才是这个商品的 购物车信息。

综上所述,我们的购物车结构是一个双层 Map:Ma<string,map<string,string>>

- 第一层 Map,Key 是用户 id

- 第二层 Map,Key 是购物车中商品 id,值是购物项数据

3)、流程 

参照京东

user-key 是随机生成的 id,不管有没有登录都会有这个 cookie 信息。 

两个功能:新增商品到购物车、查询购物车。

新增商品:判断是否登录

- 是:则添加商品到后台 Redis 中,把 user 的唯一标识符作为 key。

- 否:则添加商品到后台 redis 中,使用随机生成的 user-key 作为 key。

查询购物车列表:判断是否登录 

- 否:直接根据 user-key 查询 redis 中数据并展示

- 是:已登录,则需要先根据 user-key 查询 redis 是否有数据。

- 有:需要提交到后台添加到 redis,合并数据,而后查询。

- 否:直接去后台查询 redis,而后返回。

2、临时购物车 

    /**
     * 获取到我们要操作的购物车
     * @return
     */
    private BoundHashOperations<String, Object, Object> getCartOps() {
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        //1.
        String cartKey = "";
        if (userInfoTo.getUserId() != null) {
            cartKey = CART_PREFIX + userInfoTo.getUserId();
        } else {
            cartKey = CART_PREFIX + userInfoTo.getUserKey();
        }
        BoundHashOperations<String, Object, Object> operations = redisTemplate.boundHashOps(cartKey);
        return operations;
    }

3、登录购物车 

 @Override
    public CartItem addToCart(Long skuId, Integer num) {

        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        String res = (String) cartOps.get(skuId.toString());
        if(StringUtils.isEmpty(res)){
            CartItem cartItem = new CartItem();
            // 1.运程查询当前要添加的商品信息
            CompletableFuture<Void> getSkuInfoTask = CompletableFuture.runAsync(() -> {
                //2.商品添加到购物车(新商品)
                R skuInfo = productFeignService.getSkuInfo(skuId);
                SkuInfoVo data = skuInfo.getData("skuInfo", new TypeReference<SkuInfoVo>() {
                });

                cartItem.setCheck(true);
                cartItem.setCount(1);
                cartItem.setImage(data.getSkuDefaultImg());
                cartItem.setTitle(data.getSkuTitle());
                cartItem.setPrice(data.getPrice());
                cartItem.setSkuId(data.getSkuId());
            },executor);

            CompletableFuture<Void> getSkuSaleAttr = CompletableFuture.runAsync(() -> {
                //运程查询sku的组合信息
                List<String> values = productFeignService.getSkuSaleAttrValues(skuId);
                cartItem.setSkuAttr(values);
            }, executor);

            CompletableFuture<Void> allOf = CompletableFuture.allOf(getSkuInfoTask, getSkuSaleAttr);
            try {
                allOf.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
            String s = JSON.toJSONString(cartItem);

            cartOps.put(skuId.toString(),s);
            return cartItem;
        }
        else
        {
            //购物车有这个商品
            CartItem cartItem = JSON.parseObject(res, CartItem.class);
            cartItem.setCount(cartItem.getCount()+num);
            cartOps.put(skuId.toString(),JSON.toJSONString(cartItem));

            return cartItem;

        }


    }

    @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;
    }

 

   @Override
    public Cart getCart() {
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        Cart cart = new Cart();
        if(userInfoTo.getUserId()!=null){
            //登录
            String cartKey = CART_PREFIX+userInfoTo.getUserId();
            //如果临时购物车的数据还没有合并【合并购物车】
           String tempCartKey= CART_PREFIX + userInfoTo.getUserKey();
            List<CartItem> tempCartItems = getCartItems(tempCartKey);
            if(tempCartItems!=null){
                //合并
                for (CartItem item : tempCartItems) {
                    addToCart(item.getSkuId(),item.getCount());
                }
            }
            //3.获取登录后的数据
            List<CartItem> cartItems = getCartItems(cartKey);
            cart.setItems(cartItems);
            //清除临时购物车数据
            clearCart(tempCartKey);

        }else {
            //没登陆
            String cartKey = CART_PREFIX+userInfoTo.getUserKey();
           //获取临时购物车的所有购物项
            List<CartItem> cartItems = getCartItems(cartKey);
            cart.setItems(cartItems);


        }
        return cart;
    }

    @Override
    public void checkItem(Long skuId, Integer check) {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();

        CartItem cartItem = getCartItem(skuId);
        cartItem.setCheck(check==1?true:false);
        String s = JSON.toJSONString(cartItem);
        cartOps.put(skuId.toString(),s);

    }

    @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);

    }

    @Override
    public void deleteItem(Long skuId) {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        cartOps.delete(skuId.toString());
    }

人生在世如身处荆棘之中,心不动,人不妄动,不动则不伤;如心动则人妄动,伤其身痛其骨,于是体会到世间诸般痛苦。 

 

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

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

相关文章

【项目】---快速搜索工具

目录 一、项目背景 二、项目需求分析 三、项目涉及的知识点 四、项目实现的基础理论 五、项目框架 六、增加系统工具模块 6.1、扫描本地的文件的功能 七、增加数据管理模块 7.1、先了解数据库sqlite 7.2 封装sqlite数据库管理类 7.3、封装数据管理类 7.3.1增加搜索…

成都女子情人节给东莞男子送巧克力,却被后者典当后换成望京卡牌

一年一度的情人节已经来临&#xff0c;每年的这个时候&#xff0c;都是少男少女们欢庆的节日&#xff0c;因为他们可以借助送礼物&#xff0c;各自表达对另一半的爱慕之情。然而由于中国人的传统观念&#xff0c;一般都是男方给女方送礼物&#xff0c;女方给男方送礼物的就凤毛…

宝塔搭建实战php开源likeadmin通用管理移动端uniapp源码(四)

大家好啊&#xff0c;我是测评君&#xff0c;欢迎来到web测评。 上一期给大家分享了pc端的部署方式&#xff0c;今天来给大家分享uniapp端在本地搭建&#xff0c;与打包发布到宝塔的方法。感兴趣的朋友可以自行下载学习。 技术架构 vscode node16 vue3 uniapp vite types…

PageHelper分页查询

分页查询分页查询的优点所谓分页,就是查询结果数据较多时,采用按页显示的方法,而不是一次性全部显示分页的优点:服务器:一次性查询所有信息,服务器压力大,分页查询服务器压力小客户端:一次性显示所有信息,需要更多流量,加载时间也会更长,分页显示没有这个问题用户体验上:一般最…

Hot 100 | 287. 寻找重复数

LeetCode 287. 寻找重复数 给定一个包含 n 1 个整数的数组 nums &#xff0c;其数字都在 [1, n] 范围内&#xff08;包括 1 和 n&#xff09;&#xff0c;可知至少存在一个重复的整数。假设 nums 只有 一个重复的整数 &#xff0c;返回 这个重复的数 。 你设计的解决方案必须&…

【Spring Cloud Alibaba】(三)OpenFeign扩展点实战 + 源码详解

系列目录 【Spring Cloud Alibaba】&#xff08;一&#xff09;微服务介绍 及 Nacos注册中心实战 【Spring Cloud Alibaba】&#xff08;二&#xff09;微服务调用组件Feign原理实战 本文目录系列目录前言一、Feign扩展点配置二、OpenFeign扩展点配置1. 通过配置文件配置有效范…

二维码数据压缩实践 | 使用python对二维码数据进行压缩 |不乱码,支持中文

当前二维码的应用越来越广泛&#xff0c;包括疫情时期的健康码也是应用二维码的典型案例&#xff0c;最近需要通过一张二维码显示较多文本数据&#xff0c;也就是对二维码数据进行压缩&#xff0c;使用CSDN搜索了半天居然没有能简单使用的代码&#xff0c;很多事例代码解决不了…

机器连接和边缘计算

以一种高效、可扩展的方式进行连接和边缘计算的结合&#xff0c;解决了在工业物联网应用中的机器数据集成问题。 一 边缘计算 边缘计算描述了由中央平台管理的数据分散式处理。边缘计算对于工业物联网而言非常重要。在许多应用程序中&#xff0c;由于数据量非常大&#xff0c;…

C++STL剖析(十)—— 位图(bitset)

文章目录1. 位图的介绍2. 位图的概念3. 位图的实现&#x1f351; 构造函数&#x1f351; 设置指定位&#x1f351; 清除指定位&#x1f351; 获取指定位的状态&#x1f351; 打印函数4. 总结1. 位图的介绍 在介绍位图之前先来看一道面试题吧 给 40 亿个不重复的无符号整数&…

【网络原理2】---TCP协议的格式

传输层重点协议TCP 协议TCP 协议段格式TCP内部的工作机制1. 确认应答2.超时重传TCP 协议 TCP 协议相对于 UDP 是复杂不少的。 在网络编程这里已经讲了 TCP 的特点&#xff1a; 有链接 可靠传输 面向字节流 全双工 可靠传输 是 TCP内部的机制&#xff0c;和编码关系不大&#x…

[oeasy]python0083_十进制数如何存入计算机_八卦纪事_BCD编码_Binary_Coded_Decimal

编码进化 回忆上次内容 上次 研究了 视频终端的 演化 从VT05 到 VT100从 黑底绿字 到 RGB 24位真彩色形成了 VT100选项 从而 将颜色 数字化 了 生活中我们更常用 10个数字 但是 计算机中 用二进制 日常计数的十进制数 是如何存储进计算机的呢?&#x1f914; 从10进制到2进…

Java学习笔记-03(API阶段-2)集合

集合 我们接下来要学习的内容是Java基础中一个很重要的部分&#xff1a;集合 1. Collection接口 1.1 前言 Java语言的java.util包中提供了一些集合类,这些集合类又称之为容器 提到容器不难想到数组,集合类与数组最主要的不同之处是,数组的长度是固定的,集合的长度是可变的&a…

思科网络部署,(0基础)入门实验,超详细

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a;小刘主页 ♥️每天分享云计算网络运维课堂笔记&#xff0c;努力不一定有收获&#xff0c;但一定会有收获加油&#xff01;一起努力&#xff0c;共赴美好人生&#xff01; ♥️夕阳下&#xff0c;是最美的绽放&#xff0…

如何让一起打拼的员工有持续的动力

我们的工作都要靠团队的每一个人努力&#xff0c;如何持续让老员工也能有持续的动力完成任务是我们非常重要的管理目标。 方法一&#xff1a;提供稀缺的学习机会。很多企业的培训都是针对新员工或者管理层的&#xff0c;容易让老员工意识不到自己应该学习&#xff0c;接触不到新…

Echarts 雷达图设置拐点大小和形状,tooltip后文字不居中对齐

第017个点击查看专栏目录Echarts的雷达图的拐点大小和形状是可以设置的&#xff0c;在series中设置symbol 相应的属性即可。 使用tooltip的时候&#xff0c;默认状态文字是居中对齐的&#xff0c;不好看。需要在tooltip属性中设置一下&#xff0c;如图所示&#xff0c;效果比较…

记录robosense RS-LIDAR-16使用过程4

一、时隔一个月&#xff0c;再次记录激光雷达的使用&#xff0c;一个月不碰生疏了好多&#xff0c;如鲠在喉&#xff0c;先来个基本操作熟悉一下找找感觉。连接在线雷达&#xff1a;https://github.com/RoboSense-LiDAR/rslidar_sdk/blob/main/doc/howto/06_how_to_decode_onli…

selenium--验证码识别,一文教会你回答面试官

相信大家在日常划水&#xff0c;培训&#xff0c;工作中都遇到这样的问题&#xff0c;验证码怎么处理&#xff1f;也有一些面试官会这么问。这里大致的说说&#xff0c;最常见的处理方式。1、万能验证码&#xff1a;所谓的万能验证码也就是找开发固定一个验证码&#xff0c;比如…

jenkins下配置maven

1. 先在jenkins服务器上安装maven 下载-解压-重命名-启动 [rootVM-0-12-centos local]# wget https://mirrors.aliyun.com/apache/maven/maven-3/3.9.0/binaries/apache-maven-3.9.0-bin.tar.gz [rootVM-0-12-centos local]# tar xf apache-maven-3.9.0-bin.tar.gz [rootVM-0…

嵌入式ARM设计编程(一) 简单数据搬移

文章和代码已归档至【Github仓库&#xff1a;hardware-tutorial】&#xff0c;需要的朋友们自取。或者公众号【AIShareLab】回复 嵌入式 也可获取。 一、实验目的 熟悉实验开发环境&#xff0c;掌握简单ARM汇编指令的使用方法。 二、实验环境 硬件&#xff1a;PC机 软件&am…

【招聘】永善县社会科学界联合会招办公室文秘人员2名

【招聘】永善县社会科学界联合会招办公室文秘人员2名 因工作需要&#xff0c;根据《永善县人力资源和社会保障局关于做好2021年公益性岗位开发管理的通知》(永人社发〔2020〕34号)文件要求&#xff0c;现面向社会公开招聘公益性岗位工作人员&#xff0c;现通告如下&#xff1a…