文章目录
-
- 前言
- 一.购物车
- 二.用户下单
前言
各位新人请注意,在真实的生产环境中,购物车模块往往比网上教的复杂得多,以下只是简单地实现一些基本功能,业务量决定技术实现!
一.购物车
购物车在日常生活中十分常见,加入购物车、移出购物车、查看购物车…通过OOP的角度来看这就是一些CRUD,但值得注意的是,这不是简单的CRUD。首先,每一个用户的购物车是不同的,其次在现实生活中添加进去的商品不仅仅涉及到的是一张表(一类实体),比如我已经添加了选中的菜品(dish表),我还想添加套餐(套餐表)…这就不是一个简单的save方法能解决的
但是,只要静下心来理清表的结构,实体的联系,知道购物车对应表的字段是干什么的,是来操作什么关联表的,就会简单很多,先来看一下表的结构:
框起来的三个id格外的亮眼,在实现方法里就是通过id查到表对应的实体信息,然后对实体的属性进行操作,最后保存到各自对应的表中。
所谓的多表在代码实现过程中,其实就是几个表对应的Service之间调用方法来保存针对场景设置的属性值,记住这句话来看下面的代码就会变得非常简单!
@PostMapping("/add")
public RShoppingCart> add(@RequestBody ShoppingCart shoppingCart) {
log.info("购物车信息:{}", shoppingCart.toString());
//设置用户id,指定是当前是哪个用户的购物车
Long currentId = BaseContext.getCurrentId();
shoppingCart.setUserId(currentId);
LambdaQueryWrapperShoppingCart> 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();
LambdaQueryWrapperShoppingCart> shopLqw = new LambdaQueryWrapper>();
shopLqw.eq(ShoppingCart::getUserId, currentId);
//查询当前用户购物车数据
ListShoppingCart> 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(); //确保在多线程的情况下保证线程安全
//向订单明细表中添加购物车中的内容(主要是餐品信息)
ListOrderDetail> 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.当完成了生成订单之后要记得清空购物车
购物车与订单的关系
在这之前,我总是不能深刻理解购物车与订单之间的关系,实现下单功能后才逐渐明了,原来订单是购物车的载体,购物车的出现就是为了生成订单而服务的,购物车包含于订单!