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

领域驱动设计(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;                  // 订单IDprivate String customerId;        // 用户IDprivate 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;   // 商品IDprivate 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;}@Overridepublic void save(Order order) {jpaRepository.save(order);}@Overridepublic 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;}@PostMappingpublic 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 的小型实践示例,后续可以扩展领域事件、复杂聚合和限界上下文的实现。

相关文章:

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

以下是基于 领域驱动设计&#xff08;DDD&#xff09; 的订单管理系统实践步骤&#xff0c;系统功能主要包括订单的创建、更新、查询和状态管理&#xff0c;采用 Spring Boot 框架进行实现。 1. 需求分析 订单管理系统的基本功能&#xff1a; 订单创建&#xff1a;用户下单创…...

leetcode 面试经典 150 题:简化路径

链接简化路径题序号71题型字符串解法栈难度中等熟练度✅✅✅ 题目 给你一个字符串 path &#xff0c;表示指向某一文件或目录的 Unix 风格 绝对路径 &#xff08;以 ‘/’ 开头&#xff09;&#xff0c;请你将其转化为 更加简洁的规范路径。 在 Unix 风格的文件系统中规则如下…...

基于 STM32 的智能农业温室控制系统设计

1. 引言 随着农业现代化的发展&#xff0c;智能农业温室控制系统对于提高农作物产量和质量具有重要意义。该系统能够实时监测温室内的环境参数&#xff0c;如温度、湿度、光照强度和土壤湿度等&#xff0c;并根据这些参数自动调节温室设备&#xff0c;如通风扇、加热器、加湿器…...

【Spring Boot】掌握 Spring 事务:隔离级别与传播机制解读与应用

前言 &#x1f31f;&#x1f31f;本期讲解关于spring 事务传播机制介绍~~~ &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 &#x1f525; 你的点赞就是小编不断更新的最大动力 &#x1f386;那么废话…...

【Postgres_Python】使用python脚本将多个PG数据库合并为一个PG数据库

需要合并的多个PG数据库表个数和结构一致&#xff0c;这里提供一种思路&#xff0c;选择sql语句insert插入的方式进行&#xff0c;即将其他PG数据库的每个表内容插入到一个PG数据库中完成数据库合并 示例代码说明&#xff1a; 选择一个数据库导出表结构为.sql文件&#xff08…...

Tailwind CSS v4.0 发布

Holy shit its actually done &#xff01; 1 月 22 日&#xff0c;Tailwind CSS 正式发布了 4.0 版本&#xff0c;针对性能和灵活性进行了优化&#xff0c;重新构想了配置和定制体验&#xff0c;并充分利用了 Web 平台提供的最新进展。 新的高性能引擎- 完整构建速度提高 5 …...

pandas基础:文件的读取和写入

文件的读取和写入 读取csv文件 csv文件&#xff1a; name,age,city Alice,25,New York Bob,30,Los Angelesread_csv(filename) header&#xff1a;如 何处理文件的第一行。header0将第一行作为列名&#xff0c;headerNone表示文件中没有列名&#xff0c;所有行都是数据。 im…...

【MySQL — 数据库增删改查操作】深入解析MySQL的create insert 操作

数据库CRUD操作 1 CRUD简介 CURD是对数据库中的记录进行基本的增删改查操作: 2. Create 新增 语法 INSERT [INTO] table_name[(column [&#xff0c;column] ...)] VALUES(value_list)[&#xff0c;(value_list)] ... # value 后面的列的个数和类型&#xff0c;要和表结构匹配…...

每日OJ_牛客_小红的子串_滑动窗口+前缀和_C++_Java

目录 牛客_小红的子串_滑动窗口前缀和 题目解析 C代码 Java代码 牛客_小红的子串_滑动窗口前缀和 小红的子串 描述&#xff1a; 小红拿到了一个长度为nnn的字符串&#xff0c;她准备选取一段子串&#xff0c;满足该子串中字母的种类数量在[l,r]之间。小红想知道&…...

HTTP 配置与应用(局域网)

想做一个自己学习的有关的csdn账号&#xff0c;努力奋斗......会更新我计算机网络实验课程的所有内容&#xff0c;还有其他的学习知识^_^&#xff0c;为自己巩固一下所学知识&#xff0c;下次更新HTTP 配置与应用&#xff08;不同网段&#xff09;。 我是一个萌新小白&#xf…...

ultralytics 是什么?

ultralytics 是一个用于计算机视觉任务的 Python 库&#xff0c;专注于提供高效、易用的目标检测、实例分割和图像分类工具。它最著名的功能是实现 YOLO&#xff08;You Only Look Once&#xff09; 系列模型&#xff0c;特别是最新的 YOLOv8。 1. YOLO 是什么&#xff1f; YO…...

AI竞争:从技术壁垒到用户数据之争

标题&#xff1a;AI竞争&#xff1a;从技术壁垒到用户数据之争 文章信息摘要&#xff1a; AI市场呈现开放模型与封闭模型并存的双轨发展态势&#xff0c;但核心竞争力已从模型技术转向用户数据积累和使用习惯培养。商业模式正在多元化发展&#xff0c;从早期的价格战转向subsc…...

MySQL 主从复制(单组传统复制,GTID复制。双主复制)

案例环境 单组复制 master&#xff1a; 192.168.180.143 slave01&#xff1a;192.168.180.144 双组复制 master01&#xff1a;192.168.180.143 master02&#xff1a;192.168.180.144 案例过程 准备工作 关闭所有防火墙 setenforce 0 && systemctl stop firewa…...

python学opencv|读取图像(四十)掩模:三通道图像的局部覆盖

【1】引言 前序学习了使用numpy创建单通道的灰色图像&#xff0c;并对灰色图像的局部进行了颜色更改&#xff0c;相关链接为&#xff1a; python学opencv|读取图像&#xff08;九&#xff09;用numpy创建黑白相间灰度图_numpy生成全黑图片-CSDN博客 之后又学习了使用numpy创…...

vue3 中如何监听 props 中的值的变化

在 Vue 3 中&#xff0c;你可以使用 watch 函数来监听组件的 props 值的变化。watch 函数允许你观察一个或多个响应式数据源&#xff0c;并在这些数据源发生变化时执行回调函数。 以下是一个示例&#xff0c;展示了如何在 Vue 3 中使用 watch 来监听 props 中的值的变化&#…...

Scrapy之一个item包含多级页面的处理方案

目标 在实际开发过程中&#xff0c;我们所需要的数据往往需要通过多个页面的数据汇总得到&#xff0c;通过列表获取到的数据只有简单的介绍。站在Scrapy框架的角度来看&#xff0c;实际上就是考虑如何处理一个item包含多级页面数据的问题。本文将以获取叶子猪网站的手游排行榜及…...

hive 自动检测、自动重启、记录检测日志、自动清理日志

最终效果 定时检测hive运行状态&#xff0c;进程不存在或者进程存在但是不监听端口的hiveserver2&#xff0c;自动重新拉起每次检测脚本执行的日志都会保存在log目录下.check文件&#xff0c;每一个月一个文件每月15日&#xff0c;删除2月前的检测日志开启hive自带日志输出后&…...

HFSS同轴替换波端口

波端口仿真正常 将波端口换成内径内径0.3mm外径0.6mm同轴之后 结果很不对 换成下面的尺寸就好了...

【2024年华为OD机试】 (C卷,100分)- 素数之积(JavaScriptJava PythonC/C++)

一、问题描述 RSA 因数分解问题 题目描述 RSA 加密算法在网络安全世界中无处不在&#xff0c;它利用了极大整数因数分解的困难度。数据越大&#xff0c;安全系数越高。给定一个 32 位正整数&#xff0c;请对其进行因数分解&#xff0c;找出是哪两个素数的乘积。 输入描述 …...

【C++模板】:如何判断自定义类型是否实现某个函数

一、引子 偶尔我们会面对这样的尴尬的场景&#xff0c;我们需要显示的去判断在某个自定义类型中&#xff0c;是否已经提供了我们期待的API接口&#xff0c;以避免产生“莫须有”的错误。阁下该如何破解此问题&#xff01; 这里&#xff0c;直接给出一种通用的方法&#xff0c;…...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计&#xff1a;let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性&#xff0c;这种设计体现了语言的核心哲学。以下是深度解析&#xff1a; 1.1 设计理念剖析 安全优先原则&#xff1a;默认不可变强制开发者明确声明意图 let x 5; …...

stm32G473的flash模式是单bank还是双bank?

今天突然有人stm32G473的flash模式是单bank还是双bank&#xff1f;由于时间太久&#xff0c;我真忘记了。搜搜发现&#xff0c;还真有人和我一样。见下面的链接&#xff1a;https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频

使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验

一、多模态商品数据接口的技术架构 &#xff08;一&#xff09;多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如&#xff0c;当用户上传一张“蓝色连衣裙”的图片时&#xff0c;接口可自动提取图像中的颜色&#xff08;RGB值&…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)

要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况&#xff0c;可以通过以下几种方式模拟或触发&#xff1a; 1. 增加CPU负载 运行大量计算密集型任务&#xff0c;例如&#xff1a; 使用多线程循环执行复杂计算&#xff08;如数学运算、加密解密等&#xff09;。运行图…...

算法笔记2

1.字符串拼接最好用StringBuilder&#xff0c;不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...

Yolov8 目标检测蒸馏学习记录

yolov8系列模型蒸馏基本流程&#xff0c;代码下载&#xff1a;这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中&#xff0c;**知识蒸馏&#xff08;Knowledge Distillation&#xff09;**被广泛应用&#xff0c;作为提升模型…...

并发编程 - go版

1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程&#xff0c;系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...