文章目录
- 前言
- 一.购物车
- 二.用户下单
前言
各位新人请注意,在真实的生产环境中,购物车模块往往比网上教的复杂得多,以下只是简单地实现一些基本功能,业务量决定技术实现!
一.购物车
购物车在日常生活中十分常见,加入购物车、移出购物车、查看购物车…通过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) {//如果已在购物车中则菜品数量+1Integer num = shopOne.getNumber();shopOne.setNumber(num + 1);shopOne.setCreateTime(LocalDateTime.now());shoppingCartService.updateById(shopOne);} else {//如果不在购物车中则加入购物车,且数量默认为1shoppingCart.setNumber(1);shoppingCartService.save(shoppingCart);shopOne = shoppingCart;}return R.success(shopOne);}
看完这段代码,其实不难发现就是围绕着“拿实体,改实体”来做,只不过在实现的过程中需要注意一些小细节罢了。
下单关联表
经常网购都清楚,在下单前最重要的要素就是收货地址、用户基本信息(电话,身份证,姓名等等…)
在进行下单操作生成订单时都需要同时操作这几张表,把表里的信息读到订单表中。
在购物车的基础之上,用户下单就是对购物车对应表中的数据进行进一步操作,只不过下单的过程不仅仅涉及到购物车对应的表,还包括(用户地址,个人信息等等…),又是一次涉及到多表的操作。
二.用户下单
这次以订单表来保存用户基本信息Order,以订单明细表保存所选菜品信息OrderDetails,简单的购物车实现逻辑如图所示:
当点击下单,前端会发送过来一个请求(包含一些其他关联表的id):
对于后端,需要通过Order类型的实体接收,并通过其中已经封装的各种表id来操作其他表,就像这样:
@Transactionalpublic void submit(Orders orders) {//获得当前用户idLong 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.当完成了生成订单之后要记得清空购物车
购物车与订单的关系
在这之前,我总是不能深刻理解购物车与订单之间的关系,实现下单功能后才逐渐明了,原来订单是购物车的载体,购物车的出现就是为了生成订单而服务的,购物车包含于订单!