领域驱动设计(DDD)四 订单管理系统实践步骤
以下是基于 领域驱动设计(DDD) 的订单管理系统实践步骤,系统功能主要包括订单的创建、更新、查询和状态管理,采用 Spring Boot 框架进行实现。
1. 需求分析
订单管理系统的基本功能:
- 订单创建:用户下单创建订单。
- 订单状态更新:更新订单状态(如已支付、已发货、已完成)。
- 订单查询:支持按订单 ID 或用户查询订单信息。
- 库存管理(简化版):订单创建时检查并扣减库存。
2. 领域划分与限界上下文
限界上下文
- 订单上下文(Order Context):负责订单的生命周期管理。
- 库存上下文(Inventory Context):负责商品库存的管理。
模块划分
src/main/java/com/example/order
├── application # 应用层:处理用例逻辑
│ ├── service # 应用服务
│ └── dto # 数据传输对象
├── domain # 领域层:业务逻辑
│ ├── model # 领域模型(实体、值对象、聚合)
│ ├── repository # 仓储接口
│ ├── service # 领域服务
│ └── event # 领域事件
├── infrastructure # 基础设施层:技术实现
│ ├── repository # 仓储实现
│ └── event # 事件机制
└── interfaces # 接口层:用户交互
├── controller # REST 接口
└── vo # 视图对象
3. 代码实现
3.1 领域层设计
领域模型
(1) 订单实体
public class Order {
private Long id; // 订单ID
private String customerId; // 用户ID
private List<OrderItem> items; // 订单项
private OrderStatus status; // 订单状态
// 创建订单
public Order(String customerId, List<OrderItem> items) {
this.customerId = customerId;
this.items = items;
this.status = OrderStatus.CREATED;
}
// 更新订单状态
public void updateStatus(OrderStatus status) {
if (this.status.canTransitionTo(status)) {
this.status = status;
} else {
throw new IllegalStateException("非法状态转换");
}
}
// 计算总金额
public BigDecimal calculateTotal() {
return items.stream()
.map(item -> item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity())))
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
// Getters and Setters
}
(2) 订单项值对象
public class OrderItem {
private Long productId; // 商品ID
private int quantity; // 数量
private BigDecimal price; // 单价
// 构造方法
public OrderItem(Long productId, int quantity, BigDecimal price) {
this.productId = productId;
this.quantity = quantity;
this.price = price;
}
// Getters and Setters
}
(3) 订单状态值对象
public enum OrderStatus {
CREATED, PAID, SHIPPED, COMPLETED;
// 状态转换规则
public boolean canTransitionTo(OrderStatus newStatus) {
return switch (this) {
case CREATED -> newStatus == PAID;
case PAID -> newStatus == SHIPPED;
case SHIPPED -> newStatus == COMPLETED;
default -> false;
};
}
}
3.2 应用层设计
订单服务
@Service
public class OrderApplicationService {
private final OrderRepository orderRepository;
private final InventoryService inventoryService;
public OrderApplicationService(OrderRepository orderRepository, InventoryService inventoryService) {
this.orderRepository = orderRepository;
this.inventoryService = inventoryService;
}
// 创建订单
public Long createOrder(String customerId, List<OrderItemDto> itemDtos) {
// 转换 DTO 为领域模型
List<OrderItem> items = itemDtos.stream()
.map(dto -> new OrderItem(dto.getProductId(), dto.getQuantity(), dto.getPrice()))
.toList();
// 检查库存
items.forEach(item -> inventoryService.reserveStock(item.getProductId(), item.getQuantity()));
// 创建订单
Order order = new Order(customerId, items);
orderRepository.save(order);
return order.getId();
}
// 更新订单状态
public void updateOrderStatus(Long orderId, OrderStatus status) {
Order order = orderRepository.findById(orderId).orElseThrow(() -> new RuntimeException("订单不存在"));
order.updateStatus(status);
orderRepository.save(order);
}
// 查询订单
public OrderDto getOrderById(Long orderId) {
Order order = orderRepository.findById(orderId).orElseThrow(() -> new RuntimeException("订单不存在"));
return OrderDto.fromDomain(order);
}
}
3.3 基础设施层设计
仓储实现
@Repository
public class JpaOrderRepository implements OrderRepository {
private final SpringDataOrderJpaRepository jpaRepository;
public JpaOrderRepository(SpringDataOrderJpaRepository jpaRepository) {
this.jpaRepository = jpaRepository;
}
@Override
public void save(Order order) {
jpaRepository.save(order);
}
@Override
public Optional<Order> findById(Long id) {
return jpaRepository.findById(id);
}
}
事件机制
@Component
public class DomainEventPublisher {
private final ApplicationEventPublisher eventPublisher;
public DomainEventPublisher(ApplicationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
public void publish(Object event) {
eventPublisher.publishEvent(event);
}
}
3.4 接口层设计
订单控制器
@RestController
@RequestMapping("/api/orders")
public class OrderController {
private final OrderApplicationService orderService;
public OrderController(OrderApplicationService orderService) {
this.orderService = orderService;
}
@PostMapping
public ResponseEntity<Long> createOrder(@RequestBody OrderRequest request) {
Long orderId = orderService.createOrder(request.getCustomerId(), request.getItems());
return ResponseEntity.status(HttpStatus.CREATED).body(orderId);
}
@PutMapping("/{orderId}/status")
public ResponseEntity<Void> updateStatus(@PathVariable Long orderId, @RequestParam OrderStatus status) {
orderService.updateOrderStatus(orderId, status);
return ResponseEntity.ok().build();
}
@GetMapping("/{orderId}")
public ResponseEntity<OrderDto> getOrderById(@PathVariable Long orderId) {
return ResponseEntity.ok(orderService.getOrderById(orderId));
}
}
3.5 示例数据传输对象(DTO)
public class OrderDto {
private Long id;
private String customerId;
private List<OrderItemDto> items;
private OrderStatus status;
public static OrderDto fromDomain(Order order) {
return new OrderDto(order.getId(), order.getCustomerId(),
order.getItems().stream().map(OrderItemDto::fromDomain).toList(),
order.getStatus());
}
}
4. 运行与测试
数据库表结构(MySQL 示例)
CREATE TABLE orders (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
customer_id VARCHAR(255),
status VARCHAR(50)
);
CREATE TABLE order_items (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
order_id BIGINT,
product_id BIGINT,
quantity INT,
price DECIMAL(10,2),
FOREIGN KEY (order_id) REFERENCES orders(id)
);
测试示例
-
创建订单
POST /api/orders { "customerId": "123", "items": [ { "productId": 1, "quantity": 2, "price": 50.00 }, { "productId": 2, "quantity": 1, "price": 100.00 } ] }
-
更新订单状态
PUT /api/orders/1/status?status=PAID
-
查询订单
GET /api/orders/1
这套设计是 DDD 的小型实践示例,后续可以扩展领域事件、复杂聚合和限界上下文的实现。