在订单确认页面处理完毕后,此时用户单击“提交订单”按钮,商城系统就对应生成一笔订单数据并保存在数据库中,此即订单生成功能。
在单击“提交订单”按钮后,后端会进行一系列操作,包括数据查询、数据判断、数据整合等,订单生成流程图如下所示:
一、发起订单生成请求
在订单确认页面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注解,若执行过程中出现异常,则回滚事务。