当前位置: 首页 > article >正文

领域驱动设计(DDD)四 订单管理系统实践步骤

以下是基于 领域驱动设计(DDD) 的订单管理系统实践步骤,系统功能主要包括订单的创建、更新、查询和状态管理,采用 Spring Boot 框架进行实现。


1. 需求分析

订单管理系统的基本功能:

  1. 订单创建:用户下单创建订单。
  2. 订单状态更新:更新订单状态(如已支付、已发货、已完成)。
  3. 订单查询:支持按订单 ID 或用户查询订单信息。
  4. 库存管理(简化版):订单创建时检查并扣减库存。

2. 领域划分与限界上下文

限界上下文

  1. 订单上下文(Order Context):负责订单的生命周期管理。
  2. 库存上下文(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)
);

测试示例

  1. 创建订单

    POST /api/orders
    {
        "customerId": "123",
        "items": [
            { "productId": 1, "quantity": 2, "price": 50.00 },
            { "productId": 2, "quantity": 1, "price": 100.00 }
        ]
    }
    
  2. 更新订单状态

    PUT /api/orders/1/status?status=PAID
    
  3. 查询订单

    GET /api/orders/1
    

这套设计是 DDD 的小型实践示例,后续可以扩展领域事件、复杂聚合和限界上下文的实现。


http://www.kler.cn/a/516104.html

相关文章:

  • 编程界“华山论剑”:PHP与Go,谁主沉浮?
  • 计算机毕业设计hadoop+spark+hive图书推荐系统 豆瓣图书数据分析可视化大屏 豆瓣图书爬虫 知识图谱 图书大数据 大数据毕业设计 机器学习
  • centos9编译安装opensips 二【进阶篇-定制目录+模块】推荐
  • C#集合操作优化:高效实现批量添加与删除
  • 【项目初始化】自定义异常处理
  • cookie 与 session -- 会话管理
  • 【时时三省】(C语言基础)格式化输入输出函数
  • 2025.1.21——六、BUU XSS COURSE 1
  • P1115 最大子段和
  • 人工智能在音频、视觉、多模态领域的应用
  • 踏浪而行,2024年技术创作的星光轨迹
  • c++瓷砖
  • 4. LwIP_网络数据包管理
  • Spring AI Document
  • 消息队列篇--原理篇--常见消息队列总结(RabbitMQ,Kafka,ActiveMQ,RocketMQ,Pulsar)
  • IoTDB结合Mybatis使用示例(增删查改自定义sql等)
  • electron打包报错解决
  • ThinkPHP 8模型与数据的插入、更新、删除
  • 转换模型到 bfloat16 精度之前需要做的检查工作,不然模型报错给你看
  • Java学习教程,从入门到精通,JDBC创建数据库语法知识点及案例代码(99)
  • SpringBoot读取配置优先级顺序是什么?
  • 【记录自开发的SQL工具】工具字符拼接、Excel转sql、生成编码、生成测试数据
  • verilog笔记1
  • jmeter中对接口进行循环请求后获取相应数据
  • 智能工厂数字化化集成落地项目(交付版 67页)PPT 解读
  • K8S 快速实战