# 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 !!!