3.12订单模块实现

分类: 搭建单体商城服务

订单模块实现

订单模块是商城系统的核心业务模块,包括订单创建、订单查询、订单状态管理等功能。本节将学习如何实现完整的订单模块。

本节将学习:创建订单、订单查询、订单状态管理,以及订单支付。

创建订单

订单创建流程

订单创建实现

package com.example.ecommerce.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.example.ecommerce.entity.Order; import com.example.ecommerce.entity.OrderItem; import com.example.ecommerce.entity.Product; import com.example.ecommerce.mapper.OrderMapper; import com.example.ecommerce.service.OrderService; import com.example.ecommerce.service.OrderItemService; import com.example.ecommerce.service.ProductService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.List; import java.util.UUID; @Service public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService { @Autowired private OrderItemService orderItemService; @Autowired private ProductService productService; @Override @Transactional(rollbackFor = Exception.class) public Order createOrder(Long userId, List<OrderItem> orderItems, String shippingAddress) { // 1. 验证商品并计算总金额 BigDecimal totalAmount = BigDecimal.ZERO; for (OrderItem item : orderItems) { Product product = productService.getById(item.getProductId()); if (product == null || product.getStatus() == 0) { throw new BusinessException("Product not found or off-shelf"); } if (product.getStock() < item.getQuantity()) { throw new BusinessException("Insufficient stock for product: " + product.getName()); } // 使用商品当前价格 item.setPrice(product.getPrice()); item.setSubtotal(product.getPrice().multiply(BigDecimal.valueOf(item.getQuantity()))); totalAmount = totalAmount.add(item.getSubtotal()); } // 2. 创建订单 Order order = new Order(); order.setOrderNo(generateOrderNo()); order.setUserId(userId); order.setTotalAmount(totalAmount); order.setStatus(0); // 待支付 order.setShippingAddress(shippingAddress); save(order); // 3. 保存订单项 for (OrderItem item : orderItems) { item.setOrderId(order.getId()); orderItemService.save(item); } return order; } private String generateOrderNo() { return "ORD" + System.currentTimeMillis() + UUID.randomUUID().toString().substring(0, 8).toUpperCase(); } }

订单DTO

package com.example.ecommerce.dto; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotEmpty; import lombok.Data; import java.util.List; @Data public class OrderCreateDTO { @NotEmpty(message = "Order items cannot be empty") @Valid private List<OrderItemDTO> orderItems; @NotBlank(message = "Shipping address cannot be blank") private String shippingAddress; } @Data class OrderItemDTO { @NotNull(message = "Product ID cannot be null") private Long productId; @NotNull(message = "Quantity cannot be null") @Min(value = 1, message = "Quantity must be at least 1") private Integer quantity; }

Controller 实现

@PostMapping public Result<Order> createOrder(@RequestParam Long userId, @RequestBody @Valid OrderCreateDTO orderDTO) { List<OrderItem> orderItems = orderDTO.getOrderItems().stream() .map(dto -> { OrderItem item = new OrderItem(); item.setProductId(dto.getProductId()); item.setQuantity(dto.getQuantity()); return item; }) .collect(Collectors.toList()); Order order = orderService.createOrder(userId, orderItems, orderDTO.getShippingAddress()); return Result.success("Order created successfully", order); }

订单查询

订单列表查询

@Override public Page<Order> getOrderList(Long userId, Integer status, Integer current, Integer size) { Page<Order> page = new Page<>(current, size); LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>(); if (userId != null) { wrapper.eq(Order::getUserId, userId); } if (status != null) { wrapper.eq(Order::getStatus, status); } wrapper.orderByDesc(Order::getCreateTime); return page(page, wrapper); }

订单详情查询

@Override public Order getOrderDetail(Long id) { Order order = getById(id); if (order == null) { throw new BusinessException("Order not found"); } // 查询订单项 List<OrderItem> orderItems = orderItemService.list( new LambdaQueryWrapper<OrderItem>() .eq(OrderItem::getOrderId, id) ); order.setOrderItems(orderItems); return order; }

Controller 实现

@GetMapping public Result<Page<Order>> getOrderList( @RequestParam(required = false) Long userId, @RequestParam(required = false) Integer status, @RequestParam(defaultValue = "1") Integer current, @RequestParam(defaultValue = "10") Integer size ) { Page<Order> page = orderService.getOrderList(userId, status, current, size); return Result.success(page); } @GetMapping("/{id}") public Result<Order> getOrderDetail(@PathVariable Long id) { Order order = orderService.getOrderDetail(id); return Result.success(order); }

订单状态管理

订单状态流转

订单状态定义

package com.example.ecommerce.enums; public enum OrderStatus { PENDING(0, "Pending Payment"), PAID(1, "Paid"), SHIPPED(2, "Shipped"), COMPLETED(3, "Completed"), CANCELLED(4, "Cancelled"); private final Integer code; private final String description; OrderStatus(Integer code, String description) { this.code = code; this.description = description; } public Integer getCode() { return code; } public String getDescription() { return description; } }

状态更新实现

@Override @Transactional(rollbackFor = Exception.class) public boolean updateOrderStatus(Long id, Integer status) { Order order = getById(id); if (order == null) { throw new BusinessException("Order not found"); } // 验证状态流转 if (!isValidStatusTransition(order.getStatus(), status)) { throw new BusinessException("Invalid status transition"); } order.setStatus(status); if (status == OrderStatus.SHIPPED.getCode()) { order.setShipTime(LocalDateTime.now()); } else if (status == OrderStatus.COMPLETED.getCode()) { order.setCompleteTime(LocalDateTime.now()); } return updateById(order); } private boolean isValidStatusTransition(Integer currentStatus, Integer newStatus) { // 待支付 -> 已支付、已取消 if (currentStatus == OrderStatus.PENDING.getCode()) { return newStatus == OrderStatus.PAID.getCode() || newStatus == OrderStatus.CANCELLED.getCode(); } // 已支付 -> 已发货、已取消 if (currentStatus == OrderStatus.PAID.getCode()) { return newStatus == OrderStatus.SHIPPED.getCode() || newStatus == OrderStatus.CANCELLED.getCode(); } // 已发货 -> 已完成 if (currentStatus == OrderStatus.SHIPPED.getCode()) { return newStatus == OrderStatus.COMPLETED.getCode(); } return false; }

订单支付

支付流程

支付实现

@Override @Transactional(rollbackFor = Exception.class) public boolean payOrder(Long orderId, String paymentMethod) { Order order = getById(orderId); if (order == null) { throw new BusinessException("Order not found"); } if (order.getStatus() != OrderStatus.PENDING.getCode()) { throw new BusinessException("Order cannot be paid"); } // 创建支付记录 Payment payment = new Payment(); payment.setOrderId(orderId); payment.setPaymentNo(generatePaymentNo()); payment.setAmount(order.getTotalAmount()); payment.setPaymentMethod(paymentMethod); payment.setStatus(0); // 待支付 paymentService.save(payment); // 模拟支付处理(实际应该调用支付网关) // 这里简化处理,直接设置为支付成功 payment.setStatus(1); // 支付成功 payment.setPayTime(LocalDateTime.now()); paymentService.updateById(payment); // 更新订单状态 order.setStatus(OrderStatus.PAID.getCode()); updateById(order); return true; } private String generatePaymentNo() { return "PAY" + System.currentTimeMillis() + UUID.randomUUID().toString().substring(0, 8).toUpperCase(); }

Controller 实现

@PostMapping("/{id}/pay") public Result<?> payOrder(@PathVariable Long id, @RequestParam String paymentMethod) { orderService.payOrder(id, paymentMethod); return Result.success("Order paid successfully"); }

完整订单模块示例

OrderService 接口

package com.example.ecommerce.service; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import com.example.ecommerce.entity.Order; import com.example.ecommerce.entity.OrderItem; import java.util.List; public interface OrderService extends IService<Order> { Order createOrder(Long userId, List<OrderItem> orderItems, String shippingAddress); Page<Order> getOrderList(Long userId, Integer status, Integer current, Integer size); Order getOrderDetail(Long id); boolean updateOrderStatus(Long id, Integer status); boolean payOrder(Long orderId, String paymentMethod); boolean cancelOrder(Long id); }

官方资源

本节小结

在本节中,我们实现了:

第一个是创建订单。 验证商品、检查库存、计算总金额、创建订单和订单项。

第二个是订单查询。 支持分页查询和订单详情查询。

第三个是订单状态管理。 实现订单状态流转和状态更新。

第四个是订单支付。 创建支付记录、处理支付、更新订单状态。

这就是订单模块实现。订单模块是商城系统的核心业务模块,涉及多个表的操作和事务管理。

在下一节,我们将学习如何集成 Thymeleaf 前端,实现前后端联调。