快速开始
DDK 尚未发布到 Maven 中央仓库,需要先在本地构建安装。之后有三条路:用 archetype 生成新服务、运行示例看一个完整用例、或者在已有项目里按需引入 starter。
一条命令上手
脚本会检查 JDK 21+ 与 Maven,把 DDK 克隆到 ~/.ddk/src 并安装到本地仓库,再用 archetype 生成项目:
curl -fsSL https://raw.githubusercontent.com/poppycoderr/domain-driven-kit/main/scripts/ddk.sh | bash -s -- new order-service --group com.acme
cd order-service && mvn verify| 选项 / 环境变量 | 默认值 | 说明 |
|---|---|---|
--group | com.example | 生成项目的 groupId |
--package | groupId + 去掉连字符的 artifactId | 根包名 |
--layers | 4 | 3 或 4,选择三层 / 四层骨架 |
DDK_REF | main | 构建的分支或 tag,例如 v0.1.0 |
DDK_HOME | ~/.ddk | 源码检出目录 |
只安装不生成项目:ddk.sh install。下面是脚本背后的手动步骤。
一、本地构建
git clone https://github.com/poppycoderr/domain-driven-kit.git
cd domain-driven-kit
mvn install环境要求:JDK 21、Maven 3.9+。构建会把 com.ddk:*:0.3.0-SNAPSHOT 装到本地仓库。只想快速安装、不关心测试时可以加 -DskipTests;提交代码前请完整跑一遍,CI 使用的是 mvn install -Parchetype-it。
二、生成一个新服务
mvn archetype:generate \
-DarchetypeGroupId=com.ddk \
-DarchetypeArtifactId=ddk-layer4-archetype \
-DarchetypeVersion=0.3.0-SNAPSHOT \
-DgroupId=com.acme \
-DartifactId=order-service \
-Dpackage=com.acme.order \
-DinteractiveMode=false
cd order-service
mvn verify
mvn spring-boot:run业务简单的服务可以换成 ddk-layer3-archetype,两者的取舍见四层架构 / 三层架构。
生成的项目:
order-service
├── pom.xml spring-boot-starter-parent + ddk-dependencies BOM
├── AGENTS.md / CLAUDE.md 写给 AI 编码代理的约定与完成标准
├── .claude/skills Claude Code Skills:新增聚合、用例、领域事件
└── src
├── main/java/com/acme/order
│ ├── Application
│ ├── adapter/controller
│ ├── application/{command,query,response,service,handler}
│ ├── domain/{model,event,acl,service,error}
│ └── infrastructure/{acl/impl,converter,orm/po,orm/mapper}
├── main/resources/application.yml 内存 H2,开箱即可启动
├── main/resources/db/migration Flyway 迁移脚本,自带一个基线 V1__baseline.sql
└── test/java/com/acme/order
├── ApplicationTest 上下文启动
└── ArchitectureTest 分层规则,违反即构建失败,报告写入 target/archguard表结构由 Flyway 管理:每次变化在 db/migration 下新增一个 V<版本号>__<说明>.sql,启动时自动执行,已执行过的脚本不再修改。接入 MySQL 时除了驱动还要引入 flyway-mysql。(v0.3.0 及更早版本生成的项目没有这个目录。)
每个包里的 package-info.java 写明了它放什么。生成的项目不含示例代码,没有需要删除的东西。用 Claude Code、Codex 在生成的项目里开发,见用 AI 编码代理开发。
三、运行示例
ddk-examples/ddk-example-user 是一个完整的四层用例:注册、查询、分页、修改、禁用 / 启用、删除,内存 H2 带种子数据。
mvn -pl ddk-examples/ddk-example-user spring-boot:runcurl -s -X POST localhost:8080/users -H 'Content-Type: application/json' \
-d '{"username":"dave01","password":"password123","gender":1,"phoneNumber":"13900139001"}'
curl -s localhost:8080/users/1001一个请求如何穿过四层:
POST /users
UserController.register adapter @Valid RegisterUserRequest → RegisterUserCommand
UserService.register application @Transactional:检查用户名占用,编排领域对象
User.register domain 守卫不变量,登记 UserRegisteredEvent
UserRepository.create domain 端口
UserRepositoryImpl infrastructure User → UserPO → t_user,发布领域事件
UserResponse.from(user) application 手机号脱敏
UserEventHandler.on(...) 事务提交后执行示例 README 里有完整的冒烟命令,以及「每个类演示了哪个取舍」的对照表。
四、在已有项目中引入
先 import ddk-dependencies BOM,之后引依赖不用再写版本号:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.ddk</groupId>
<artifactId>ddk-dependencies</artifactId>
<version>0.3.0-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.ddk</groupId>
<artifactId>ddk-web-starter</artifactId>
</dependency>
<dependency>
<groupId>com.ddk</groupId>
<artifactId>ddk-mybatis-starter</artifactId>
</dependency>
<dependency>
<groupId>com.ddk</groupId>
<artifactId>ddk-event-starter</artifactId>
</dependency>
<dependency>
<groupId>com.ddk</groupId>
<artifactId>ddk-archguard-starter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>注意引的是 ddk-mybatis-starter 而不是 ddk-mybatis:通用仓储依赖的 MapperProvider 由前者的自动配置注册。
写一个用例需要落下这些类,以示例为参照:
| 层 | 类 | 示例 |
|---|---|---|
| domain | 聚合根、标识、值对象、事件、仓储端口 | User、UserId、PhoneNumber、UserRegisteredEvent、UserRepository |
| infrastructure | PO、Mapper、两个方向的转换器、仓储实现 | UserPO、UserMapper、UserPoConverter、UserEntityConverter、UserRepositoryImpl |
| application | 命令、查询、响应、应用服务 | RegisterUserCommand、UserPageQuery、UserResponse、UserService |
| adapter | 请求对象、控制器 | RegisterUserRequest、UserController |
Entity ↔ PO 的两个转换器都必须注册,漏掉任何一个,仓储在第一次调用时就会抛 MissingMapperException,并在消息里给出转换器模板。
五、配置示例
spring:
application:
name: order-service
datasource:
url: jdbc:mysql://localhost:3306/orders
username: app
password: secret
ddk:
mybatis:
db-type: mysql # 分页方言
max-page-size: 500
worker-id: 1 # 雪花 ID 机器号,多实例部署必须区分
web:
cors:
enabled: true
allowed-origins: [ "https://admin.acme.com" ]所有 starter 的配置都在 ddk.* 前缀下,并生成了配置元数据,IDE 里有补全。各项说明见 starter 文档。
六、上手前值得知道
| 行为 | 原因 |
|---|---|
JSON 里的 Long 是字符串 | 雪花 ID 超出 JavaScript 安全整数范围,数字形式会在浏览器里静默丢精度。可用 ddk.web.write-long-as-string=false 关闭 |
| 领域不变量违反返回 400 | 值对象、聚合抛带领域错误码的 BusinessException,全局异常处理转成 400 |
pageSize 默认上限 200(MyBatis 插件层 500) | 防止单次查询拉取过多数据,特殊接口在查询对象里覆盖 setter |
PageQuery.addSort() 没有字段白名单 | 对外开放排序参数时,自己做字段映射 |
| 跨域默认关闭 | 库不替使用方开跨域,按需配置 ddk.web.cors.* |