Skip to content

领域模型设计

文档编号:SYS-DES-BA-002
文档版本:1.0
创建日期:2026-03-08
文档作者:架构师
文档状态:✅ 已评审通过
评审记录00-review-records/01-domain-analysis-review-record.md


1. 概述

1.1 文档目的

本文档基于领域边界划分,详细设计System基础平台的领域模型,包括实体、值对象、聚合、领域事件和领域服务,为后续架构设计和开发实现提供详细的业务模型指导。

1.2 输入文档

  • 领域边界划分(SYS-DES-BA-001)
  • System系统业务需求文档(BRD)V1.1

1.3 设计原则

  • 单一职责原则:每个聚合只负责一个业务概念
  • 高内聚低耦合:聚合内部高内聚,聚合之间低耦合
  • 业务一致性:领域模型忠实反映业务规则
  • 可扩展性:支持未来业务扩展

2. 领域模型总览

2.1 领域模型全景图

┌─────────────────────────────────────────────────────────────────────────────┐
│                           System 领域模型全景图                               │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                        用户管理上下文                                 │   │
│  │  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐             │   │
│  │  │   用户聚合   │◄──►│ 用户角色关系 │    │ 用户部门关系 │             │   │
│  │  │  User Agg   │    │   聚合      │    │   聚合      │             │   │
│  │  │             │    │ UserRole    │    │UserDept     │             │   │
│  │  │ - User      │    │             │    │             │             │   │
│  │  │ - UserId    │    │ - UserId    │    │ - UserId    │             │   │
│  │  │ - Username  │    │ - RoleId    │    │ - DeptId    │             │   │
│  │  │ - Password  │    │ - IsPrimary │    │ - IsPrimary │             │   │
│  │  │ - EmployeeNo│    │             │    │             │             │   │
│  │  └─────────────┘    └─────────────┘    └─────────────┘             │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                        权限管理上下文                                 │   │
│  │  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐             │   │
│  │  │   角色聚合   │◄──►│ 角色权限关系 │    │   权限聚合   │             │   │
│  │  │  Role Agg   │    │   聚合      │    │ Permission  │             │   │
│  │  │             │    │RolePerm     │    │   Agg       │             │   │
│  │  │ - Role      │    │             │    │             │             │   │
│  │  │ - RoleId    │    │ - RoleId    │    │ - Permission│             │   │
│  │  │ - RoleCode  │    │ - PermId    │    │ - Resource  │             │   │
│  │  │ - RoleName  │    │             │    │ - Operation │             │   │
│  │  └─────────────┘    └─────────────┘    └─────────────┘             │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                        组织管理上下文                                 │   │
│  │  ┌─────────────┐    ┌─────────────┐                                │   │
│  │  │   部门聚合   │    │   岗位聚合   │                                │   │
│  │  │ Department  │    │  Position   │                                │   │
│  │  │    Agg      │    │    Agg      │                                │   │
│  │  │             │    │             │                                │   │
│  │  │ - Department│    │ - Position  │                                │   │
│  │  │ - DeptId    │    │ - PositionId│                                │   │
│  │  │ - DeptCode  │    │ - Position  │                                │   │
│  │  │ - ParentId  │    │   Code      │                                │   │
│  │  └─────────────┘    └─────────────┘                                │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                        认证授权上下文                                 │   │
│  │  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐             │   │
│  │  │   认证聚合   │    │   授权聚合   │    │   Token聚合  │             │   │
│  │  │    Auth     │    │    Authz    │    │   Token     │             │   │
│  │  │    Agg      │    │    Agg      │    │    Agg      │             │   │
│  │  │             │    │             │    │             │             │   │
│  │  │ - AuthRecord│    │ - AuthzRec  │    │ - Token     │             │   │
│  │  │ - AuthType  │    │ - Resource  │    │ - AccessTok │             │   │
│  │  │ - AuthStatus│    │ - Action    │    │ - RefreshTok│             │   │
│  │  └─────────────┘    └─────────────┘    └─────────────┘             │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                        系统配置上下文                                 │   │
│  │  ┌─────────────┐    ┌─────────────────────────────────────────┐    │   │
│  │  │  配置分组聚合 │    │              配置聚合                    │    │   │
│  │  │ ConfigGroup │    │               Config                     │    │   │
│  │  │    Agg      │    │                Agg                       │    │   │
│  │  │             │    │                                          │    │   │
│  │  │ - GroupId   │    │  - ConfigId    - ConfigKey    - GroupId  │    │   │
│  │  │ - GroupCode │    │  - ConfigValue - ConfigType  - IsEncrypt │    │   │
│  │  │ - GroupName │    │  - web.* / biz.* / sys.*                 │    │   │
│  │  └─────────────┘    └─────────────────────────────────────────┘    │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

3. 用户管理上下文领域模型

3.1 用户聚合(User Aggregate)

3.1.1 聚合根:User(用户)

java
// 伪代码示例
@Entity
@Table(name = "sys_user")
public class User extends BaseAggregateRoot<UserId> {
    
    // 标识
    private UserId userId;
    private Username username;
    
    // 基本信息
    private RealName realName;
    private Email email;
    private Phone phone;
    private Password password;
    
    // 员工关联
    private EmployeeNo employeeNo;      // 员工编号
    private EmployeeStatus employeeStatus;  // 员工状态
    
    // 部门关联
    private DeptId primaryDeptId;       // 主部门ID
    private PositionId positionId;      // 岗位ID
    
    // 状态
    private UserStatus status;          // 用户状态
    private LocalDateTime lastLoginTime; // 最后登录时间
    private String lastLoginIp;         // 最后登录IP
    
    // 审计
    private LocalDateTime createdAt;
    private UserId createdBy;
    private LocalDateTime updatedAt;
    private UserId updatedBy;
    
    // 领域方法
    public void disable() {
        this.status = UserStatus.DISABLED;
        registerEvent(new UserDisabledEvent(this.userId));
    }
    
    public void resetPassword() {
        this.password = Password.generateRandom();
        registerEvent(new PasswordResetEvent(this.userId, this.email));
    }
    
    public void linkEmployee(EmployeeNo employeeNo) {
        this.employeeNo = employeeNo;
        this.employeeStatus = EmployeeStatus.ACTIVE;
        registerEvent(new EmployeeLinkedEvent(this.userId, employeeNo));
    }
    
    public void unlinkEmployee() {
        EmployeeNo oldEmployeeNo = this.employeeNo;
        this.employeeNo = null;
        this.employeeStatus = null;
        registerEvent(new EmployeeUnlinkedEvent(this.userId, oldEmployeeNo));
    }
}

3.1.2 值对象定义

值对象属性校验规则
UserIdvalue: StringUUID格式,系统生成
Usernamevalue: String字母开头,4-20位,允许字母数字下划线,全局唯一
RealNamevalue: String2-20位中文或英文
Emailvalue: String符合邮箱格式,唯一
Phonevalue: String大陆手机号11位,唯一
Passwordvalue: String, salt: Stringbcrypt加密存储,长度60位
EmployeeNovalue: StringHR系统员工编号,唯一
EmployeeStatusvalue: EnumACTIVE(在职), RESIGNED(离职), PROBATION(试用期)
UserStatusvalue: EnumENABLED(启用), DISABLED(禁用), LOCKED(锁定)

3.1.3 领域事件

领域事件触发条件事件属性
UserCreatedEvent用户创建userId, username, email, createdAt
UserUpdatedEvent用户更新userId, updatedFields, updatedAt
UserDisabledEvent用户禁用userId, disabledAt, disabledBy
UserDeletedEvent用户删除userId, deletedAt, deletedBy
PasswordResetEvent密码重置userId, email, resetAt
PasswordChangedEvent密码修改userId, changedAt
EmployeeLinkedEvent关联员工userId, employeeNo, linkedAt
EmployeeUnlinkedEvent解除关联userId, employeeNo, unlinkedAt
UserLoginSuccessEvent登录成功userId, loginTime, loginIp, clientInfo
UserLoginFailedEvent登录失败username, failTime, failIp, failReason

3.2 用户角色关系聚合(UserRole Aggregate)

3.2.1 聚合根:UserRole(用户角色关系)

java
@Entity
@Table(name = "sys_user_role")
public class UserRole extends BaseAggregateRoot<UserRoleId> {
    
    private UserRoleId userRoleId;
    private UserId userId;
    private RoleId roleId;
    private boolean isPrimary;      // 是否主角色
    private LocalDateTime assignedAt;
    private UserId assignedBy;
    
    // 领域方法
    public void setAsPrimary() {
        this.isPrimary = true;
        registerEvent(new PrimaryRoleSetEvent(this.userId, this.roleId));
    }
}

3.2.2 值对象

值对象属性校验规则
UserRoleIdvalue: StringUUID格式
UserIdvalue: String引用用户聚合
RoleIdvalue: String引用角色聚合

3.2.3 领域事件

领域事件触发条件事件属性
RoleAssignedToUserEvent角色分配userId, roleId, assignedAt, assignedBy
RoleRemovedFromUserEvent角色移除userId, roleId, removedAt, removedBy
PrimaryRoleSetEvent设置主角色userId, roleId, setAt

3.3 用户部门关系聚合(UserDepartment Aggregate)

3.3.1 聚合根:UserDepartment(用户部门关系)

java
@Entity
@Table(name = "sys_user_dept")
public class UserDepartment extends BaseAggregateRoot<UserDeptId> {
    
    private UserDeptId userDeptId;
    private UserId userId;
    private DeptId deptId;
    private boolean isPrimary;      // 是否主部门
    private LocalDateTime assignedAt;
    
    // 领域方法
    public void changeToPrimary() {
        this.isPrimary = true;
        registerEvent(new PrimaryDepartmentChangedEvent(this.userId, this.deptId));
    }
}

4. 权限管理上下文领域模型

4.1 角色聚合(Role Aggregate)

4.1.1 聚合根:Role(角色)

java
@Entity
@Table(name = "sys_role")
public class Role extends BaseAggregateRoot<RoleId> {
    
    private RoleId roleId;
    private RoleCode roleCode;        // 角色编码
    private RoleName roleName;        // 角色名称
    private String description;       // 描述
    private RoleStatus status;        // 状态
    private boolean isSystem;         // 是否系统预设
    private DataScope dataScope;      // 数据权限范围
    
    // 审计
    private LocalDateTime createdAt;
    private UserId createdBy;
    private LocalDateTime updatedAt;
    private UserId updatedBy;
    
    // 领域方法
    public void assignPermission(PermissionId permissionId) {
        // 检查权限是否已分配
        // 创建角色权限关系
        registerEvent(new PermissionAssignedToRoleEvent(this.roleId, permissionId));
    }
    
    public void revokePermission(PermissionId permissionId) {
        // 移除角色权限关系
        registerEvent(new PermissionRevokedFromRoleEvent(this.roleId, permissionId));
    }
    
    public void setDataScope(DataScope dataScope) {
        this.dataScope = dataScope;
        registerEvent(new RoleDataScopeChangedEvent(this.roleId, dataScope));
    }
}

4.1.2 值对象

值对象属性校验规则
RoleIdvalue: StringUUID格式
RoleCodevalue: String全局唯一,字母开头,2-50位
RoleNamevalue: String2-50位中文或英文
RoleStatusvalue: EnumENABLED(启用), DISABLED(禁用)
DataScopevalue: EnumALL(全部), DEPT_AND_CHILD(本部门及子部门), DEPT(本部门), SELF(本人)

4.1.3 领域事件

领域事件触发条件事件属性
RoleCreatedEvent角色创建roleId, roleCode, roleName, createdAt
RoleUpdatedEvent角色更新roleId, updatedFields, updatedAt
RoleDeletedEvent角色删除roleId, deletedAt
RoleStatusChangedEvent状态变更roleId, oldStatus, newStatus, changedAt
PermissionAssignedToRoleEvent权限分配roleId, permissionId, assignedAt
PermissionRevokedFromRoleEvent权限撤销roleId, permissionId, revokedAt
RoleDataScopeChangedEvent数据范围变更roleId, oldScope, newScope, changedAt

4.2 权限聚合(Permission Aggregate)

4.2.1 聚合根:Permission(权限)

java
@Entity
@Table(name = "sys_permission")
public class Permission extends BaseAggregateRoot<PermissionId> {
    
    private PermissionId permissionId;
    private ResourceType resourceType;    // 资源类型
    private ResourceId resourceId;        // 资源ID
    private OperationType operation;      // 操作类型
    private String description;
    
    // 领域方法
    public boolean implies(Permission other) {
        // 判断当前权限是否包含其他权限
        return this.resourceId.equals(other.resourceId) &&
               this.operation.implies(other.operation);
    }
}

4.2.2 值对象

值对象属性校验规则
PermissionIdvalue: StringUUID格式
ResourceTypevalue: EnumMENU(菜单), BUTTON(按钮), API(API接口), DATA(数据)
ResourceIdvalue: String资源唯一标识
OperationTypevalue: EnumVIEW(查看), CREATE(创建), UPDATE(更新), DELETE(删除), EXPORT(导出)

4.3 角色权限关系聚合(RolePermission Aggregate)

4.3.1 聚合根:RolePermission(角色权限关系)

java
@Entity
@Table(name = "sys_role_permission")
public class RolePermission extends BaseAggregateRoot<RolePermissionId> {
    
    private RolePermissionId rolePermissionId;
    private RoleId roleId;
    private PermissionId permissionId;
    private LocalDateTime grantedAt;
    private UserId grantedBy;
}

5. 组织管理上下文领域模型

5.1 部门聚合(Department Aggregate)

5.1.1 聚合根:Department(部门)

java
@Entity
@Table(name = "sys_department")
public class Department extends BaseAggregateRoot<DeptId> {
    
    private DeptId deptId;
    private DeptCode deptCode;          // 部门编码
    private DeptName deptName;          // 部门名称
    private DeptId parentId;            // 上级部门ID
    private UserId leaderId;            // 负责人ID
    private String description;
    private int sortOrder;              // 排序号
    private DeptStatus status;          // 状态
    private String treePath;            // 树路径,如:/1/2/5/
    private int treeLevel;              // 树层级
    
    // 审计
    private LocalDateTime createdAt;
    private UserId createdBy;
    private LocalDateTime updatedAt;
    private UserId updatedBy;
    
    // 领域方法
    public void changeParent(DeptId newParentId) {
        // 检查新父部门是否为自己的子部门(避免循环)
        // 更新父部门
        // 重新计算树路径和层级
        this.parentId = newParentId;
        registerEvent(new DepartmentParentChangedEvent(this.deptId, newParentId));
    }
    
    public void setLeader(UserId leaderId) {
        this.leaderId = leaderId;
        registerEvent(new DepartmentLeaderChangedEvent(this.deptId, leaderId));
    }
    
    public void disable() {
        // 检查是否有子部门
        // 检查是否有用户
        this.status = DeptStatus.DISABLED;
        registerEvent(new DepartmentDisabledEvent(this.deptId));
    }
    
    public List<DeptId> getTreePathIds() {
        // 解析treePath获取路径上的所有部门ID
        return Arrays.stream(treePath.split("/"))
                     .filter(s -> !s.isEmpty())
                     .map(DeptId::new)
                     .collect(Collectors.toList());
    }
}

5.1.2 值对象

值对象属性校验规则
DeptIdvalue: StringUUID格式
DeptCodevalue: String全局唯一,2-50位
DeptNamevalue: String2-50位中文或英文
DeptStatusvalue: EnumENABLED(启用), DISABLED(禁用)

5.1.3 领域事件

领域事件触发条件事件属性
DepartmentCreatedEvent部门创建deptId, deptCode, deptName, parentId, createdAt
DepartmentUpdatedEvent部门更新deptId, updatedFields, updatedAt
DepartmentParentChangedEvent父部门变更deptId, oldParentId, newParentId, changedAt
DepartmentLeaderChangedEvent负责人变更deptId, oldLeaderId, newLeaderId, changedAt
DepartmentDisabledEvent部门禁用deptId, disabledAt
DepartmentDeletedEvent部门删除deptId, deletedAt

5.2 岗位聚合(Position Aggregate)

5.2.1 聚合根:Position(岗位)

java
@Entity
@Table(name = "sys_position")
public class Position extends BaseAggregateRoot<PositionId> {
    
    private PositionId positionId;
    private PositionCode positionCode;    // 岗位编码
    private PositionName positionName;    // 岗位名称
    private DeptId deptId;                // 所属部门
    private String description;
    private PositionStatus status;
    
    // 审计
    private LocalDateTime createdAt;
    private UserId createdBy;
}

5.2.2 值对象

值对象属性校验规则
PositionIdvalue: StringUUID格式
PositionCodevalue: String部门内唯一,2-50位
PositionNamevalue: String2-50位中文或英文
PositionStatusvalue: EnumENABLED(启用), DISABLED(禁用)

6. 认证授权上下文领域模型

6.1 认证聚合(Authentication Aggregate)

6.1.1 聚合根:AuthenticationRecord(认证记录)

java
@Entity
@Table(name = "sys_auth_record")
public class AuthenticationRecord extends BaseAggregateRoot<AuthId> {
    
    private AuthId authId;
    private UserId userId;
    private AuthType authType;          // 认证类型
    private AuthStatus authStatus;      // 认证状态
    private LocalDateTime authTime;     // 认证时间
    private String clientInfo;          // 客户端信息(IP、浏览器、OS等)
    private String failReason;          // 失败原因
    
    // 领域方法
    public static AuthenticationRecord success(UserId userId, AuthType type, String clientInfo) {
        AuthenticationRecord record = new AuthenticationRecord();
        record.userId = userId;
        record.authType = type;
        record.authStatus = AuthStatus.SUCCESS;
        record.authTime = LocalDateTime.now();
        record.clientInfo = clientInfo;
        record.registerEvent(new AuthenticationSuccessEvent(userId, type, record.authTime));
        return record;
    }
    
    public static AuthenticationRecord failure(String username, AuthType type, String clientInfo, String failReason) {
        AuthenticationRecord record = new AuthenticationRecord();
        record.authType = type;
        record.authStatus = AuthStatus.FAILED;
        record.authTime = LocalDateTime.now();
        record.clientInfo = clientInfo;
        record.failReason = failReason;
        record.registerEvent(new AuthenticationFailedEvent(username, type, record.authTime, failReason));
        return record;
    }
}

6.1.2 值对象

值对象属性校验规则
AuthIdvalue: StringUUID格式
AuthTypevalue: EnumPASSWORD(密码), SMS(短信), EMAIL(邮箱), OAUTH(OAuth), MFA(多因素)
AuthStatusvalue: EnumSUCCESS(成功), FAILED(失败)

6.2 Token聚合(Token Aggregate)

6.2.1 聚合根:Token(令牌)

java
@Entity
@Table(name = "sys_token")
public class Token extends BaseAggregateRoot<TokenId> {
    
    private TokenId tokenId;
    private UserId userId;
    private AccessToken accessToken;        // 访问令牌
    private RefreshToken refreshToken;      // 刷新令牌
    private LocalDateTime accessTokenExpiresAt;   // Access Token过期时间
    private LocalDateTime refreshTokenExpiresAt;  // Refresh Token过期时间
    private TokenStatus status;             // 令牌状态
    private String clientInfo;
    private LocalDateTime createdAt;
    
    // 领域方法
    public static Token create(UserId userId, String clientInfo) {
        Token token = new Token();
        token.userId = userId;
        token.accessToken = AccessToken.generate();
        token.refreshToken = RefreshToken.generate();
        token.accessTokenExpiresAt = LocalDateTime.now().plusHours(2);
        token.refreshTokenExpiresAt = LocalDateTime.now().plusDays(7);
        token.status = TokenStatus.ACTIVE;
        token.clientInfo = clientInfo;
        token.createdAt = LocalDateTime.now();
        token.registerEvent(new TokenCreatedEvent(userId, token.accessToken, token.createdAt));
        return token;
    }
    
    public Token refresh() {
        // 验证Refresh Token是否过期
        if (LocalDateTime.now().isAfter(refreshTokenExpiresAt)) {
            throw new TokenExpiredException("Refresh token expired");
        }
        
        // 生成新的Token
        this.accessToken = AccessToken.generate();
        this.accessTokenExpiresAt = LocalDateTime.now().plusHours(2);
        registerEvent(new TokenRefreshedEvent(this.userId, this.accessToken, LocalDateTime.now()));
        return this;
    }
    
    public void revoke() {
        this.status = TokenStatus.REVOKED;
        registerEvent(new TokenRevokedEvent(this.userId, this.accessToken, LocalDateTime.now()));
    }
    
    public boolean isExpired() {
        return LocalDateTime.now().isAfter(accessTokenExpiresAt);
    }
}

6.2.2 值对象

值对象属性校验规则
TokenIdvalue: StringUUID格式
AccessTokenvalue: StringJWT格式,包含userId, exp, iat等claims
RefreshTokenvalue: String随机字符串,长度32位
TokenStatusvalue: EnumACTIVE(有效), EXPIRED(过期), REVOKED(撤销)

7. 领域服务设计

7.1 用户管理领域服务

7.1.1 UserDomainService

java
@Service
public class UserDomainService {
    
    @Autowired
    private UserMapper userMapper;  // MyBatis Plus Mapper
    
    @Autowired
    private PasswordEncoder passwordEncoder;
    
    /**
     * 创建用户
     */
    public User createUser(CreateUserCommand command) {
        // 检查用户名唯一性
        if (userMapper.selectCountByUsername(command.getUsername()) > 0) {
            throw new DuplicateUsernameException("Username already exists");
        }
        
        // 检查邮箱唯一性
        if (userMapper.selectCountByEmail(command.getEmail()) > 0) {
            throw new DuplicateEmailException("Email already exists");
        }
        
        // 创建用户
        User user = User.builder()
            .userId(UserId.generate())
            .username(new Username(command.getUsername()))
            .realName(new RealName(command.getRealName()))
            .email(new Email(command.getEmail()))
            .phone(new Phone(command.getPhone()))
            .password(Password.encode(command.getInitialPassword(), passwordEncoder))
            .primaryDeptId(new DeptId(command.getDeptId()))
            .status(UserStatus.ENABLED)
            .build();
        
        userMapper.insert(user);
        return user;
    }
    
    /**
     * 批量导入用户
     */
    public UserImportResult importUsers(List<ImportUserCommand> commands) {
        // 数据校验
        // 批量创建
        // 返回导入结果
    }
    
    /**
     * 同步员工信息
     */
    public void syncEmployeeInfo(UserId userId, EmployeeSyncInfo syncInfo) {
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new UserNotFoundException("User not found");
        }
        
        // 更新员工信息
        user.updateEmployeeInfo(syncInfo);
        userMapper.updateById(user);
    }
}

7.2 权限管理领域服务

7.2.1 PermissionDomainService

java
@Service
public class PermissionDomainService {
    
    @Autowired
    private RoleMapper roleMapper;  // MyBatis Plus Mapper
    
    @Autowired
    private UserMapper userMapper;  // MyBatis Plus Mapper
    
    /**
     * 检查用户是否有权限
     */
    public boolean hasPermission(UserId userId, Permission permission) {
        // 获取用户所有角色
        List<Role> roles = roleMapper.selectByUserId(userId);
        
        // 检查任一角色是否有权限
        return roles.stream()
            .anyMatch(role -> role.hasPermission(permission));
    }
    
    /**
     * 获取用户数据权限范围
     */
    public DataScope getUserDataScope(UserId userId) {
        List<Role> roles = roleMapper.selectByUserId(userId);
        
        // 取最大权限范围
        return roles.stream()
            .map(Role::getDataScope)
            .max(Comparator.comparingInt(DataScope::getPriority))
            .orElse(DataScope.SELF);
    }
    
    /**
     * 分配角色给用户
     */
    public void assignRoleToUser(UserId userId, RoleId roleId, boolean isPrimary) {
        // 创建用户角色关系
        // 如果是主角色,取消其他主角色
        // 发布领域事件
    }
}

7.3 认证授权领域服务

7.3.1 AuthenticationDomainService

java
@Service
public class AuthenticationDomainService {
    
    @Autowired
    private UserMapper userMapper;  // MyBatis Plus Mapper
    
    @Autowired
    private TokenMapper tokenMapper;  // MyBatis Plus Mapper
    
    @Autowired
    private PasswordEncoder passwordEncoder;
    
    @Autowired
    private LoginAttemptCache loginAttemptCache;
    
    /**
     * 用户登录
     */
    public Token authenticate(LoginCommand command) {
        // 检查登录失败次数
        if (loginAttemptCache.isLocked(command.getUsername())) {
            throw new AccountLockedException("Account locked due to too many failed attempts");
        }
        
        // 查找用户
        User user = userMapper.selectByUsername(command.getUsername());
        if (user == null) {
            throw new UserNotFoundException("User not found");
        }
        
        // 检查用户状态
        if (user.getStatus() != UserStatus.ENABLED) {
            throw new AccountDisabledException("Account disabled");
        }
        
        // 验证密码
        if (!passwordEncoder.matches(command.getPassword(), user.getPassword().getValue())) {
            loginAttemptCache.recordFailedAttempt(command.getUsername());
            AuthenticationRecord.failure(command.getUsername(), AuthType.PASSWORD, 
                command.getClientInfo(), "Invalid password");
            throw new InvalidPasswordException("Invalid password");
        }
        
        // 清除登录失败记录
        loginAttemptCache.clearAttempts(command.getUsername());
        
        // 记录认证成功
        AuthenticationRecord.success(user.getUserId(), AuthType.PASSWORD, command.getClientInfo());
        
        // 创建Token
        Token token = Token.create(user.getUserId(), command.getClientInfo());
        tokenMapper.insert(token);
        
        return token;
    }
    
    /**
     * 刷新Token
     */
    public Token refreshToken(String refreshToken) {
        Token token = tokenMapper.selectByRefreshToken(refreshToken);
        if (token == null) {
            throw new TokenNotFoundException("Token not found");
        }
        
        token.refresh();
        tokenMapper.updateById(token);
        
        return token;
    }
    
    /**
     * 撤销Token
     */
    public void revokeToken(String accessToken) {
        Token token = tokenMapper.selectByAccessToken(accessToken);
        if (token == null) {
            throw new TokenNotFoundException("Token not found");
        }
        
        token.revoke();
        tokenMapper.updateById(token);
    }
}

7. 系统配置上下文领域模型

7.1 配置聚合(Config Aggregate)

7.1.1 聚合根:Config(配置)

java
@Entity
@Table(name = "sys_config")
public class Config extends BaseAggregateRoot<ConfigId> {
    
    private ConfigId configId;
    private ConfigKey configKey;          // 配置键
    private ConfigValue configValue;      // 配置值
    private ConfigType configType;        // 配置类型
    private String description;           // 描述
    private boolean isEncrypted;          // 是否加密
    private GroupId groupId;              // 分组ID
    private int sortOrder;                // 排序号
    private boolean isSystem;             // 是否系统预设
    
    // 审计
    private LocalDateTime createdAt;
    private UserId createdBy;
    private LocalDateTime updatedAt;
    private UserId updatedBy;
    
    // 领域方法
    public void updateValue(ConfigValue newValue) {
        // 校验值类型
        validateValueType(newValue);
        
        // 如需要加密则加密存储
        if (this.isEncrypted) {
            newValue = encryptValue(newValue);
        }
        
        this.configValue = newValue;
        this.updatedAt = LocalDateTime.now();
        registerEvent(new ConfigUpdatedEvent(this.configId, this.configKey, newValue));
    }
    
    public ConfigValue getDecryptedValue() {
        if (this.isEncrypted) {
            return decryptValue(this.configValue);
        }
        return this.configValue;
    }
    
    private void validateValueType(ConfigValue value) {
        switch (this.configType) {
            case NUMBER:
                // 验证是否为数字
                break;
            case BOOLEAN:
                // 验证是否为布尔值
                break;
            case JSON:
                // 验证是否为有效JSON
                break;
            default:
                // STRING类型无需验证
        }
    }
}

7.1.2 值对象

值对象属性校验规则
ConfigIdvalue: StringUUID格式
ConfigKeyvalue: String全局唯一,格式:category.subcategory.name,如web.system.name
ConfigValuevalue: String根据configType进行格式校验
ConfigTypevalue: EnumSTRING(字符串), NUMBER(数字), BOOLEAN(布尔), JSON(JSON对象)
GroupIdvalue: String引用配置分组

7.1.3 配置键命名规范

配置键格式:{category}.{subcategory}.{name}

分类说明:
├── web.*          # Web端展示配置
│   ├── web.system.*    # 系统基本信息
│   ├── web.login.*     # 登录页配置
│   ├── web.footer.*    # 页脚配置
│   ├── web.theme.*     # 主题配置
│   ├── web.locale.*    # 国际化配置
│   └── web.watermark.* # 水印配置

├── biz.*          # 商务信息配置
│   ├── biz.company.*   # 企业信息
│   ├── biz.legal.*     # 法人信息
│   ├── biz.address.*   # 地址信息
│   ├── biz.contact.*   # 联系信息
│   ├── biz.bank.*      # 银行信息
│   ├── biz.contract.*  # 合同配置
│   └── biz.invoice.*   # 发票信息

└── sys.*          # 系统参数配置
    ├── sys.security.*  # 安全配置
    ├── sys.upload.*    # 上传配置
    ├── sys.backup.*    # 备份配置
    └── sys.log.*       # 日志配置

7.1.4 领域事件

领域事件触发条件事件属性
ConfigCreatedEvent配置创建configId, configKey, configType, createdAt
ConfigUpdatedEvent配置更新configId, configKey, oldValue, newValue, updatedAt
ConfigDeletedEvent配置删除configId, configKey, deletedAt
ConfigCacheRefreshedEvent配置缓存刷新configKey, refreshedAt

7.2 配置分组聚合(ConfigGroup Aggregate)

7.2.1 聚合根:ConfigGroup(配置分组)

java
@Entity
@Table(name = "sys_config_group")
public class ConfigGroup extends BaseAggregateRoot<GroupId> {
    
    private GroupId groupId;
    private GroupCode groupCode;      // 分组编码
    private GroupName groupName;      // 分组名称
    private String description;       // 描述
    private String icon;              // 分组图标
    private int sortOrder;            // 排序号
    
    // 审计
    private LocalDateTime createdAt;
    private UserId createdBy;
}

7.2.2 值对象

值对象属性校验规则
GroupIdvalue: StringUUID格式
GroupCodevalue: String全局唯一,如:web、biz、sys
GroupNamevalue: String2-50位中文或英文

7.3 系统配置领域服务

7.3.1 ConfigDomainService

java
@Service
public class ConfigDomainService {
    
    @Autowired
    private ConfigMapper configMapper;  // MyBatis Plus Mapper
    
    @Autowired
    private ConfigGroupMapper configGroupMapper;
    
    @Autowired
    private ConfigCacheManager cacheManager;
    
    /**
     * 获取配置值
     */
    public ConfigValue getConfigValue(ConfigKey key) {
        // 先从缓存获取
        ConfigValue cached = cacheManager.get(key);
        if (cached != null) {
            return cached;
        }
        
        // 从数据库获取
        Config config = configMapper.selectByKey(key);
        if (config == null) {
            throw new ConfigNotFoundException("Config not found: " + key);
        }
        
        ConfigValue value = config.getDecryptedValue();
        
        // 放入缓存
        cacheManager.put(key, value);
        
        return value;
    }
    
    /**
     * 获取Web配置(按分组)
     */
    public Map<String, ConfigValue> getWebConfigs() {
        List<Config> configs = configMapper.selectByGroupPrefix("web");
        return configs.stream()
            .collect(Collectors.toMap(
                c -> c.getConfigKey().getValue(),
                Config::getDecryptedValue
            ));
    }
    
    /**
     * 获取商务配置
     */
    public BusinessConfigDTO getBusinessConfig() {
        List<Config> configs = configMapper.selectByGroupPrefix("biz");
        
        BusinessConfigDTO dto = new BusinessConfigDTO();
        configs.forEach(config -> {
            String key = config.getConfigKey().getValue();
            ConfigValue value = config.getDecryptedValue();
            
            switch (key) {
                case "biz.company.name":
                    dto.setCompanyName(value.getValue());
                    break;
                case "biz.company.creditCode":
                    dto.setCreditCode(value.getValue());
                    break;
                case "biz.legal.representative":
                    dto.setLegalRepresentative(value.getValue());
                    break;
                // ... 其他字段映射
            }
        });
        
        return dto;
    }
    
    /**
     * 批量更新配置
     */
    @Transactional
    public void batchUpdateConfigs(Map<ConfigKey, ConfigValue> configMap, UserId operator) {
        configMap.forEach((key, value) -> {
            Config config = configMapper.selectByKey(key);
            if (config != null) {
                config.updateValue(value);
                config.setUpdatedBy(operator);
                config.setUpdatedAt(LocalDateTime.now());
                configMapper.updateById(config);
            }
        });
        
        // 刷新缓存
        cacheManager.refreshBatch(configMap.keySet());
    }
    
    /**
     * 初始化系统默认配置
     */
    @Transactional
    public void initDefaultConfigs() {
        // Web端默认配置
        createConfigIfNotExists("web.system.name", "System基础平台", ConfigType.STRING, "web");
        createConfigIfNotExists("web.login.title", "欢迎登录", ConfigType.STRING, "web");
        createConfigIfNotExists("web.theme.primaryColor", "#1890ff", ConfigType.STRING, "web");
        createConfigIfNotExists("web.locale.default", "zh-CN", ConfigType.STRING, "web");
        
        // 系统安全默认配置
        createConfigIfNotExists("sys.security.passwordExpireDays", "90", ConfigType.NUMBER, "sys");
        createConfigIfNotExists("sys.security.maxLoginAttempts", "5", ConfigType.NUMBER, "sys");
        createConfigIfNotExists("sys.security.lockDuration", "30", ConfigType.NUMBER, "sys");
        createConfigIfNotExists("sys.security.sessionTimeout", "30", ConfigType.NUMBER, "sys");
        createConfigIfNotExists("sys.security.tokenExpireHours", "2", ConfigType.NUMBER, "sys");
    }
    
    private void createConfigIfNotExists(String key, String value, ConfigType type, String groupCode) {
        if (configMapper.selectByKey(new ConfigKey(key)) == null) {
            ConfigGroup group = configGroupMapper.selectByCode(groupCode);
            
            Config config = Config.builder()
                .configId(ConfigId.generate())
                .configKey(new ConfigKey(key))
                .configValue(new ConfigValue(value))
                .configType(type)
                .groupId(group != null ? group.getGroupId() : null)
                .isSystem(true)
                .build();
            
            configMapper.insert(config);
        }
    }
}

8. 领域事件处理

8.1 事件发布与订阅

java
// 事件发布
public class DomainEventPublisher {
    
    @Autowired
    private ApplicationEventPublisher publisher;
    
    public void publish(DomainEvent event) {
        publisher.publishEvent(event);
    }
}

// 事件订阅示例
@Component
public class UserEventHandler {
    
    @Autowired
    private TokenMapper tokenMapper;  // MyBatis Plus Mapper
    
    @Autowired
    private AuditLogService auditLogService;
    
    /**
     * 用户禁用事件处理
     */
    @EventListener
    public void onUserDisabled(UserDisabledEvent event) {
        // 撤销该用户的所有Token
        List<Token> tokens = tokenMapper.selectByUserIdAndStatus(event.getUserId(), TokenStatus.ACTIVE);
        tokens.forEach(Token::revoke);
        tokens.forEach(tokenMapper::updateById);
        
        // 记录审计日志
        auditLogService.logOperation("USER_DISABLED", event.getUserId(), null, null);
    }
    
    /**
     * 员工关联事件处理
     */
    @EventListener
    public void onEmployeeLinked(EmployeeLinkedEvent event) {
        // 同步员工信息
        // 发送通知
    }
}

9. 附录

9.1 实体关系图(ER图)

┌─────────────────────────────────────────────────────────────────────────────┐
│                            实体关系图(简化版)                               │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌──────────────┐         ┌──────────────┐         ┌──────────────┐        │
│  │    User      │1       *│  UserRole    │*       1│     Role     │        │
│  │    用户      │────────►│  用户角色关系 │◄────────│     角色     │        │
│  │              │         │              │         │              │        │
│  │  PK: user_id │         │  PK: id      │         │  PK: role_id │        │
│  │  FK: dept_id │         │  FK: user_id │         │  FK: data_   │        │
│  │  FK: emp_no  │         │  FK: role_id │         │      scope   │        │
│  └──────┬───────┘         └──────────────┘         └──────┬───────┘        │
│         │                                                 │                │
│         │1                                               *│                │
│         │                                                 │                │
│         ▼                                                 ▼                │
│  ┌──────────────┐         ┌──────────────┐         ┌──────────────┐        │
│  │ Department   │1       *│  UserDept    │*       1│RolePermission│        │
│  │    部门      │◄────────│  用户部门关系 │────────►│  角色权限关系 │        │
│  │              │         │              │         │              │        │
│  │  PK: dept_id │         │  PK: id      │         │  PK: id      │        │
│  │  FK: parent  │         │  FK: user_id │         │  FK: role_id │        │
│  └──────────────┘         │  FK: dept_id │         │  FK: perm_id │        │
│                           └──────────────┘         └──────┬───────┘        │
│                                                           │                │
│                                                           *                │
│                                                           │                │
│                                                           ▼                │
│                                                  ┌──────────────┐          │
│                                                  │  Permission  │          │
│                                                  │    权限      │          │
│                                                  │              │          │
│                                                  │  PK: perm_id │          │
│                                                  └──────────────┘          │
│                                                                             │
│  ┌──────────────┐         ┌──────────────┐                                  │
│  │    Token     │*       1│    User      │                                  │
│  │    令牌      │◄────────│    用户      │                                  │
│  │              │         │              │                                  │
│  │  PK: token_id│         │              │                                  │
│  │  FK: user_id │         │              │                                  │
│  └──────────────┘         └──────────────┘                                  │
│                                                                             │
│  ┌──────────────┐         ┌──────────────┐                                  │
│  │ ConfigGroup  │1       *│    Config    │                                  │
│  │  配置分组    │◄────────│    配置      │                                  │
│  │              │         │              │                                  │
│  │  PK: group_id│         │  PK: config  │                                  │
│  │  group_code  │         │  FK: group_id│                                  │
│  │  group_name  │         │  config_key  │                                  │
│  └──────────────┘         │  config_value│                                  │
│                           └──────────────┘                                  │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

9.2 修订记录

版本日期修订人修订内容
1.02026-03-08架构师初始版本

文档编制:架构师
文档审核:技术负责人
编制日期:2026-03-08

Released under the MIT License.