在订单确认页面处理完毕后,此时用户单击“提交订单”按钮,商城系统就对应生成一笔订单数据并保存在数据库中,此即订单生成功能。
在单击“提交订单”按钮后,后端会进行一系列操作,包括数据查询、数据判断、数据整合等,订单生成流程图如下所示:
一、发起订单生成请求
在订单确认页面order-settle.html中,编写“提交订单”按钮单击事件,代码如下所示:
$('#saveOrder').click(function () {var userAddress = $(".user_address_label").html();if (userAddress == '' || userAddress == '无') {Swal.fire({text: "请填写收货信息",icon: "error",iconColor:"#f05b72",});return;}if (userAddress.trim().length < 10) {Swal.fire({text: "请输入正确的收货信息",icon: "error",iconColor:"#f05b72",});return;}window.location.href = '../saveOrder';});
前端主要验证用户输入的信息是否正确,如果验证通过,则向saveOrder请求地址发起订单生成请求。
二、订单生成请求处理
首先在controller包中新建OrderController类用于处理订单模块的相关请求,然后新增saveOrder()方法用于订单生成的请求,代码如下所示:
@GetMapping("/saveOrder")
public String saveOrder(HttpSession httpSession) {NewBeeMallUserVO user = (NewBeeMallUserVO) httpSession.getAttribute(Constants.MALL_USER_SESSION_KEY);List<NewBeeMallShoppingCartItemVO> myShoppingCartItems = newBeeMallShoppingCartService.getMyShoppingCartItems(user.getUserId());if (!StringUtils.hasText(user.getAddress().trim())) {//无收货地址NewBeeMallException.fail(ServiceResultEnum.NULL_ADDRESS_ERROR.getResult());}if (CollectionUtils.isEmpty(myShoppingCartItems)) {//购物车中无数据则跳转至错误页NewBeeMallException.fail(ServiceResultEnum.SHOPPING_ITEM_ERROR.getResult());}//保存订单并返回订单号String saveOrderResult = newBeeMallOrderService.saveOrder(user, myShoppingCartItems);//跳转到订单详情页return "redirect:/orders/" + saveOrderResult;}
此方法处理的映射地址为/saveOrder,请求方法为GET,过程如下所示:
(1)验证收货地址信息
(2)验证购物车中是否有数据
(3)将购物项数据和用户信息作为参数传递给saveOrder()方法
(4)如果订单生成成功,则返回订单号,跳转至订单详情页
三、订单生成逻辑的实现
在service包中新建订单模块的业务实现类,并实现订单生成的业务逻辑,代码如下所示:
@Override
@Transactional
public String saveOrder(NewBeeMallUserVO user, List<NewBeeMallShoppingCartItemVO> myShoppingCartItems) {List<Long> itemIdList = myShoppingCartItems.stream().map(NewBeeMallShoppingCartItemVO::getCartItemId).collect(Collectors.toList());List<Long> goodsIds = myShoppingCartItems.stream().map(NewBeeMallShoppingCartItemVO::getGoodsId).collect(Collectors.toList());List<NewBeeMallGoods> newBeeMallGoods = newBeeMallGoodsMapper.selectByPrimaryKeys(goodsIds);//检查是否包含已下架商品List<NewBeeMallGoods> goodsListNotSelling = newBeeMallGoods.stream().filter(newBeeMallGoodsTemp -> newBeeMallGoodsTemp.getGoodsSellStatus() != Constants.SELL_STATUS_UP).collect(Collectors.toList());if (!CollectionUtils.isEmpty(goodsListNotSelling)) {//goodsListNotSelling 对象非空则表示有下架商品NewBeeMallException.fail(goodsListNotSelling.get(0).getGoodsName() + "已下架,无法生成订单");}Map<Long, NewBeeMallGoods> newBeeMallGoodsMap = newBeeMallGoods.stream().collect(Collectors.toMap(NewBeeMallGoods::getGoodsId, Function.identity(), (entity1, entity2) -> entity1));//判断商品库存for (NewBeeMallShoppingCartItemVO shoppingCartItemVO : myShoppingCartItems) {//查出的商品中不存在购物车中的这条关联商品数据,直接返回错误提醒if (!newBeeMallGoodsMap.containsKey(shoppingCartItemVO.getGoodsId())) {NewBeeMallException.fail(ServiceResultEnum.SHOPPING_ITEM_ERROR.getResult());}//存在数量大于库存的情况,直接返回错误提醒if (shoppingCartItemVO.getGoodsCount() > newBeeMallGoodsMap.get(shoppingCartItemVO.getGoodsId()).getStockNum()) {NewBeeMallException.fail(ServiceResultEnum.SHOPPING_ITEM_COUNT_ERROR.getResult());}}//删除购物项if (!CollectionUtils.isEmpty(itemIdList) && !CollectionUtils.isEmpty(goodsIds) && !CollectionUtils.isEmpty(newBeeMallGoods)) {if (newBeeMallShoppingCartItemMapper.deleteBatch(itemIdList) > 0) {List<StockNumDTO> stockNumDTOS = BeanUtil.copyList(myShoppingCartItems, StockNumDTO.class);int updateStockNumResult = newBeeMallGoodsMapper.updateStockNum(stockNumDTOS);if (updateStockNumResult < 1) {NewBeeMallException.fail(ServiceResultEnum.SHOPPING_ITEM_COUNT_ERROR.getResult());}//生成订单号String orderNo = NumberUtil.genOrderNo();int priceTotal = 0;//保存订单NewBeeMallOrder newBeeMallOrder = new NewBeeMallOrder();newBeeMallOrder.setOrderNo(orderNo);newBeeMallOrder.setUserId(user.getUserId());newBeeMallOrder.setUserAddress(user.getAddress());//总价for (NewBeeMallShoppingCartItemVO newBeeMallShoppingCartItemVO : myShoppingCartItems) {priceTotal += newBeeMallShoppingCartItemVO.getGoodsCount() * newBeeMallShoppingCartItemVO.getSellingPrice();}if (priceTotal < 1) {NewBeeMallException.fail(ServiceResultEnum.ORDER_PRICE_ERROR.getResult());}newBeeMallOrder.setTotalPrice(priceTotal);//订单body字段,用来作为生成支付单描述信息,暂时未接入第三方支付接口,故该字段暂时设为空字符串String extraInfo = "";newBeeMallOrder.setExtraInfo(extraInfo);//生成订单项并保存订单项纪录if (newBeeMallOrderMapper.insertSelective(newBeeMallOrder) > 0) {//生成所有的订单项快照,并保存至数据库List<NewBeeMallOrderItem> newBeeMallOrderItems = new ArrayList<>();for (NewBeeMallShoppingCartItemVO newBeeMallShoppingCartItemVO : myShoppingCartItems) {NewBeeMallOrderItem newBeeMallOrderItem = new NewBeeMallOrderItem();//使用BeanUtil工具类将newBeeMallShoppingCartItemVO中的属性复制到newBeeMallOrderItem对象中BeanUtil.copyProperties(newBeeMallShoppingCartItemVO, newBeeMallOrderItem);//NewBeeMallOrderMapper文件insert()方法中使用了useGeneratedKeys因此orderId可以获取到newBeeMallOrderItem.setOrderId(newBeeMallOrder.getOrderId());newBeeMallOrderItems.add(newBeeMallOrderItem);}//保存至数据库if (newBeeMallOrderItemMapper.insertBatch(newBeeMallOrderItems) > 0) {//所有操作成功后,将订单号返回,以供Controller方法跳转到订单详情return orderNo;}NewBeeMallException.fail(ServiceResultEnum.ORDER_PRICE_ERROR.getResult());}NewBeeMallException.fail(ServiceResultEnum.DB_ERROR.getResult());}NewBeeMallException.fail(ServiceResultEnum.DB_ERROR.getResult());}NewBeeMallException.fail(ServiceResultEnum.SHOPPING_ITEM_ERROR.getResult());return ServiceResultEnum.SHOPPING_ITEM_ERROR.getResult();}
订单生成方法先验证,再进行订单数据封装,最后将订单数据和订单项数据保存到数据库中,其 详细过程如下所示:
(1)检查结算商品中是否包含已下架商品
(2)判断商品数据和商品库存
(3)对象的非空判断
(4)生成订单后,删除相应的购物项数据
(5)更新商品库存记录
(6)判断订单价格
(7)生成订单号并封装成对象,保存订单记录至数据库
(8)封装订单项并保存至数据库
(9)返回新订单的订单号
在此方法中添加@Transactional注解,若执行过程中出现异常,则回滚事务。