# qiqb-framework
**Repository Path**: fz51/qiqb-framework
## Basic Information
- **Project Name**: qiqb-framework
- **Description**: 构建以DDD(域驱动设计)为中心的应用程序方案
- **Primary Language**: Java
- **License**: Apache-2.0
- **Default Branch**: dev
- **Homepage**: http://www.qiqb.net
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 1
- **Created**: 2024-08-12
- **Last Updated**: 2025-09-20
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# qiqb-framework
构建以CQRS(命令查询、责任分离)和 DDD(域驱动设计)为中心的应用程序方案。
# 快速开始
基本要求:
* java 17
* 了解DDD基本概念
## 非spring boot 模式
添加Maven依赖
```xml
net.qiqb.framework
qiqb-core
${qiqbframework.version}
```
一个简单的用户增删改案例:
```java
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.qiqbframework.commandhandling.CommandHandler;
import net.qiqbframework.commandhandling.gateway.CommandGateway;
import net.qiqbframework.common.IdentifierFactory;
import net.qiqbframework.config.Configuration;
import net.qiqbframework.config.Configurer;
import net.qiqbframework.config.ConsoleBannerModule;
import net.qiqbframework.config.DefaultConfigurer;
import net.qiqbframework.loadhanding.LoadHandler;
import net.qiqbframework.modelling.command.BizHandler;
import net.qiqbframework.modelling.command.BizIdentifierVoucher;
import net.qiqbframework.modelling.command.Cmd;
import net.qiqbframework.modelling.command.FetchHandler;
import net.qiqbframework.modelling.domain.AggregateContext;
import net.qiqbframework.modelling.domain.AggregateRoot;
import net.qiqbframework.modelling.domain.AggregateRootId;
import net.qiqbframework.modelling.domain.BizIdentifier;
import net.qiqbframework.persisthanding.PersistHandler;
import net.qiqbframework.persisthanding.PersistType;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
@Slf4j(topic = "SimpleBootQiqb")
public class SimpleBootTest {
/**
* 用户聚合根
*/
@AggregateRoot
@Slf4j
static class User implements Serializable {
// 用户聚合根id,唯一且不可修改
@AggregateRootId
private String id;
// 用户名称唯一,全局内不能重复。属于业务id,但是可以修改
@BizIdentifier
private String name;
private int age;
// 邮件,可以修改
private String email;
// 创建(注册)
public User(String name, int age, String email) {
this.id = IdentifierFactory.getInstance().generate();
this.name = name;
this.age = age;
this.email = email;
log.info("create user:{}", this);
}
// 修改邮件
public void changeEmail(String newEmail) {
this.email = newEmail;
}
@CommandHandler
public void changeAge(ChangeAgeCmd changeAgeCmd) {
final int newAge = changeAgeCmd.age;
if (newAge < 1 || newAge > 150) {
throw new IllegalArgumentException("年龄不合法");
}
this.age = newAge;
}
public void remove() {
// 删除一些验证。如果不通过,直接抛出异常
// 标记删除
AggregateContext.markDeleted();
}
@Override
public String toString() {
return "User{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age=" + age +
", email='" + email + '\'' +
'}';
}
}
// 创建用户命令
@Cmd(User.class)
static class CreateUserCmd {
private final String name;
private final int age;
private final String email;
public CreateUserCmd(String name, int age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
@FetchHandler
public User fetch() {
return new User(name, age, email);
}
}
// 修改用户邮件命令
@Cmd(User.class)
static class ChangeEmailCmd {
// 业务id加载凭证
@BizIdentifierVoucher
private final String name;
private final String newEmail;
public ChangeEmailCmd(String name, String newEmail) {
this.name = name;
this.newEmail = newEmail;
}
@BizHandler
public void changeEmail(User user) {
user.changeEmail(newEmail);
}
}
// 修改用户邮件命令
static class ChangeAgeCmd {
// 业务id加载凭证
@BizIdentifierVoucher
private final String name;
private final int age;
public ChangeAgeCmd(String name, int age) {
this.name = name;
this.age = age;
}
}
// 删除用户命令
@Cmd(User.class)
static class RemoveCmd {
// 业务id加载凭证
@BizIdentifierVoucher
private final String name;
public RemoveCmd(String name) {
this.name = name;
}
@BizHandler
public void handle(User cmd) {
cmd.remove();
}
}
// 模拟持久化
static class UserRepository {
// 模拟user 的数据库:{key:id,value:user}
@Getter
private final static Map userCache = new HashMap<>();
// 模拟根据用户名称检索用户。{key:name,value:user}
private final static Map nameUserCache = new HashMap<>();
// 根据业务id加载
@LoadHandler(bizIdentifierName = "id")
public User loadById(String id) {
log.info("load by id:{}", id);
return userCache.get(id);
}
// 根据业务id名称加载
@LoadHandler(bizIdentifierName = "name")
public User loadNyName(String name) {
log.info("load by name:{}", name);
return nameUserCache.get(name);
}
// 新增
@PersistHandler(type = PersistType.ADD)
public void add(User user) {
log.info("add user:{}", user);
userCache.put(user.id, user);
nameUserCache.put(user.name, user);
}
// 修改持久化
@PersistHandler(type = PersistType.MODIFY)
public void modify(User modifiedUser, User snapshotUser) {
log.info("modifiedUser :{},snapshotUser :{}", modifiedUser, snapshotUser);
userCache.put(modifiedUser.id, modifiedUser);
nameUserCache.put(modifiedUser.name, modifiedUser);
}
// 删除持久化
@PersistHandler(type = PersistType.REMOVE)
public void delete(User user) {
log.info("remove user:{}", user);
userCache.remove(user.id);
nameUserCache.remove(user.name);
}
}
public static void main(String[] args) throws Exception {
// 初始环境配置
final UserRepository userPersist = new UserRepository();
Configurer configurer = DefaultConfigurer.defaultConfiguration()
.registerModule(new ConsoleBannerModule());
// 注册聚合根定义
configurer.aggregateConfigurer().registerAggregateRootTypeBuilder(c -> User.class);
// 注册用户加载器
configurer.loadConfigurer().registerLoadHandlerBuilder(c -> userPersist);
// 注册用户持久化
configurer.persistenceConfigurer().registerPersistenceHandlerBuilder(c -> userPersist);
// 注册操作命令类型
configurer.commandConfigurer()
.registerAggregateCommandType(c -> CreateUserCmd.class)
.registerAggregateCommandType(c -> ChangeEmailCmd.class)
//.registerAggregateCommandType(c -> ChangeAgeCmd.class)
.registerAggregateCommandType(c -> RemoveCmd.class);
Configuration configuration = configurer.buildConfiguration();
configuration.start();
// 命令网关,接受一切命令。
final CommandGateway commandGateway = configuration.commandGateway();
// 用户张三唯一ID
String userName = "foo";
// 用户第一次创建
commandGateway.sendAndWait(new CreateUserCmd(userName, 18, "foo@123.com"));
log.info("模拟数据库查询:{}", UserRepository.getUserCache().get(userName));
// 经过一系列的操作。例如:用户修改
commandGateway.sendAndWait(new ChangeEmailCmd(userName, "foo@456.com"));
log.info("模拟数据库查询:{}", UserRepository.getUserCache().get(userName));
commandGateway.sendAndWait(new ChangeAgeCmd(userName, 19));
log.info("模拟数据库查询:{}", UserRepository.getUserCache().get(userName));
// 用户销毁
commandGateway.sendAndWait(new RemoveCmd(userName));
log.info("模拟数据库查询:{}", UserRepository.getUserCache().get(userName));
configuration.shutdown();
}
}
```
运行结果:
```
2025-04-07 21:56:43.892 [main] INFO net.qiqbframework.boot.SimpleBootTest$User - create user:User{id='0452b185-33f3-4a7c-bcb7-9771ed64f2da', name='foo', age=18, email='foo@123.com'}
2025-04-07 21:56:43.905 [main] INFO SimpleBootQiqb - add user:User{id='0452b185-33f3-4a7c-bcb7-9771ed64f2da', name='foo', age=18, email='foo@123.com'}
2025-04-07 21:56:43.906 [main] INFO SimpleBootQiqb - 模拟数据库查询:null
2025-04-07 21:56:43.908 [main] INFO SimpleBootQiqb - load by name:foo
2025-04-07 21:56:43.914 [main] INFO SimpleBootQiqb - modifiedUser :User{id='0452b185-33f3-4a7c-bcb7-9771ed64f2da', name='foo', age=18, email='foo@456.com'},snapshotUser :User{id='0452b185-33f3-4a7c-bcb7-9771ed64f2da', name='foo', age=18, email='foo@123.com'}
2025-04-07 21:56:43.915 [main] INFO SimpleBootQiqb - 模拟数据库查询:null
2025-04-07 21:56:43.915 [main] INFO SimpleBootQiqb - load by name:foo
2025-04-07 21:56:43.917 [main] INFO SimpleBootQiqb - modifiedUser :User{id='0452b185-33f3-4a7c-bcb7-9771ed64f2da', name='foo', age=19, email='foo@456.com'},snapshotUser :User{id='0452b185-33f3-4a7c-bcb7-9771ed64f2da', name='foo', age=18, email='foo@456.com'}
2025-04-07 21:56:43.917 [main] INFO SimpleBootQiqb - 模拟数据库查询:null
2025-04-07 21:56:43.918 [main] INFO SimpleBootQiqb - load by name:foo
2025-04-07 21:56:43.919 [main] INFO SimpleBootQiqb - remove user:User{id='0452b185-33f3-4a7c-bcb7-9771ed64f2da', name='foo', age=19, email='foo@456.com'}
2025-04-07 21:56:43.919 [main] INFO SimpleBootQiqb - 模拟数据库查询:null
```
## spring boot 模式
添加Maven 依赖,无需依赖qiqb-core。
```xml
net.qiqb.framework
qiqb-spring-boot-starter
${qiqbframework.version}
```
> `qiqb-spring-boot-starter`默认会自动依赖`qiqb-core`,无需重复依赖
enjoy fun !!!