【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);
}

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

下单关联表

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

二.用户下单

这次以订单表来保存用户基本信息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.new AtomicInteger()来定义餐品数量,确保线程安全

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

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

猜你喜欢

转载自blog.csdn.net/weixin_57535055/article/details/127661922