Hi,大家好,我是Steafan!项目开发到这里,基本上已经进行了90%了。项目中最关键的也是最难开发的就是今天我要向大家介绍的订单管理模块了。在实际的项目开发中,订单管理模块和支付模块往往是并行开发的,在开发过程中往往会遇到这样的情景:两个后台开发工程师,一个在开发订单管理模块,另一个在开发支付模块,恰好呢,在开发订单管理模块时会使用到支付模块中的部分功能,这时候工程师还没有写完支付模块,这就会产生一个等待的问题。无论让这两个工程师谁去等待谁都是不合理的,对于这样的情景,我们就应该学会抽象开发另一种功能的能力。
一、订单管理模块-概述
先来看看我们需要在订单管理模块实现哪些功能
由图可见,订单管理分为前台和后台。先来实现前台的功能。
在订单管理模块前台开发中,最复杂的要数订单号的生成规则和处理支付宝回调信息,在讲解该功能点时我会花费较大的篇幅去讲解,希望大家能够看明白。
二、订单管理模块-涉及到的VO
(1)、OrderItemVo
-
public class OrderItemVo { -
private Long orderNo; -
private Integer productId; -
private String productName; -
private String productImage; -
private BigDecimal currentUnitPrice; -
private Integer quantity; -
private BigDecimal totalPrice; -
private String createTime; -
public Long getOrderNo() { -
return orderNo; -
} -
public void setOrderNo(Long orderNo) { -
this.orderNo = orderNo; -
} -
public Integer getProductId() { -
return productId; -
} -
public void setProductId(Integer productId) { -
this.productId = productId; -
} -
public String getProductName() { -
return productName; -
} -
public void setProductName(String productName) { -
this.productName = productName; -
} -
public String getProductImage() { -
return productImage; -
} -
public void setProductImage(String productImage) { -
this.productImage = productImage; -
} -
public BigDecimal getCurrentUnitPrice() { -
return currentUnitPrice; -
} -
public void setCurrentUnitPrice(BigDecimal currentUnitPrice) { -
this.currentUnitPrice = currentUnitPrice; -
} -
public Integer getQuantity() { -
return quantity; -
} -
public void setQuantity(Integer quantity) { -
this.quantity = quantity; -
} -
public BigDecimal getTotalPrice() { -
return totalPrice; -
} -
public void setTotalPrice(BigDecimal totalPrice) { -
this.totalPrice = totalPrice; -
} -
public String getCreateTime() { -
return createTime; -
} -
public void setCreateTime(String createTime) { -
this.createTime = createTime; -
} -
}
这里存储了订单号和商品有关的信息。
(2)、OrderProductVo
-
public class OrderProductVo { -
private List<OrderItemVo> orderItemVoList; -
private BigDecimal productTotalPrice; -
private String imageHost; -
public List<OrderItemVo> getOrderItemVoList() { -
return orderItemVoList; -
} -
public void setOrderItemVoList(List<OrderItemVo> orderItemVoList) { -
this.orderItemVoList = orderItemVoList; -
} -
public BigDecimal getProductTotalPrice() { -
return productTotalPrice; -
} -
public void setProductTotalPrice(BigDecimal productTotalPrice) { -
this.productTotalPrice = productTotalPrice; -
} -
public String getImageHost() { -
return imageHost; -
} -
public void setImageHost(String imageHost) { -
this.imageHost = imageHost; -
} -
}
这里存储了和商品有关的订单信息。
(3)、OrderVo
-
public class OrderVo { -
private Long orderNo; -
private BigDecimal payment; -
private Integer paymentType; -
private String paymentTypeDesc; -
private Integer postage; -
private Integer status; -
private String statusDesc; -
private String paymentTime; -
private String sendTime; -
private String endTime; -
private String closeTime; -
private String createTime; -
//订单的明细 -
private List<OrderItemVo> orderItemVoList; -
private String imageHost; -
private Integer shippingId; -
private String receiverName; -
private ShippingVo shippingVo; -
public Long getOrderNo() { -
return orderNo; -
} -
public void setOrderNo(Long orderNo) { -
this.orderNo = orderNo; -
} -
public BigDecimal getPayment() { -
return payment; -
} -
public void setPayment(BigDecimal payment) { -
this.payment = payment; -
} -
public Integer getPaymentType() { -
return paymentType; -
} -
public void setPaymentType(Integer paymentType) { -
this.paymentType = paymentType; -
} -
public String getPaymentTypeDesc() { -
return paymentTypeDesc; -
} -
public void setPaymentTypeDesc(String paymentTypeDesc) { -
this.paymentTypeDesc = paymentTypeDesc; -
} -
public Integer getPostage() { -
return postage; -
} -
public void setPostage(Integer postage) { -
this.postage = postage; -
} -
public Integer getStatus() { -
return status; -
} -
public void setStatus(Integer status) { -
this.status = status; -
} -
public String getStatusDesc() { -
return statusDesc; -
} -
public void setStatusDesc(String statusDesc) { -
this.statusDesc = statusDesc; -
} -
public String getPaymentTime() { -
return paymentTime; -
} -
public void setPaymentTime(String paymentTime) { -
this.paymentTime = paymentTime; -
} -
public String getSendTime() { -
return sendTime; -
} -
public void setSendTime(String sendTime) { -
this.sendTime = sendTime; -
} -
public String getEndTime() { -
return endTime; -
} -
public void setEndTime(String endTime) { -
this.endTime = endTime; -
} -
public String getCloseTime() { -
return closeTime; -
} -
public void setCloseTime(String closeTime) { -
this.closeTime = closeTime; -
} -
public String getCreateTime() { -
return createTime; -
} -
public void setCreateTime(String createTime) { -
this.createTime = createTime; -
} -
public List<OrderItemVo> getOrderItemVoList() { -
return orderItemVoList; -
} -
public void setOrderItemVoList(List<OrderItemVo> orderItemVoList) { -
this.orderItemVoList = orderItemVoList; -
} -
public String getImageHost() { -
return imageHost; -
} -
public void setImageHost(String imageHost) { -
this.imageHost = imageHost; -
} -
public Integer getShippingId() { -
return shippingId; -
} -
public void setShippingId(Integer shippingId) { -
this.shippingId = shippingId; -
} -
public String getReceiverName() { -
return receiverName; -
} -
public void setReceiverName(String receiverName) { -
this.receiverName = receiverName; -
} -
public ShippingVo getShippingVo() { -
return shippingVo; -
} -
public void setShippingVo(ShippingVo shippingVo) { -
this.shippingVo = shippingVo; -
} -
}
这里存储了和订单状态有关的所有字段信息。
(4)、处理OrderVo
-
private OrderVo assembleOrderVo(Order order,List<OrderItem> orderItemList){ -
OrderVo orderVo = new OrderVo(); -
orderVo.setOrderNo(order.getOrderNo()); -
orderVo.setPayment(order.getPayment()); -
orderVo.setPaymentType(order.getPaymentType()); -
orderVo.setPaymentTypeDesc(Const.PaymentTypeEnum.codeOf(order.getPaymentType()).getValue()); -
orderVo.setPostage(order.getPostage()); -
orderVo.setStatus(order.getStatus()); -
orderVo.setStatusDesc(Const.OrderStatusEnum.codeOf(order.getStatus()).getValue()); -
orderVo.setShippingId(order.getShippingId()); -
Shipping shipping = shippingMapper.selectByPrimaryKey(order.getShippingId()); -
if(shipping != null){ -
orderVo.setReceiverName(shipping.getReceiverName()); -
orderVo.setShippingVo(assembleShippingVo(shipping)); -
} -
orderVo.setPaymentTime(DateTimeUtil.dateToStr(order.getPaymentTime())); -
orderVo.setSendTime(DateTimeUtil.dateToStr(order.getSendTime())); -
orderVo.setEndTime(DateTimeUtil.dateToStr(order.getEndTime())); -
orderVo.setCreateTime(DateTimeUtil.dateToStr(order.getCreateTime())); -
orderVo.setCloseTime(DateTimeUtil.dateToStr(order.getCloseTime())); -
orderVo.setImageHost(PropertiesUtil.getProperty("ftp.server.http.prefix")); -
List<OrderItemVo> orderItemVoList = Lists.newArrayList(); -
for(OrderItem orderItem : orderItemList){ -
OrderItemVo orderItemVo = assembleOrderItemVo(orderItem); -
orderItemVoList.add(orderItemVo); -
} -
orderVo.setOrderItemVoList(orderItemVoList); -
return orderVo; -
}
这里面会涉及到几个工具类,在后面会进行补充说明。
(5)、处理OrderItemVo
-
private OrderItemVo assembleOrderItemVo(OrderItem orderItem){ -
OrderItemVo orderItemVo = new OrderItemVo(); -
orderItemVo.setOrderNo(orderItem.getOrderNo()); -
orderItemVo.setProductId(orderItem.getProductId()); -
orderItemVo.setProductName(orderItem.getProductName()); -
orderItemVo.setProductImage(orderItem.getProductImage()); -
orderItemVo.setCurrentUnitPrice(orderItem.getCurrentUnitPrice()); -
orderItemVo.setQuantity(orderItem.getQuantity()); -
orderItemVo.setTotalPrice(orderItem.getTotalPrice()); -
orderItemVo.setCreateTime(DateTimeUtil.dateToStr(orderItem.getCreateTime())); -
return orderItemVo; -
}
这里的处理OrderProductVo是分开处理的,按需分配,需要使用其中的哪一个字段或方法再来处理!
值得一提的是,这些Vo并不是随便定义的,包括在之前的其他模块中的Vo,都是根据实际开发需求来定义的,不用随便定义Vo。
三、订单管理模块-前台-生成订单功能的开发
-
public ServerResponse createOrder(Integer userId,Integer shippingId){ -
//从购物车中获取数据 -
List<Cart> cartList = cartMapper.selectCheckedCartByUserId(userId); -
//计算这个订单的总价 -
ServerResponse serverResponse = this.getCartOrderItem(userId,cartList); -
if(!serverResponse.isSuccess()){ -
return serverResponse; -
} -
List<OrderItem> orderItemList = (List<OrderItem>)serverResponse.getData(); -
BigDecimal payment = this.getOrderTotalPrice(orderItemList); -
//生成订单 -
Order order = this.assembleOrder(userId,shippingId,payment); -
if(order == null){ -
return ServerResponse.createByErrorMessage("生成订单错误"); -
} -
if(CollectionUtils.isEmpty(orderItemList)){ -
return ServerResponse.createByErrorMessage("购物车为空"); -
} -
for(OrderItem orderItem : orderItemList){ -
orderItem.setOrderNo(order.getOrderNo()); -
} -
//mybatis 批量插入 -
orderItemMapper.batchInsert(orderItemList); -
//生成成功,我们要减少产品的库存 -
this.reduceProductStock(orderItemList); -
//清空一下购物车 -
this.cleanCart(cartList); -
//返回给前端数据 -
OrderVo orderVo = assembleOrderVo(order,orderItemList); -
return ServerResponse.createBySuccess(orderVo); -
}
生成订单的核心就是从购物车中遍历存在的商品(信息),然后根据商品(信息)生成一串数字并对应该商品(信息)记录,此时就完成了一个商品订单的生成。当用户在前台点击该商品订单的时候,用户会看到该订单商品的详细信息,这就是数字为什么要绑定商品信息的原因。如果订单只有一串数字(订单号)而不包含其他商品信息,这样是不符合要求的。
该方法通过传递过来的userId来进行用户区分,从购物车中获取该userId(用户)下的所有的商品信息并存放到List集合中,通过getCartOrderItem方法来生成个当前用户的购物车中商品的总价。如果到这里请求都是成功的,接下来就通过shippingId来生成订单,此时生成的订单中就包含当前用户下单的商品信息和下单的商品总价。如果返回的order为null,表示生成定订单错误;如果orderItemList为空,说明在用户购物车中没有商品,否则订单生成成功。然后把生成的订单信息批量插入到数据库中,同时减少相应的商品库存和清空在用户购物车中的对应的商品记录信息,最后将数据返回给前端即可。
-
private ServerResponse getCartOrderItem(Integer userId,List<Cart> cartList){ -
List<OrderItem> orderItemList = Lists.newArrayList(); -
if(CollectionUtils.isEmpty(cartList)){ -
return ServerResponse.createByErrorMessage("购物车为空"); -
} -
//校验购物车的数据,包括产品的状态和数量 -
for(Cart cartItem : cartList){ -
OrderItem orderItem = new OrderItem(); -
Product product = productMapper.selectByPrimaryKey(cartItem.getProductId()); -
if(Const.ProductStatusEnum.ON_SALE.getCode() != product.getStatus()){ -
return ServerResponse.createByErrorMessage("产品"+product.getName()+"不是在线售卖状态"); -
} -
//校验库存 -
if(cartItem.getQuantity() > product.getStock()){ -
return ServerResponse.createByErrorMessage("产品"+product.getName()+"库存不足"); -
} -
orderItem.setUserId(userId); -
orderItem.setProductId(product.getId()); -
orderItem.setProductName(product.getName()); -
orderItem.setProductImage(product.getMainImage()); -
orderItem.setCurrentUnitPrice(product.getPrice()); -
orderItem.setQuantity(cartItem.getQuantity()); -
orderItem.setTotalPrice(BigDecimalUtil.mul(product.getPrice().doubleValue(),cartItem.getQuantity())); -
orderItemList.add(orderItem); -
} -
return ServerResponse.createBySuccess(orderItemList); -
}
getCartOrderItem方法需要传递一个userId和Cart类型的List集合。该方法的主要作用是判断用户购物车是否为空
-
private void reduceProductStock(List<OrderItem> orderItemList){ -
for(OrderItem orderItem : orderItemList){ -
Product product = productMapper.selectByPrimaryKey(orderItem.getProductId()); -
product.setStock(product.getStock()-orderItem.getQuantity()); -
productMapper.updateByPrimaryKeySelective(product); -
} -
}
减少商品库存
-
private void cleanCart(List<Cart> cartList){ -
for(Cart cart : cartList){ -
cartMapper.deleteByPrimaryKey(cart.getId()); -
} -
}
清空用户购物车
Controller层
-
@RequestMapping("create.do") -
@ResponseBody -
public ServerResponse create(HttpSession session, Integer shippingId){ -
User user = (User)session.getAttribute(Const.CURRENT_USER); -
if(user ==null){ -
return ServerResponse.createByErrorCodeMessage(ResponseCode.NEED_LOGIN.getCode(),ResponseCode.NEED_LOGIN.getDesc()); -
} -
return iOrderService.createOrder(user.getId(),shippingId); -
}
在生成订单之前需要对用户是否登录做一个校验,如果用户未登录则需要强制登录,否则返回在Service层中的处理方法即可!
四、订单管理模块-前台-取消订单功能的开发
-
public ServerResponse<String> cancel(Integer userId,Long orderNo){ -
Order order = orderMapper.selectByUserIdAndOrderNo(userId,orderNo); -
if(order == null){ -
return ServerResponse.createByErrorMessage("该用户此订单不存在"); -
} -
if(order.getStatus() != Const.OrderStatusEnum.NO_PAY.getCode()){ -
return ServerResponse.createByErrorMessage("已付款,无法取消订单"); -
} -
Order updateOrder = new Order(); -
updateOrder.setId(order.getId()); -
updateOrder.setStatus(Const.OrderStatusEnum.CANCELED.getCode()); -
int row = orderMapper.updateByPrimaryKeySelective(updateOrder); -
if(row > 0){ -
return ServerResponse.createBySuccess(); -
} -
return ServerResponse.createByError(); -
}
取消订单的返回结果是String类型的,所以ServerResponse的泛型为String。通过传递过来的userId和对应的订单号来进行订单的查询。在查询出来以后还要进行是否已付款的校验,如果订单已经付款,就不能取消订单,否则就进行取消订单的操作。
-
@RequestMapping("cancel.do") -
@ResponseBody -
public ServerResponse cancel(HttpSession session, Long orderNo){ -
User user = (User)session.getAttribute(Const.CURRENT_USER); -
if(user ==null){ -
return ServerResponse.createByErrorCodeMessage(ResponseCode.NEED_LOGIN.getCode(),ResponseCode.NEED_LOGIN.getDesc()); -
} -
return iOrderService.cancel(user.getId(),orderNo); -
}
处理方法同上,不再赘述!
五、订单管理模块-前台-获取购物车中订单的数量功能的开发
-
public ServerResponse getOrderCartProduct(Integer userId){ -
OrderProductVo orderProductVo = new OrderProductVo(); -
//从购物车中获取数据 -
List<Cart> cartList = cartMapper.selectCheckedCartByUserId(userId); -
ServerResponse serverResponse = this.getCartOrderItem(userId,cartList); -
if(!serverResponse.isSuccess()){ -
return serverResponse; -
} -
List<OrderItem> orderItemList =( List<OrderItem> ) serverResponse.getData(); -
List<OrderItemVo> orderItemVoList = Lists.newArrayList(); -
BigDecimal payment = new BigDecimal("0"); -
for(OrderItem orderItem : orderItemList){ -
payment = BigDecimalUtil.add(payment.doubleValue(),orderItem.getTotalPrice().doubleValue()); -
orderItemVoList.add(assembleOrderItemVo(orderItem)); -
} -
orderProductVo.setProductTotalPrice(payment); -
orderProductVo.setOrderItemVoList(orderItemVoList); -
orderProductVo.setImageHost(PropertiesUtil.getProperty("ftp.server.http.prefix")); -
return ServerResponse.createBySuccess(orderProductVo); -
}
Controller层
-
@RequestMapping("get_order_cart_product.do") -
@ResponseBody -
public ServerResponse getOrderCartProduct(HttpSession session){ -
User user = (User)session.getAttribute(Const.CURRENT_USER); -
if(user ==null){ -
return ServerResponse.createByErrorCodeMessage(ResponseCode.NEED_LOGIN.getCode(),ResponseCode.NEED_LOGIN.getDesc()); -
} -
return iOrderService.getOrderCartProduct(user.getId()); -
}
处理方法同上,不再赘述!
六、订单管理模块-前台-获取订单列表功能的开发
-
public ServerResponse<PageInfo> getOrderList(Integer userId,int pageNum,int pageSize){ -
PageHelper.startPage(pageNum,pageSize); -
List<Order> orderList = orderMapper.selectByUserId(userId); -
List<OrderVo> orderVoList = assembleOrderVoList(orderList,userId); -
PageInfo pageResult = new PageInfo(orderList); -
pageResult.setList(orderVoList); -
return ServerResponse.createBySuccess(pageResult); -
}
获取订单列表的操作和之前获取列表的操作是一样的,不再赘述!
-
@RequestMapping("list.do") -
@ResponseBody -
public ServerResponse list(HttpSession session, @RequestParam(value = "pageNum",defaultValue = "1") int pageNum, @RequestParam(value = "pageSize",defaultValue = "10") int pageSize){ -
User user = (User)session.getAttribute(Const.CURRENT_USER); -
if(user ==null){ -
return ServerResponse.createByErrorCodeMessage(ResponseCode.NEED_LOGIN.getCode(),ResponseCode.NEED_LOGIN.getDesc()); -
} -
return iOrderService.getOrderList(user.getId(),pageNum,pageSize); -
}
处理方法同上,不再赘述!
七、时间和字符串类型之间的转换工具类的补充(joda-time)
-
public class DateTimeUtil { -
//joda-time -
//str->Date -
//Date->str -
public static final String STANDARD_FORMAT = "yyyy-MM-dd HH:mm:ss"; -
public static Date strToDate(String dateTimeStr,String formatStr){ -
DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(formatStr); -
DateTime dateTime = dateTimeFormatter.parseDateTime(dateTimeStr); -
return dateTime.toDate(); -
} -
public static String dateToStr(Date date,String formatStr){ -
if(date == null){ -
return StringUtils.EMPTY; -
} -
DateTime dateTime = new DateTime(date); -
return dateTime.toString(formatStr); -
} -
public static Date strToDate(String dateTimeStr){ -
DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(STANDARD_FORMAT); -
DateTime dateTime = dateTimeFormatter.parseDateTime(dateTimeStr); -
return dateTime.toDate(); -
} -
public static String dateToStr(Date date){ -
if(date == null){ -
return StringUtils.EMPTY; -
} -
DateTime dateTime = new DateTime(date); -
return dateTime.toString(STANDARD_FORMAT); -
} -
}
由于时间关系,剩下的功能我们下期再见!
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36314960/article/details/79395708