赞
踩
各位新人请注意,在真实的生产环境中,购物车模块往往比网上教的复杂得多,以下只是简单地实现一些基本功能,业务量决定技术实现!
购物车在日常生活中十分常见,加入购物车、移出购物车、查看购物车…通过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.当完成了生成订单之后要记得清空购物车
购物车与订单的关系
在这之前,我总是不能深刻理解购物车与订单之间的关系,实现下单功能后才逐渐明了,原来订单是购物车的载体,购物车的出现就是为了生成订单而服务的,购物车包含于订单!
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。