diff --git "a/\346\235\250\345\217\257\347\233\210/20240708.DDD.md" "b/\346\235\250\345\217\257\347\233\210/20240708.DDD.md" new file mode 100644 index 0000000000000000000000000000000000000000..5e965e5f1864d05c7c8d6a28c3681c19112837cc --- /dev/null +++ "b/\346\235\250\345\217\257\347\233\210/20240708.DDD.md" @@ -0,0 +1,17 @@ +## 关于DDD领域驱动设计思想的探讨与思考 +- 域 +- 子域 +- 聚合 +- 聚合根 +- 领域模型 +- 值对象 +- 领域模型 一些不涉及其他实体的业务操作,放在领域模型 +- 通用仓储接口(底层 贴近数据) --Domain/Interfaces 其实现放在基础设施层、单独的一层ORM工具层 +- 领域模型仓储接口 --Domain 领域独有的一些业务,可以写成领域模型接口,其实现放在Domain层 +- 领域服务接口 --Domain 涉及到多个领域实体的业务和操作,放在领域服务 持久化也放在领域服务 +- 应用服务接口 --Application Application/Contract 其实就是对领域模型业务和领域服务业务进行编排的一个层 比较薄 +- API服务接口(高层 贴近用户) 接收参数 最多做一些数据验证工作 +- 领域事件 +- 头脑风暴 +- 事件风暴 + diff --git "a/\346\235\250\345\217\257\347\233\210/20240709--\345\210\206\351\205\215\350\247\222\350\211\262\347\273\231\347\224\250\346\210\267.md" "b/\346\235\250\345\217\257\347\233\210/20240709--\345\210\206\351\205\215\350\247\222\350\211\262\347\273\231\347\224\250\346\210\267.md" new file mode 100644 index 0000000000000000000000000000000000000000..a30ffee7bece286d1a1dce5bd4db70c5724d4c1a --- /dev/null +++ "b/\346\235\250\345\217\257\347\233\210/20240709--\345\210\206\351\205\215\350\247\222\350\211\262\347\273\231\347\224\250\346\210\267.md" @@ -0,0 +1,98 @@ +#### 分配角色给用户 +``` +using Admin2024.Domain.Entity.System; +using Admin2024.Domain.Interface; + +namespace Admin2024.Domain.DomainService; + +public class AppUserDomainService : IAppUserDomainService +{ + private readonly IRepository _appUserRepository; + private readonly IRepository _appRoleRepository; + private readonly IRepository _appUserRoleRepository; + + public AppUserDomainService(IRepository appUserRepository, + IRepository appUserRoleRepository, IRepository appRoleRepository) + { + _appUserRepository = appUserRepository; + _appRoleRepository = appRoleRepository; + _appUserRoleRepository = appUserRoleRepository; + } + + // 给用户分配角色 + public async Task AssigmRole(Guid appUserId, Guid appRoleId) + { + // 1.需要对id对应的实例存在不存在做验证 + // 2.如果都存在,需要对id对应的领域对象做进一步验证,如状态验证和业务验证 + var user = await _appUserRepository.GetByIdAsync(appUserId); + var role = await _appRoleRepository.GetByIdAsync(appRoleId); + // id对应的用户和角色都存在的情况下 + if (user != null && role != null) + { + // 业务要求:用户没有被删除,也没有被禁用 + // 业务要求:角色没有被删除,也没有被禁用 + if (user.IsDeleted != true && user.IsActived == true + && role.IsDeleted != true && role.IsActived == true) + { + var userRole = new AppUserRole { AppUserId = appUserId, AppRoleId = appRoleId }; + var res = await _appUserRoleRepository.CreateAsync(userRole); + return res; + } + + return null; + } + + return null; + + } + + public async Task Create(string username, string password, string confirmPassword) + { + // 先用用户名去查找数据库有无相当用户名的记录,如果找到,说明用户名重复了 + var user = _appUserRepository.Table.FirstOrDefault(x => x.Username == username); + + if (user == null && password == confirmPassword) + { + var appUser = await _appUserRepository.CreateAsync(new AppUser + { + Username = username, + Password = password, + Salt = "可盐可甜" + }); + return appUser; + } + return null; + } + + public void HasPemission(AppPermission appPermission) + { + throw new NotImplementedException(); + } + + public string? Login(string username, string password) + { + var user = _appUserRepository.Table.FirstOrDefault(x => x.Username == username); + + if (user != null && user.Password == password) + { + return "我是token"; + } + + return null; + } + + // 修改密码,修改密码的大部分操作在领域类型中完成的,如,md5加密,或者base64加密 + // 领域服务中,仅仅只是完成持久化 + public async void ModifyPassword(Guid id, string password) + { + var user = await _appUserRepository.GetByIdAsync(id); + if (user != null) + { + // 真正修改密码,其实是在领域模型中完成 + user.ModifyPassword(password); + await _appUserRepository.UpdateAsync(id, user); + } + + } +} +``` \ No newline at end of file diff --git "a/\346\235\250\345\217\257\347\233\210/20240710--\344\277\256\346\224\271\345\220\204\346\216\245\345\217\243\345\256\236\347\216\260.md.md" "b/\346\235\250\345\217\257\347\233\210/20240710--\344\277\256\346\224\271\345\220\204\346\216\245\345\217\243\345\256\236\347\216\260.md.md" new file mode 100644 index 0000000000000000000000000000000000000000..c2d7ba1b6bb672dfa513f380aa5d91b71f6f6be1 --- /dev/null +++ "b/\346\235\250\345\217\257\347\233\210/20240710--\344\277\256\346\224\271\345\220\204\346\216\245\345\217\243\345\256\236\347\216\260.md.md" @@ -0,0 +1,166 @@ +### 修改各接口及实现,统一领域服务返回值结构 +``` +using Admin2024.Domain.Entity.System; +using Admin2024.Domain.Interface; +using Admin2024.Domain.ObjectValue; + +namespace Admin2024.Domain.DomainService; + +public class AppUserDomainService : IAppUserDomainService +{ + private readonly IRepository _appUserRepository; + private readonly IRepository _appRoleRepository; + private readonly IRepository _appUserRoleRepository; + + public AppUserDomainService(IRepository appUserRepository, + IRepository appUserRoleRepository, IRepository appRoleRepository) + { + _appUserRepository = appUserRepository; + _appRoleRepository = appRoleRepository; + _appUserRoleRepository = appUserRoleRepository; + } + + // 给用户分配角色 + public async Task AssigmRole(Guid appUserId, Guid appRoleId) + { + // 1.需要对id对应的实例存在不存在做验证 + // 2.如果都存在,需要对id对应的领域对象做进一步验证,如状态验证和业务验证 + var user = await _appUserRepository.GetByIdAsync(appUserId); + var role = await _appRoleRepository.GetByIdAsync(appRoleId); + // id对应的用户和角色都存在的情况下 + if (user != null && role != null) + { + // 业务要求:用户没有被删除,也没有被禁用 + // 业务要求:角色没有被删除,也没有被禁用 + if (user.IsDeleted != true && user.IsActived == true + && role.IsDeleted != true && role.IsActived == true) + { + var userRole = new AppUserRole { AppUserId = appUserId, AppRoleId = appRoleId }; + var res = await _appUserRoleRepository.CreateAsync(userRole); + return res; + } + + return null; + } + + return null; + + } + + public async Task> Create(string username, string password, string confirmPassword) + { + // 去除前后空格 + username = username.Trim(); + password = password.Trim(); + confirmPassword = confirmPassword.Trim(); + + // 先用用户名去查找数据库有无相当用户名的记录,如果找到,说明用户名重复了 + var user = _appUserRepository.Table.FirstOrDefault(x => x.Username == username); + + // 如果有找到同步用户,则直接返回消息 + + if (user != null) + { + return DomainResult.Error("用户名重复"); + } + + // 判断用户名长度和密码是否符合要求 用户名>=5 <=30 密码>=6 <=18 + if (!(username.Length >= 5 && username.Length <= 30)) + { + return DomainResult.Error("用户名长度不符合规范,请确认后重试"); + } + + if (!(password.Length >= 5 && password.Length < 18)) + { + return DomainResult.Error("密码长度不符合规范,请确认后重试"); + } + // 两次密码不一致 + if (password != confirmPassword) + { + return DomainResult.Error("两次密码输入不一致,请确认后重试"); + } + + // 所有要求都符合,开始创建用户 + var appUser = new AppUser {Username=username,Password=password,Salt="随机字符" }; + var x = await _appUserRepository.CreateAsync(appUser); + + return DomainResult.Success(x); + } + + public void HasPemission(AppPermission appPermission) + { + throw new NotImplementedException(); + } + + public DomainResult Login(string username, string password) + { + // 通用用户名先查找有没有对应用户 + var user = _appUserRepository.Table.FirstOrDefault(x => x.Username == username); + + if (user == null) + { + return DomainResult.Error("用户名或密码不正确,请稍后重试"); + } + + if (user.IsDeleted) + { + return DomainResult.Error("用户已经被删除,请确认后重试"); + } + + if (!user.IsActived) + { + return DomainResult.Error("用户已经被禁用/封号,请确认后重试"); + } + + if (user.Password != password) + { + return DomainResult.Error("用户名或密码不正确,请稍后重试"); + } + + return DomainResult.Success(user); + } + + // 修改密码,修改密码的大部分操作在领域类型中完成的,如,md5加密,或者base64加密 + // 领域服务中,仅仅只是完成持久化 + public async void ModifyPassword(Guid id, string password) + { + var user = await _appUserRepository.GetByIdAsync(id); + if (user != null) + { + // 真正修改密码,其实是在领域模型中完成 + user.ModifyPassword(password); + await _appUserRepository.UpdateAsync(id, user); + } + + } +} +``` + +``` +namespace Admin2024.Domain.ObjectValue; + +public class DomainResult +{ + public bool IsSuccess { get; protected set; } + public T Data { get; protected set; } + public string ErrorMessage { get; protected set; } + + public DomainResult(bool isSuccess, T data, string errorMessage) + { + IsSuccess = isSuccess; + Data = data; + ErrorMessage = errorMessage; + } + + public static DomainResult Success(T data) + { + return new DomainResult(true, data, "成功"); + } + public static DomainResult Error(string errorMessage) + { +#pragma warning disable CS8604 // 引用类型参数可能为 null。 + return new DomainResult(false, default, errorMessage); +#pragma warning restore CS8604 // 引用类型参数可能为 null。 + } +} +``` \ No newline at end of file diff --git "a/\346\235\250\345\217\257\347\233\210/20240711--\351\242\206\345\237\237\346\234\215\345\212\241\346\216\245\345\217\243.md" "b/\346\235\250\345\217\257\347\233\210/20240711--\351\242\206\345\237\237\346\234\215\345\212\241\346\216\245\345\217\243.md" new file mode 100644 index 0000000000000000000000000000000000000000..69604fe5c33935895fa8a6176d5bb13791f1c301 --- /dev/null +++ "b/\346\235\250\345\217\257\347\233\210/20240711--\351\242\206\345\237\237\346\234\215\345\212\241\346\216\245\345\217\243.md" @@ -0,0 +1,132 @@ +### 领域服务接口探索和尝试 +``` +using Admin2024.Domain.Entity.System; +using Admin2024.Domain.ObjectValue; + +namespace Admin2024.Domain.DomainService.System; + +// 资源访问控制服务 +public interface IResourceAccessControlService +{ + Task> CanAccessResource(Guid appUserId, Guid appResourceId); + +} +``` + +``` +using Admin2024.Domain.Entity.System; +using Admin2024.Domain.ObjectValue; + +namespace Admin2024.Domain.DomainService.System; + +// 用户认证服务接口 +public interface IAuthenticationService +{ + Task> Authenticate(string username, string password); + + Task> RefreshToken(string token); +} +``` + +``` +using Admin2024.Domain.Entity.System; +using Admin2024.Domain.ObjectValue; + +namespace Admin2024.Domain.DomainService.System; + +// 用户认证服务接口 +public interface IAuthenticationService +{ + Task> Authenticate(string username, string password); + + Task> RefreshToken(string token); +} +``` + +``` +using Admin2024.Domain.Entity.System; +using Admin2024.Domain.ObjectValue; + +namespace Admin2024.Domain.DomainService.System; + +// 用户认证服务接口 +public interface IAuthorizationService +{ + Task> HasRole(Guid appUserId, string roleName); + + Task> HasPermission(Guid appUserId,string permission); +} +``` + +``` +using Admin2024.Domain.Entity.System; +using Admin2024.Domain.ObjectValue; + +namespace Admin2024.Domain.DomainService.System; + +public interface IPasswordManagementService +{ + Task> ChangePassword(Guid appUserId, string password); + + Task> ResetPassword(Guid appUserId,string newPassword); +} +``` + +``` +using Admin2024.Domain.Entity.System; +using Admin2024.Domain.ObjectValue; + +namespace Admin2024.Domain.DomainService.System; + +public interface IPermissionManagementService +{ + Task> CreatePermission(Guid username, string password); + + Task> DeletePermission(string token); +} +``` + +``` +using Admin2024.Domain.Entity.System; +using Admin2024.Domain.ObjectValue; + +namespace Admin2024.Domain.DomainService.System; + +// 角色管理服务接口 +public interface IRoleManagementService +{ + Task> CreateRole(string roleName); + + Task> DeleteRole(string token); + Task> UpdateRoleName(Guid appRoleId, string roleName); + Task> AssignPermissionToRole(Guid appRoleId, Guid appPermissionId); + Task> RemovePermissionFromRole(Guid appRoleId, Guid appPermissionId); +} +``` + +``` +using Admin2024.Domain.Entity.System; +using Admin2024.Domain.ObjectValue; + +namespace Admin2024.Domain.DomainService.System; + +public interface IUserInformationManagementService +{ + Task> UpdateUserInfo(Guid appUserId, string password); + +} +``` + +``` +using Admin2024.Domain.Entity.System; +using Admin2024.Domain.ObjectValue; + +namespace Admin2024.Domain.DomainService.System; + +public interface IUserRoleManagementService +{ + Task> AssignRoleToUser(Guid appUserId, Guid appRoleId); + + Task> RemoveRoleFromUser(Guid appUserId, Guid appRoleId); +} +``` \ No newline at end of file diff --git "a/\346\235\250\345\217\257\347\233\210/20240712.md" "b/\346\235\250\345\217\257\347\233\210/20240712.md" new file mode 100644 index 0000000000000000000000000000000000000000..42ec30c24c71de7c428b341f2818471eeacf72bd --- /dev/null +++ "b/\346\235\250\345\217\257\347\233\210/20240712.md" @@ -0,0 +1,66 @@ +### 搭建前端管理界面 +## 一、引入 ant-design-vue +### 1.新建项目 +### 2.使用组件 +#### 1. 安装 +~~~js +npm i --save ant-design-vue@4.x +~~~ +#### 2. 注册 +1. 全局完整注册 +~~~js + import { createApp } from 'vue'; + import App from './App'; + // 以下完整引入antdv + import Antd from 'ant-design-vue'; + import 'ant-design-vue/dist/reset.css'; + + let app = createApp(App); + + app.use(Antd).mount('#app'); + // 样式文件需要单独引入 +~~~ +2. 全局部分注册 +~~~js + import { createApp } from 'vue'; + import { Button, message } from 'ant-design-vue'; + import App from './App'; + + let app = createApp(App); + + /* 会自动注册 Button 下的子组件, 例如 Button.Group */ + app.use(Button).mount('#app'); + + app.config.globalProperties.$message = message; +~~~ +3. 局部组件 +需要分别注册组件子组件,如 Button、ButtonGroup,并且注册后仅在当前组件中有效 +~~~js + // 选项式写法 + + + // 组合式写法 + + + +~~~ + +## 二、按需加载 +ant-design-vue 默认支持基于 ES modules 的 tree shaking,直接引入 import { Button } from 'ant-design-vue'; 就会有按需加载的效果 \ No newline at end of file