From e4a0ab070f6079c96f7c800908f834810b71d602 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E5=A4=A9=E4=BC=9F?= <1571831274@qq.com> Date: Sun, 14 Jul 2024 21:53:07 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AC=94=E8=AE=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...42\350\256\250\346\200\235\350\200\203.md" | 46 +++++ ...62\347\273\231\347\224\250\346\210\267.md" | 100 ++++++++++ ...36\345\200\274\347\273\223\346\236\204.md" | 176 ++++++++++++++++++ ...42\345\222\214\345\260\235\350\257\225.md" | 144 ++++++++++++++ ...15\347\253\257\351\241\265\351\235\242.md" | 31 +++ 5 files changed, 497 insertions(+) create mode 100644 "\351\273\204\345\244\251\344\274\237/20240708_DDD\346\216\242\350\256\250\346\200\235\350\200\203.md" create mode 100644 "\351\273\204\345\244\251\344\274\237/20240709_\345\210\206\351\205\215\350\247\222\350\211\262\347\273\231\347\224\250\346\210\267.md" create mode 100644 "\351\273\204\345\244\251\344\274\237/20240710_\347\273\237\344\270\200\351\242\206\345\237\237\346\234\215\345\212\241\350\277\224\345\233\236\345\200\274\347\273\223\346\236\204.md" create mode 100644 "\351\273\204\345\244\251\344\274\237/20240711_\351\242\206\345\237\237\346\234\215\345\212\241\346\216\245\345\217\243\346\216\242\347\264\242\345\222\214\345\260\235\350\257\225.md" create mode 100644 "\351\273\204\345\244\251\344\274\237/20240712_\346\220\255\345\273\272\345\211\215\347\253\257\351\241\265\351\235\242.md" diff --git "a/\351\273\204\345\244\251\344\274\237/20240708_DDD\346\216\242\350\256\250\346\200\235\350\200\203.md" "b/\351\273\204\345\244\251\344\274\237/20240708_DDD\346\216\242\350\256\250\346\200\235\350\200\203.md" new file mode 100644 index 0000000..198b81a --- /dev/null +++ "b/\351\273\204\345\244\251\344\274\237/20240708_DDD\346\216\242\350\256\250\346\200\235\350\200\203.md" @@ -0,0 +1,46 @@ +## 关于DDD领域驱动设计思想的探讨与思考 + +1. DDD中一些概念 + + - 域 + + - 子域 + + - 聚合 + + - 聚合根 + + - 领域模型 + + - 值对象 + + - 通用仓储接口 (底层 贴近数据) + + - 领域模型仓储接口 + + - 领域服务接口 + + - 应用服务接口 + + - API服务接口 (高层,因为贴近因为) + + - 领域事件 + + - 大脑风暴 + + - 事件风暴 + +领域模型:一些不涉及其它对象(不是指其他类型,是指对象实例)的业务操作,放在领域模型 + +1. 通用仓储接口: 通用的仓储接口,其实现放在基础设施层、单独的一层ORM工具层 + +2. 领域模型仓储接口:领域独有的一些业务,可以写成领域模型接口,其实现放在Domain + +3. 领域服务接口:涉及到多个领域对象的业务和操作,放在领域服务;但是持久化也放在领域服务层 + +4. 应用服务接口:应用服务其实就是对领域模型业务和领域服务业务进行编排的一个层,比较薄 + +5. API服务接口 (高层,因为贴近因为):接受参数,最多做一些数据验证工作 + + + diff --git "a/\351\273\204\345\244\251\344\274\237/20240709_\345\210\206\351\205\215\350\247\222\350\211\262\347\273\231\347\224\250\346\210\267.md" "b/\351\273\204\345\244\251\344\274\237/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 0000000..9e87e04 --- /dev/null +++ "b/\351\273\204\345\244\251\344\274\237/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,100 @@ + +## 分配角色给用户 + +``` +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/\351\273\204\345\244\251\344\274\237/20240710_\347\273\237\344\270\200\351\242\206\345\237\237\346\234\215\345\212\241\350\277\224\345\233\236\345\200\274\347\273\223\346\236\204.md" "b/\351\273\204\345\244\251\344\274\237/20240710_\347\273\237\344\270\200\351\242\206\345\237\237\346\234\215\345\212\241\350\277\224\345\233\236\345\200\274\347\273\223\346\236\204.md" new file mode 100644 index 0000000..8547ba6 --- /dev/null +++ "b/\351\273\204\345\244\251\344\274\237/20240710_\347\273\237\344\270\200\351\242\206\345\237\237\346\234\215\345\212\241\350\277\224\345\233\236\345\200\274\347\273\223\346\236\204.md" @@ -0,0 +1,176 @@ +### 修改各接口及实现,统一领域服务返回值结构 + +``` +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/\351\273\204\345\244\251\344\274\237/20240711_\351\242\206\345\237\237\346\234\215\345\212\241\346\216\245\345\217\243\346\216\242\347\264\242\345\222\214\345\260\235\350\257\225.md" "b/\351\273\204\345\244\251\344\274\237/20240711_\351\242\206\345\237\237\346\234\215\345\212\241\346\216\245\345\217\243\346\216\242\347\264\242\345\222\214\345\260\235\350\257\225.md" new file mode 100644 index 0000000..b5d8ab6 --- /dev/null +++ "b/\351\273\204\345\244\251\344\274\237/20240711_\351\242\206\345\237\237\346\234\215\345\212\241\346\216\245\345\217\243\346\216\242\347\264\242\345\222\214\345\260\235\350\257\225.md" @@ -0,0 +1,144 @@ +## 领域服务接口探索和尝试 + +``` +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/\351\273\204\345\244\251\344\274\237/20240712_\346\220\255\345\273\272\345\211\215\347\253\257\351\241\265\351\235\242.md" "b/\351\273\204\345\244\251\344\274\237/20240712_\346\220\255\345\273\272\345\211\215\347\253\257\351\241\265\351\235\242.md" new file mode 100644 index 0000000..096c041 --- /dev/null +++ "b/\351\273\204\345\244\251\344\274\237/20240712_\346\220\255\345\273\272\345\211\215\347\253\257\351\241\265\351\235\242.md" @@ -0,0 +1,31 @@ +## 搭建前端管理界面 + +main.js +``` +import { createApp } from 'vue' +import App from './App.vue' +// 以下完整引入antdv +import antdv from 'ant-design-vue' +import 'ant-design-vue/dist/reset.css' + +import { createRouter, createWebHistory } from 'vue-router' + +let router = createRouter({ + history: createWebHistory(), + routes: [ + { + path: '/', + component: () => import('./views/test.vue') + }, + { + path: '/about', + component: () => import('./views/about.vue') + } + ] +}) + +let app = createApp(App); + +app.use(router).use(antdv).mount('#app') + +``` \ No newline at end of file -- Gitee