diff --git a/Yi.Abp.Net8/Yi.Abp.sln b/Yi.Abp.Net8/Yi.Abp.sln index dd4a26a7..fef906fa 100644 --- a/Yi.Abp.Net8/Yi.Abp.sln +++ b/Yi.Abp.Net8/Yi.Abp.sln @@ -154,6 +154,18 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tool", "tool", "{084CBEEC-5 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Abp.Tool", "tool\Yi.Abp.Tool\Yi.Abp.Tool.csproj", "{4FEBBDD9-E4F4-4BAF-8599-E2D57C08A74F}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Abp.Tool.Web", "tool\Yi.Abp.Tool.Web\Yi.Abp.Tool.Web.csproj", "{2CE51D4C-1EF9-462B-BA14-7EA01A7E4AF1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Abp.Tool.Application", "tool\Yi.Abp.Tool.Application\Yi.Abp.Tool.Application.csproj", "{776590BA-B900-4C8B-986A-5B721FA4B306}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Abp.Tool.Application.Contracts", "tool\Yi.Abp.Tool.Application.Contracts\Yi.Abp.Tool.Application.Contracts.csproj", "{3A3AF1ED-FC7F-48CF-8ACE-9D50426B4675}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Abp.Tool.Domain", "tool\Yi.Abp.Tool.Domain\Yi.Abp.Tool.Domain.csproj", "{68F73B7B-0F8A-41C1-8092-6D6FFAED32F8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Abp.Tool.Domain.Shared", "tool\Yi.Abp.Tool.Domain.Shared\Yi.Abp.Tool.Domain.Shared.csproj", "{4AE84CDE-2A47-4D68-8E93-86193F72E4E8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Abp.Tool.HttpApi.Client", "tool\Yi.Abp.Tool.HttpApi.Client\Yi.Abp.Tool.HttpApi.Client.csproj", "{C8F97775-D903-4365-A4FF-3DA97E318CD2}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -384,6 +396,30 @@ Global {4FEBBDD9-E4F4-4BAF-8599-E2D57C08A74F}.Debug|Any CPU.Build.0 = Debug|Any CPU {4FEBBDD9-E4F4-4BAF-8599-E2D57C08A74F}.Release|Any CPU.ActiveCfg = Release|Any CPU {4FEBBDD9-E4F4-4BAF-8599-E2D57C08A74F}.Release|Any CPU.Build.0 = Release|Any CPU + {2CE51D4C-1EF9-462B-BA14-7EA01A7E4AF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2CE51D4C-1EF9-462B-BA14-7EA01A7E4AF1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2CE51D4C-1EF9-462B-BA14-7EA01A7E4AF1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2CE51D4C-1EF9-462B-BA14-7EA01A7E4AF1}.Release|Any CPU.Build.0 = Release|Any CPU + {776590BA-B900-4C8B-986A-5B721FA4B306}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {776590BA-B900-4C8B-986A-5B721FA4B306}.Debug|Any CPU.Build.0 = Debug|Any CPU + {776590BA-B900-4C8B-986A-5B721FA4B306}.Release|Any CPU.ActiveCfg = Release|Any CPU + {776590BA-B900-4C8B-986A-5B721FA4B306}.Release|Any CPU.Build.0 = Release|Any CPU + {3A3AF1ED-FC7F-48CF-8ACE-9D50426B4675}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3A3AF1ED-FC7F-48CF-8ACE-9D50426B4675}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3A3AF1ED-FC7F-48CF-8ACE-9D50426B4675}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3A3AF1ED-FC7F-48CF-8ACE-9D50426B4675}.Release|Any CPU.Build.0 = Release|Any CPU + {68F73B7B-0F8A-41C1-8092-6D6FFAED32F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {68F73B7B-0F8A-41C1-8092-6D6FFAED32F8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {68F73B7B-0F8A-41C1-8092-6D6FFAED32F8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {68F73B7B-0F8A-41C1-8092-6D6FFAED32F8}.Release|Any CPU.Build.0 = Release|Any CPU + {4AE84CDE-2A47-4D68-8E93-86193F72E4E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4AE84CDE-2A47-4D68-8E93-86193F72E4E8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4AE84CDE-2A47-4D68-8E93-86193F72E4E8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4AE84CDE-2A47-4D68-8E93-86193F72E4E8}.Release|Any CPU.Build.0 = Release|Any CPU + {C8F97775-D903-4365-A4FF-3DA97E318CD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C8F97775-D903-4365-A4FF-3DA97E318CD2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C8F97775-D903-4365-A4FF-3DA97E318CD2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C8F97775-D903-4365-A4FF-3DA97E318CD2}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -452,6 +488,12 @@ Global {B7A1A8F3-CFA6-4ECF-A707-0F33FE0A6F1D} = {D8CDDE99-3684-4EED-A5E5-87F2AF4C78AB} {9ECF0841-53BE-4FD8-95D1-A7223C7F3A07} = {0D10EEF2-FBAE-4C72-B816-A52823FC299B} {4FEBBDD9-E4F4-4BAF-8599-E2D57C08A74F} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4} + {2CE51D4C-1EF9-462B-BA14-7EA01A7E4AF1} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4} + {776590BA-B900-4C8B-986A-5B721FA4B306} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4} + {3A3AF1ED-FC7F-48CF-8ACE-9D50426B4675} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4} + {68F73B7B-0F8A-41C1-8092-6D6FFAED32F8} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4} + {4AE84CDE-2A47-4D68-8E93-86193F72E4E8} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4} + {C8F97775-D903-4365-A4FF-3DA97E318CD2} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {23D6FBC9-C970-4641-BC1E-2AEA59F51C18} diff --git a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Middlewares/ApiInfoMiddleware.cs b/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Middlewares/ApiInfoMiddleware.cs index ab0f42a9..5345ff89 100644 --- a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Middlewares/ApiInfoMiddleware.cs +++ b/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Middlewares/ApiInfoMiddleware.cs @@ -15,10 +15,15 @@ namespace Yi.Framework.AspNetCore.Microsoft.AspNetCore.Middlewares context.Response.OnStarting(() => { if (context.Response.StatusCode == StatusCodes.Status200OK -&& context.Response.Headers["Content-Type"].ToString() == "application/vnd.ms-excel") + && context.Response.Headers["Content-Type"].ToString() == "application/vnd.ms-excel") { context.FileAttachmentHandle($"{DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss")}.xlsx"); } + if (context.Response.StatusCode == StatusCodes.Status200OK && + context.Response.Headers["Content-Type"].ToString() == "application/x-zip-compressed") + { + context.FileAttachmentHandle($"{DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss")}.zip"); + } return Task.CompletedTask; }); diff --git a/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs b/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs index e6f33dec..6c86fbe1 100644 --- a/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs +++ b/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs @@ -260,10 +260,6 @@ namespace Yi.Abp.Web { var service = context.ServiceProvider; - var sss=service.GetRequiredService>().Value; - - - var env = context.GetEnvironment(); var app = context.GetApplicationBuilder(); diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool.Application.Contracts/Dtos/TemplateGenCreateInputDto.cs b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Application.Contracts/Dtos/TemplateGenCreateInputDto.cs new file mode 100644 index 00000000..c65e1101 --- /dev/null +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Application.Contracts/Dtos/TemplateGenCreateInputDto.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Abp.Tool.Domain.Shared.Enums; + +namespace Yi.Abp.Tool.Application.Contracts.Dtos +{ + public class TemplateGenCreateInputDto + { + /// + /// 模块名称 + /// + public string Name { get; set; } + + + /// + /// 数据库提供者 + /// + public DbmsEnum Dbms { get; set; } + + + /// + /// 需要替换的字符串内容 + /// + public Dictionary ReplaceStrData { get; set; }=new Dictionary(); + + public void SetNameReplace() + { + ReplaceStrData.Add("Yi.Abp", Name); + ReplaceStrData.Add("YiAbp", Name.Replace(".", "")); + } + } +} diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool.Application.Contracts/ITemplateGenService.cs b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Application.Contracts/ITemplateGenService.cs new file mode 100644 index 00000000..f5830b68 --- /dev/null +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Application.Contracts/ITemplateGenService.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Yi.Abp.Tool.Application.Contracts.Dtos; + +namespace Yi.Abp.Tool.Application.Contracts +{ + public interface ITemplateGenService + { + Task CreateModuleAsync(TemplateGenCreateInputDto moduleCreateInputDto); + Task CreateProjectAsync(TemplateGenCreateInputDto moduleCreateInputDto); + } +} diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool.Application.Contracts/Yi.Abp.Tool.Application.Contracts.csproj b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Application.Contracts/Yi.Abp.Tool.Application.Contracts.csproj new file mode 100644 index 00000000..90506e73 --- /dev/null +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Application.Contracts/Yi.Abp.Tool.Application.Contracts.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool.Application.Contracts/YiAbpToolApplicationContractsModule.cs b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Application.Contracts/YiAbpToolApplicationContractsModule.cs new file mode 100644 index 00000000..f5668c2a --- /dev/null +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Application.Contracts/YiAbpToolApplicationContractsModule.cs @@ -0,0 +1,10 @@ +using Yi.Abp.Tool.Domain.Shared; + +namespace Yi.Abp.Tool.Application.Contracts +{ + [DependsOn(typeof(YiAbpToolDomainSharedModule))] + public class YiAbpToolApplicationContractsModule:AbpModule + { + + } +} diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool.Application/TemplateGenService.cs b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Application/TemplateGenService.cs new file mode 100644 index 00000000..4290aacf --- /dev/null +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Application/TemplateGenService.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Mapster; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.DependencyInjection; +using Yi.Abp.Tool.Application.Contracts; +using Yi.Abp.Tool.Application.Contracts.Dtos; +using Yi.Abp.Tool.Domain; +using Yi.Abp.Tool.Domain.Shared.Dtos; +using Yi.Framework.Core.Helper; + +namespace Yi.Abp.Tool.Application +{ + public class TemplateGenService : IRemoteService, ITemplateGenService, ITransientDependency + { + private readonly TemplateGenManager _templateGenManager; + public TemplateGenService(TemplateGenManager templateGenManager) { _templateGenManager = templateGenManager; } + + /// + /// 下载模块文件 + /// + /// + public async Task CreateModuleAsync(TemplateGenCreateInputDto moduleCreateInputDto) + { + moduleCreateInputDto.SetNameReplace(); + + var input = moduleCreateInputDto.Adapt(); + input.SetTemplateFilePath(_templateGenManager._toolOptions.ModuleTemplateFilePath); + var filePath = await _templateGenManager.CreateTemplateAsync(input); + + //考虑从路径中获取 + var fileContentType = MimeHelper.GetMimeMapping(Path.GetFileName(filePath)); + //设置附件下载,下载名称 + return new FileContentResult(await File.ReadAllBytesAsync(filePath), fileContentType); + } + + /// + /// 下载模块文件 + /// + /// + public async Task CreateProjectAsync(TemplateGenCreateInputDto moduleCreateInputDto) + { + moduleCreateInputDto.SetNameReplace(); + + var input = moduleCreateInputDto.Adapt(); + input.SetTemplateFilePath(_templateGenManager._toolOptions.ProjectTemplateFilePath); + var filePath = await _templateGenManager.CreateTemplateAsync(input); + + //考虑从路径中获取 + var fileContentType = MimeHelper.GetMimeMapping(Path.GetFileName(filePath)); + //设置附件下载,下载名称 + return new FileContentResult(await File.ReadAllBytesAsync(filePath), fileContentType); + } + } +} diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool.Application/Yi.Abp.Tool.Application.csproj b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Application/Yi.Abp.Tool.Application.csproj new file mode 100644 index 00000000..cd464635 --- /dev/null +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Application/Yi.Abp.Tool.Application.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool.Application/YiAbpToolApplicationModule.cs b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Application/YiAbpToolApplicationModule.cs new file mode 100644 index 00000000..76535e45 --- /dev/null +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Application/YiAbpToolApplicationModule.cs @@ -0,0 +1,12 @@ +using Yi.Abp.Tool.Application.Contracts; +using Yi.Abp.Tool.Domain; + +namespace Yi.Abp.Tool.Application +{ + [DependsOn(typeof(YiAbpToolApplicationContractsModule), + typeof(YiAbpToolDomainModule))] + public class YiAbpToolApplicationModule:AbpModule + { + + } +} diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool.Domain.Shared/Dtos/TemplateGenCreateDto.cs b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Domain.Shared/Dtos/TemplateGenCreateDto.cs new file mode 100644 index 00000000..9259ae84 --- /dev/null +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Domain.Shared/Dtos/TemplateGenCreateDto.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Abp.Tool.Domain.Shared.Enums; + +namespace Yi.Abp.Tool.Domain.Shared.Dtos +{ + public class TemplateGenCreateDto + { + public void SetTemplateFilePath(string templateFilePath) + { + this.TemplateFilePath = templateFilePath; + } + + + /// + /// 模板文件路径 + /// + public string TemplateFilePath { get; set; } + /// + /// 模块名称 + /// + public string Name { get; set; } + + + /// + /// 数据库提供者 + /// + public DbmsEnum Dbms { get; set; } + + + /// + /// 需要替换的字符串内容 + /// + public Dictionary ReplaceStrData { get; set; } + } +} diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool.Domain.Shared/Enums/DbmsEnum.cs b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Domain.Shared/Enums/DbmsEnum.cs new file mode 100644 index 00000000..a59a98cc --- /dev/null +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Domain.Shared/Enums/DbmsEnum.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Abp.Tool.Domain.Shared.Enums +{ + public enum DbmsEnum + { + MySQL, + SQLite, + SQLServer, + Oracle, + PostgreSQL + } +} diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool.Domain.Shared/Options/ToolOptions.cs b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Domain.Shared/Options/ToolOptions.cs new file mode 100644 index 00000000..a2084956 --- /dev/null +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Domain.Shared/Options/ToolOptions.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Abp.Tool.Domain.Shared.Options +{ + public class ToolOptions + { + /// + /// 模块模板zip文件路径 + /// + public string ModuleTemplateFilePath { get; set; } + + /// + /// 项目模板zip文件路径 + /// + public string ProjectTemplateFilePath { get; set; } + + + /// + /// 临时文件目录 + /// + public string TempDirPath { get; set; } + } +} diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool.Domain.Shared/Yi.Abp.Tool.Domain.Shared.csproj b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Domain.Shared/Yi.Abp.Tool.Domain.Shared.csproj new file mode 100644 index 00000000..eaf50bd2 --- /dev/null +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Domain.Shared/Yi.Abp.Tool.Domain.Shared.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool.Domain.Shared/YiAbpToolDomainSharedModule.cs b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Domain.Shared/YiAbpToolDomainSharedModule.cs new file mode 100644 index 00000000..734a62e1 --- /dev/null +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Domain.Shared/YiAbpToolDomainSharedModule.cs @@ -0,0 +1,10 @@ +using Yi.Framework.Core; + +namespace Yi.Abp.Tool.Domain.Shared +{ + [DependsOn(typeof(YiFrameworkCoreModule))] + public class YiAbpToolDomainSharedModule : AbpModule + { + + } +} diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool.Domain/TemplateGenManager.cs b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Domain/TemplateGenManager.cs new file mode 100644 index 00000000..b9edbe74 --- /dev/null +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Domain/TemplateGenManager.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.IO.Compression; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; +using Yi.Abp.Tool.Domain.Shared.Dtos; +using Yi.Abp.Tool.Domain.Shared.Options; + +namespace Yi.Abp.Tool.Domain +{ + public class TemplateGenManager : ITransientDependency + { + public readonly ToolOptions _toolOptions; + public TemplateGenManager(IOptionsMonitor toolOptions) { _toolOptions = toolOptions.CurrentValue; } + public async Task CreateTemplateAsync(TemplateGenCreateDto input) + { + if (string.IsNullOrEmpty(input.TemplateFilePath)) + { + throw new UserFriendlyException($"模板路径无法找到,请检查,[{input.TemplateFilePath}]路径"); + } + if (string.IsNullOrEmpty(_toolOptions.TempDirPath)) + { + throw new UserFriendlyException($"临时目录路径无法找到,请检查,[{_toolOptions.TempDirPath}]路径"); + } + + var id = Guid.NewGuid().ToString("N"); + var tempFileDirPath = Path.Combine(_toolOptions.TempDirPath, $"{id}"); + if (!Directory.Exists(tempFileDirPath)) + { + Directory.CreateDirectory(tempFileDirPath); + } + + //文件解压覆盖 + ZipFile.ExtractToDirectory(input.TemplateFilePath, tempFileDirPath, true); + + await ReplaceContentAsync(tempFileDirPath, input.ReplaceStrData); + var tempFilePath = Path.Combine(_toolOptions.TempDirPath, $"{id}.zip"); + + ZipFile.CreateFromDirectory(tempFileDirPath, tempFilePath); + //创建压缩包后删除临时目录 + Directory.Delete(tempFileDirPath, true); + return tempFilePath; + } + + /// + /// 替换内容,key为要替换的内容,value为替换成的内容 + /// + /// + private async Task ReplaceContentAsync(string rootDirectory, Dictionary dic) + { + + foreach (var dicEntry in dic) + { + await ReplaceInDirectory(rootDirectory, dicEntry.Key, dicEntry.Value); + } + + //替换目录名 + static async Task ReplaceInDirectory(string directoryPath, string searchString, string replaceString) + { + // 替换当前目录下的文件和文件夹名称 + var newDirPath = await ReplaceInFiles(directoryPath, searchString, replaceString); + + // 递归遍历子目录 + string[] subDirectories = Directory.GetDirectories(newDirPath); + foreach (string subDirectory in subDirectories) + { + await ReplaceInDirectory(subDirectory, searchString, replaceString); + } + } + + //替换文件名 + static async Task ReplaceInFiles(string directoryPath, string searchString, string replaceString) + { + // 替换目录名 + string directoryName = new DirectoryInfo(directoryPath).Name; + string newDirectoryName = directoryName.Replace(searchString, replaceString); + if (directoryName != newDirectoryName) + { + string parentDirectory = Path.GetDirectoryName(directoryPath); + string newDirectoryPath = Path.Combine(parentDirectory, newDirectoryName); + Directory.Move(directoryPath, newDirectoryPath); + directoryPath = newDirectoryPath; + } + + + // 替换文件名 + string[] files = Directory.GetFiles(directoryPath); + foreach (string file in files) + { + string newFileName = file.Replace(searchString, replaceString); + if (file != newFileName) + { + File.Move(file, newFileName); + } + } + + files = Directory.GetFiles(directoryPath); + // 替换文件内容 + foreach (string file in files) + { + string fileContent = await File.ReadAllTextAsync(file); + string newFileContent = fileContent.Replace(searchString, replaceString); + await File.WriteAllTextAsync(file, newFileContent); + } + + + return directoryPath; + } + } + } +} diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool.Domain/Yi.Abp.Tool.Domain.csproj b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Domain/Yi.Abp.Tool.Domain.csproj new file mode 100644 index 00000000..062edcec --- /dev/null +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Domain/Yi.Abp.Tool.Domain.csproj @@ -0,0 +1,12 @@ + + + + net8.0 + enable + enable + + + + + + diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool.Domain/YiAbpToolDomainModule.cs b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Domain/YiAbpToolDomainModule.cs new file mode 100644 index 00000000..b8559b2f --- /dev/null +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Domain/YiAbpToolDomainModule.cs @@ -0,0 +1,24 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Yi.Abp.Tool.Domain.Shared; +using Yi.Abp.Tool.Domain.Shared.Options; + +namespace Yi.Abp.Tool.Domain +{ + [DependsOn(typeof(YiAbpToolDomainSharedModule))] + public class YiAbpToolDomainModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + Configure(configuration.GetSection("ToolOptions")); + var toolOptions = new ToolOptions(); + configuration.GetSection("ToolOptions").Bind(toolOptions); + if (!Directory.Exists(toolOptions.TempDirPath)) + { + Directory.CreateDirectory(toolOptions.TempDirPath); + } + + } + } +} diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool.HttpApi.Client/Yi.Abp.Tool.HttpApi.Client.csproj b/Yi.Abp.Net8/tool/Yi.Abp.Tool.HttpApi.Client/Yi.Abp.Tool.HttpApi.Client.csproj new file mode 100644 index 00000000..a0fff017 --- /dev/null +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool.HttpApi.Client/Yi.Abp.Tool.HttpApi.Client.csproj @@ -0,0 +1,16 @@ + + + + net8.0 + enable + enable + + + + + + + + + + diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool.HttpApi.Client/YiAbpToolHttpApiClientModule.cs b/Yi.Abp.Net8/tool/Yi.Abp.Tool.HttpApi.Client/YiAbpToolHttpApiClientModule.cs new file mode 100644 index 00000000..cd33b08e --- /dev/null +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool.HttpApi.Client/YiAbpToolHttpApiClientModule.cs @@ -0,0 +1,27 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Autofac; +using Volo.Abp.Http.Client; +using Yi.Abp.Tool.Application.Contracts; + +namespace Yi.Abp.Tool.HttpApi.Client +{ + [DependsOn(typeof(AbpHttpClientModule), + typeof(AbpAutofacModule), + typeof(YiAbpToolApplicationContractsModule))] + public class YiAbpToolHttpApiClientModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + //创建动态客户端代理 + context.Services.AddHttpClientProxies( + typeof(YiAbpToolApplicationContractsModule).Assembly + + ); + Configure(options => + { + options.RemoteServices.Default = + new RemoteServiceConfiguration("http://localhost:19002"); + }); + } + } +} diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool.Web/Program.cs b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Web/Program.cs new file mode 100644 index 00000000..c0ad451f --- /dev/null +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Web/Program.cs @@ -0,0 +1,9 @@ +using Yi.Abp.Tool.Web; + +var builder = WebApplication.CreateBuilder(args); +builder.WebHost.UseUrls(builder.Configuration["App:SelfUrl"]); +builder.Host.UseAutofac(); +await builder.Services.AddApplicationAsync(); +var app = builder.Build(); +await app.InitializeApplicationAsync(); +await app.RunAsync(); \ No newline at end of file diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool.Web/Properties/launchSettings.json b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Web/Properties/launchSettings.json new file mode 100644 index 00000000..0c73d601 --- /dev/null +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Web/Properties/launchSettings.json @@ -0,0 +1,25 @@ +{ + "profiles": { + "Yi.Abp.Tool.Web": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + //"ASPNETCORE_ENVIRONMENT": "Staging" + }, + "dotnetRunMessages": true, + "applicationUrl": "http://localhost:19002" + }, + "Docker": { + "commandName": "Docker", + "launchBrowser": true, + "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger", + "environmentVariables": { + "ASPNETCORE_HTTP_PORTS": "19002" + }, + "publishAllPorts": true + } + }, + "$schema": "https://json.schemastore.org/launchsettings.json" +} \ No newline at end of file diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool.Web/Yi.Abp.Tool.Web.csproj b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Web/Yi.Abp.Tool.Web.csproj new file mode 100644 index 00000000..8c2119ac --- /dev/null +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Web/Yi.Abp.Tool.Web.csproj @@ -0,0 +1,24 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + + + + + + + diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool.Web/YiAbpToolWebModule.cs b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Web/YiAbpToolWebModule.cs new file mode 100644 index 00000000..dd4cc1c7 --- /dev/null +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Web/YiAbpToolWebModule.cs @@ -0,0 +1,159 @@ +using System.Globalization; +using System.Threading.RateLimiting; +using Microsoft.AspNetCore.Cors; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.OpenApi.Models; +using Newtonsoft.Json.Converters; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc.AntiForgery; +using Volo.Abp.Autofac; +using Volo.Abp.Swashbuckle; +using Yi.Abp.Tool.Application; +using Yi.Framework.AspNetCore; +using Yi.Framework.AspNetCore.Microsoft.AspNetCore.Builder; +using Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection; + +namespace Yi.Abp.Tool.Web +{ + [DependsOn(typeof(YiAbpToolApplicationModule), + + + typeof(AbpAspNetCoreMvcModule), + typeof(AbpAutofacModule), + typeof(AbpSwashbuckleModule), + typeof(YiFrameworkAspNetCoreModule) + )] + public class YiAbpToolWebModule : AbpModule + { + private const string DefaultCorsPolicyName = "Default"; + public override Task ConfigureServicesAsync(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + var host = context.Services.GetHostingEnvironment(); + var service = context.Services; + + //动态Api + Configure(options => + { + options.ConventionalControllers.Create(typeof(YiAbpToolApplicationModule).Assembly, options => options.RemoteServiceName = "tool"); + //统一前缀 + options.ConventionalControllers.ConventionalControllerSettings.ForEach(x => x.RootPath = "api/app"); + }); + + //设置api格式 + service.AddControllers().AddNewtonsoftJson(options => + { + options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; + options.SerializerSettings.Converters.Add(new StringEnumConverter()); + }); + + + + + Configure(options => + { + options.AutoValidate = false; + }); + + //Swagger + context.Services.AddYiSwaggerGen(options => + { + options.SwaggerDoc("default", new OpenApiInfo { Title = "Yi.Framework.Abp", Version = "v1", Description = "集大成者" }); + }); + + //跨域 + context.Services.AddCors(options => + { + options.AddPolicy(DefaultCorsPolicyName, builder => + { + builder + .WithOrigins( + configuration["App:CorsOrigins"]! + .Split(";", StringSplitOptions.RemoveEmptyEntries) + .Select(o => o.RemovePostFix("/")) + .ToArray() + ) + .WithAbpExposedHeaders() + .SetIsOriginAllowedToAllowWildcardSubdomains() + .AllowAnyHeader() + .AllowAnyMethod() + .AllowCredentials(); + }); + }); + + + //速率限制 + //每60秒限制100个请求,滑块添加,分6段 + service.AddRateLimiter(_ => + { + _.RejectionStatusCode = StatusCodes.Status429TooManyRequests; + _.OnRejected = (context, _) => + { + if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter)) + { + context.HttpContext.Response.Headers.RetryAfter = + ((int)retryAfter.TotalSeconds).ToString(NumberFormatInfo.InvariantInfo); + } + context.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests; + context.HttpContext.Response.WriteAsync("Too many requests. Please try again later."); + + return new ValueTask(); + }; + + //全局使用,链式表达式 + _.GlobalLimiter = PartitionedRateLimiter.CreateChained( + PartitionedRateLimiter.Create(httpContext => + { + var userAgent = httpContext.Request.Headers.UserAgent.ToString(); + + return RateLimitPartition.GetSlidingWindowLimiter + (userAgent, _ => + new SlidingWindowRateLimiterOptions + { + PermitLimit = 1000, + Window = TimeSpan.FromSeconds(60), + SegmentsPerWindow = 6, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst + }); + })); + }); + + + + return Task.CompletedTask; + } + + + public override Task OnApplicationInitializationAsync(ApplicationInitializationContext context) + { + var service = context.ServiceProvider; + var env = context.GetEnvironment(); + var app = context.GetApplicationBuilder(); + + app.UseRouting(); + + //跨域 + app.UseCors(DefaultCorsPolicyName); + + if (!env.IsDevelopment()) + { + //速率限制 + app.UseRateLimiter(); + } + //swagger + app.UseYiSwagger(); + + //请求处理 + app.UseYiApiHandlinge(); + //静态资源 + app.UseStaticFiles("/api/app/wwwroot"); + app.UseDefaultFiles(); + app.UseDirectoryBrowser("/api/app/wwwroot"); + + //终节点 + app.UseConfiguredEndpoints(); + + return Task.CompletedTask; + } + } +} diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool.Web/appsettings.Development.json b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Web/appsettings.Development.json new file mode 100644 index 00000000..0c208ae9 --- /dev/null +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Web/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool.Web/appsettings.json b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Web/appsettings.json new file mode 100644 index 00000000..a9d33481 --- /dev/null +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Web/appsettings.json @@ -0,0 +1,19 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + //应用启动 + "App": { + "SelfUrl": "http://*:19002", + "CorsOrigins": "http://localhost:19002;http://localhost:18002" + }, + "ToolOptions": { + "TempDirPath": "wwwroot/temp", + "ModuleTemplateFilePath": "wwwroot/ModuleTemplate.zip", + "ProjectTemplateFilePath": "wwwroot/ProjectTemplate.zip" + } +} diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool.Web/wwwroot/ModuleTemplate.zip b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Web/wwwroot/ModuleTemplate.zip new file mode 100644 index 00000000..1c4a0fd1 Binary files /dev/null and b/Yi.Abp.Net8/tool/Yi.Abp.Tool.Web/wwwroot/ModuleTemplate.zip differ diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool/CommandSelector.cs b/Yi.Abp.Net8/tool/Yi.Abp.Tool/CommandSelector.cs index 28844a62..70d58aef 100644 --- a/Yi.Abp.Net8/tool/Yi.Abp.Tool/CommandSelector.cs +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool/CommandSelector.cs @@ -62,7 +62,7 @@ namespace Yi.Abp.Tool } - await commandOrNull.InvokerAsync(options); + await commandOrNull.InvokerAsync(options,args); } /// diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool/Commands/HelpCommand.cs b/Yi.Abp.Net8/tool/Yi.Abp.Tool/Commands/HelpCommand.cs index 0edf9947..5aab22bf 100644 --- a/Yi.Abp.Net8/tool/Yi.Abp.Tool/Commands/HelpCommand.cs +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool/Commands/HelpCommand.cs @@ -11,7 +11,7 @@ namespace Yi.Abp.Tool.Commands { public List CommandStrs => new List { "h", "help", "-h", "-help" }; - public Task InvokerAsync(Dictionary options) + public Task InvokerAsync(Dictionary options, string[] args) { string? errorMsg = null; if (options.TryGetValue("error", out _)) diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool/Commands/NewCommand.cs b/Yi.Abp.Net8/tool/Yi.Abp.Tool/Commands/NewCommand.cs new file mode 100644 index 00000000..6a812d00 --- /dev/null +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool/Commands/NewCommand.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Yi.Abp.Tool.Application.Contracts; +using Yi.Abp.Tool.Application.Contracts.Dtos; + +namespace Yi.Abp.Tool.Commands +{ + public class NewCommand : ICommand + { + private readonly ITemplateGenService _templateGenService; + public NewCommand(ITemplateGenService templateGenService) + { + _templateGenService = templateGenService; + } + + public List CommandStrs => new List() { "new" }; + + + public async Task InvokerAsync(Dictionary options, string[] args) + { + //只有一个new + if (args.Length <= 1) + { + throw new UserFriendlyException("命令错误,new命令后必须添加 名称"); + } + string name = args[1]; + + options.TryGetValue("t", out var templateType); + + if (templateType == "module") + { + //代表模块生成 + var fileResult = await _templateGenService.CreateModuleAsync(new TemplateGenCreateInputDto + { + Name = name, + }); + var fileContent = fileResult as FileContentResult; + File.WriteAllText("./", Encoding.UTF8.GetString(fileContent.FileContents)); + + } + else + { + //暂未实现 + throw new NotImplementedException(); + //代表模块生成 + var fileResult = await _templateGenService.CreateProjectAsync(new TemplateGenCreateInputDto + { + Name = name, + }); + } + + + + } + } +} diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool/Commands/VersionCommand.cs b/Yi.Abp.Net8/tool/Yi.Abp.Tool/Commands/VersionCommand.cs index b472cd45..86c56f96 100644 --- a/Yi.Abp.Net8/tool/Yi.Abp.Tool/Commands/VersionCommand.cs +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool/Commands/VersionCommand.cs @@ -4,7 +4,7 @@ { public List CommandStrs => new List { "version", "v", "-version", "-v" }; - public Task InvokerAsync(Dictionary options) + public Task InvokerAsync(Dictionary options, string[] args) { var version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; Console.WriteLine($"Yi-ABP TOOL {version}"); diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool/ICommand.cs b/Yi.Abp.Net8/tool/Yi.Abp.Tool/ICommand.cs index 577b299d..8b9f9108 100644 --- a/Yi.Abp.Net8/tool/Yi.Abp.Tool/ICommand.cs +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool/ICommand.cs @@ -18,6 +18,6 @@ namespace Yi.Abp.Tool /// 执行 /// /// - public Task InvokerAsync(Dictionary options); + public Task InvokerAsync(Dictionary options, string[] args); } } diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool/Program.cs b/Yi.Abp.Net8/tool/Yi.Abp.Tool/Program.cs index 96e8416f..61893169 100644 --- a/Yi.Abp.Net8/tool/Yi.Abp.Tool/Program.cs +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool/Program.cs @@ -15,6 +15,7 @@ class Program //args = ["-h"]; //args = []; //args = ["12312"]; + args = ["new", "Acme.Book","-t", "module", "-csf"]; #endif try { @@ -34,6 +35,7 @@ class Program Console.WriteLine(ex.Message); Console.WriteLine(ex.StackTrace); } + Console.ReadKey(); } } \ No newline at end of file diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool/Yi.Abp.Tool.csproj b/Yi.Abp.Net8/tool/Yi.Abp.Tool/Yi.Abp.Tool.csproj index 4ef7f100..662938e1 100644 --- a/Yi.Abp.Net8/tool/Yi.Abp.Tool/Yi.Abp.Tool.csproj +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool/Yi.Abp.Tool.csproj @@ -31,6 +31,11 @@ + + + + + True diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool/YiAbpToolModule.cs b/Yi.Abp.Net8/tool/Yi.Abp.Tool/YiAbpToolModule.cs index 1f8c6fb8..02ca7846 100644 --- a/Yi.Abp.Net8/tool/Yi.Abp.Tool/YiAbpToolModule.cs +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool/YiAbpToolModule.cs @@ -3,9 +3,11 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Yi.Abp.Tool.HttpApi.Client; namespace Yi.Abp.Tool { + [DependsOn(typeof(YiAbpToolHttpApiClientModule))] public class YiAbpToolModule : AbpModule { }