• 【SpringBoot+MP】实现简单购物车并集成用户下单功能


    前言

    各位新人请注意,在真实的生产环境中,购物车模块往往比网上教的复杂得多,以下只是简单地实现一些基本功能,业务量决定技术实现!
    在这里插入图片描述

    一.购物车

    购物车在日常生活中十分常见,加入购物车、移出购物车、查看购物车…通过OOP的角度来看这就是一些CRUD,但值得注意的是,这不是简单的CRUD首先,每一个用户的购物车是不同的,其次在现实生活中添加进去的商品不仅仅涉及到的是一张表(一类实体),比如我已经添加了选中的菜品(dish表),我还想添加套餐(套餐表)…这就不是一个简单的save方法能解决的
    在这里插入图片描述
    但是,只要静下心来理清表的结构,实体的联系,知道购物车对应表的字段是干什么的,是来操作什么关联表的,就会简单很多,先来看一下表的结构:
    在这里插入图片描述
    框起来的三个id格外的亮眼,在实现方法里就是通过id查到表对应的实体信息,然后对实体的属性进行操作,最后保存到各自对应的表中。
    所谓的多表在代码实现过程中,其实就是几个表对应的Service之间调用方法来保存针对场景设置的属性值,记住这句话来看下面的代码就会变得非常简单!

    @PostMapping("/add")
    public R<ShoppingCart> add(@RequestBody ShoppingCart shoppingCart) {
    
        log.info("购物车信息:{}", shoppingCart.toString());
    
        //设置用户id,指定是当前是哪个用户的购物车
        Long currentId = BaseContext.getCurrentId();
        shoppingCart.setUserId(currentId);
    
        LambdaQueryWrapper<ShoppingCart> shoppingCartLqw = new LambdaQueryWrapper<>();
        shoppingCartLqw.eq(ShoppingCart::getUserId, currentId);//查找用户
        //查询当前菜品或者套餐是否在购物车中
        Long dishId = shoppingCart.getDishId();
        if (dishId != null) {
            //添加到购物车的是菜品
            shoppingCartLqw.eq(ShoppingCart::getDishId, dishId);
        } else {
            //添加到购物车的是套餐
            shoppingCartLqw.eq(ShoppingCart::getSetmealId, shoppingCart.getSetmealId());
        }
    
        ShoppingCart shopOne = shoppingCartService.getOne(shoppingCartLqw);
    
        if (shopOne != null) {
            //如果已在购物车中则菜品数量+1
            Integer num = shopOne.getNumber();
            shopOne.setNumber(num + 1);
            shopOne.setCreateTime(LocalDateTime.now());
            shoppingCartService.updateById(shopOne);
        } else {
            //如果不在购物车中则加入购物车,且数量默认为1
            shoppingCart.setNumber(1);
            shoppingCartService.save(shoppingCart);
            shopOne = shoppingCart;
        }
        return R.success(shopOne);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    看完这段代码,其实不难发现就是围绕着“拿实体,改实体”来做,只不过在实现的过程中需要注意一些小细节罢了。

    下单关联表

    经常网购都清楚,在下单前最重要的要素就是收货地址、用户基本信息(电话,身份证,姓名等等…)
    在进行下单操作生成订单时都需要同时操作这几张表,把表里的信息读到订单表中。
    在这里插入图片描述
    在购物车的基础之上,用户下单就是对购物车对应表中的数据进行进一步操作,只不过下单的过程不仅仅涉及到购物车对应的表,还包括(用户地址,个人信息等等…),又是一次涉及到多表的操作。

    二.用户下单

    这次以订单表来保存用户基本信息Order,以订单明细表保存所选菜品信息OrderDetails,简单的购物车实现逻辑如图所示:
    在这里插入图片描述
    当点击下单,前端会发送过来一个请求(包含一些其他关联表的id):

    在这里插入图片描述
    对于后端,需要通过Order类型的实体接收,并通过其中已经封装的各种表id来操作其他表,就像这样:

    @Transactional
    public void submit(Orders orders) {
        //获得当前用户id
        Long currentId = BaseContext.getCurrentId();
        LambdaQueryWrapper<ShoppingCart> shopLqw = new LambdaQueryWrapper<>();
        shopLqw.eq(ShoppingCart::getUserId, currentId);
    
        //查询当前用户购物车数据
        List<ShoppingCart> shopOne = shoppingCartService.list(shopLqw);
        if (shopOne == null || shopOne.size() == 0) {
    
            throw new CustomException("购物车为空,不能下单~");
        }
    
        //查询用户信息
        User userNow = userService.getById(currentId);
    
        //查询地址信息
        Long addressBookId = orders.getAddressBookId();
    
        AddressBook addressBook = addressBookService.getById(addressBookId);
        if (addressBook == null) {
            throw new CustomException("不好意思,您还没有填写地址哟");
        }
    
        long orderId = IdWorker.getId();//订单号
    
        AtomicInteger amount = new AtomicInteger(); //确保在多线程的情况下保证线程安全
    
        //向订单明细表中添加购物车中的内容(主要是餐品信息)
        List<OrderDetail> orderDetails = shopOne.stream().map((item) -> {
            OrderDetail orderDetail = new OrderDetail();
            orderDetail.setOrderId(orderId);
            orderDetail.setNumber(item.getNumber());
            orderDetail.setDishFlavor(item.getDishFlavor());
            orderDetail.setDishId(item.getDishId());
            orderDetail.setSetmealId(item.getSetmealId());
            orderDetail.setName(item.getName());
            orderDetail.setImage(item.getImage());
            orderDetail.setAmount(item.getAmount());
            amount.addAndGet(item.getAmount().multiply(new BigDecimal(item.getNumber())).intValue());
            return orderDetail;
        }).collect(Collectors.toList());
    
    
        //向订单表中添加基本信息(用户基本信息)
        orders.setId(orderId);
        orders.setOrderTime(LocalDateTime.now());
        orders.setCheckoutTime(LocalDateTime.now());
        orders.setStatus(2);
        orders.setAmount(new BigDecimal(amount.get()));
        orders.setUserId(currentId);
        orders.setNumber(String.valueOf(orderId));
        orders.setUserName(userNow.getName());
        orders.setConsignee(addressBook.getConsignee());
        orders.setPhone(addressBook.getPhone());
        orders.setAddress((addressBook.getProvinceName() == null ? "" : addressBook.getProvinceName())
                + (addressBook.getCityName() == null ? "" : addressBook.getCityName())
                + (addressBook.getDistrictName() == null ? "" : addressBook.getDistrictName()) + (addressBook.getDetail() == null ? "" : addressBook.getDetail()));
    
        //向订单插入一条数据,主要是客户基本信息
        this.save(orders);
        //向订单明细表插入多条数据,主要是客户所选餐品
        orderDetailService.saveBatch(orderDetails);
        //清空购物车数据
        shoppingCartService.remove(shopLqw);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    在实现过程中有一些细节还是值得注意一下:
    1.涉及多表要开启事务,确保一致性
    2.new AtomicInteger()来定义餐品数量,确保线程安全

    3.全局异常要处理好
    4.当完成了生成订单之后要记得清空购物车

    购物车与订单的关系
    在这之前,我总是不能深刻理解购物车与订单之间的关系,实现下单功能后才逐渐明了,原来订单是购物车的载体,购物车的出现就是为了生成订单而服务的,购物车包含于订单!

  • 相关阅读:
    【Qt之QSplashScreen】开场动画使用:进度条加载及设置鼠标指针不转圈
    Kvaser Leaf light HS v2 | 如何使用Excel发送和接收CAN报文数据
    磁力链接的示例与解释
    超详讲解yum包管理器/Vim编辑器/gdb调试器【Linux】
    webpack自定义plugin
    JWT(2):JWT入门使用
    css:html元素的定位
    02【数据库的基本操作】
    HTTP 介绍
    Winodws10测试驱动禁用签名
  • 原文地址:https://blog.csdn.net/weixin_57535055/article/details/127661922