From 6c409bfa00e2480173f4f1fb21699c495ea4908b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A9=99=E5=AD=90?= <454313500@qq.com> Date: Sat, 21 Dec 2024 18:00:43 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IServices/IFileService.cs | 14 +- .../Services/FileService.cs | 114 +++------------ .../Entities/FileAggregateRoot.cs | 131 ++++++++++++++++-- .../Managers/FileManager.cs | 84 +++++++++++ .../Managers/IFileManager.cs | 6 + 5 files changed, 243 insertions(+), 106 deletions(-) create mode 100644 Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Managers/FileManager.cs create mode 100644 Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Managers/IFileManager.cs diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/IServices/IFileService.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/IServices/IFileService.cs index d9fdc6c5..52132f84 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/IServices/IFileService.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/IServices/IFileService.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; using Volo.Abp.Application.Services; using Yi.Framework.Rbac.Application.Contracts.Dtos.FileManager; @@ -6,7 +7,16 @@ namespace Yi.Framework.Rbac.Application.Contracts.IServices { public interface IFileService : IApplicationService { - Task GetReturnPathAsync(Guid code, bool? isThumbnail); - Task> Post(IFormFileCollection file); + /// + /// 下载文件,支持缩略图 + /// + /// + Task Get([FromRoute] Guid code, [FromRoute] bool? isThumbnail); + + /// + /// 上传文件 + /// + /// + Task> Post([FromForm] IFormFileCollection file); } } diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/FileService.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/FileService.cs index 011be87f..f7be6221 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/FileService.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/FileService.cs @@ -15,129 +15,55 @@ using Yi.Framework.Core.Helper; using Yi.Framework.Rbac.Application.Contracts.Dtos.FileManager; using Yi.Framework.Rbac.Application.Contracts.IServices; using Yi.Framework.Rbac.Domain.Entities; +using Yi.Framework.Rbac.Domain.Managers; namespace Yi.Framework.Rbac.Application.Services { public class FileService : ApplicationService, IFileService { private readonly IRepository _repository; - private IGuidGenerator _guidGenerator; - public FileService(IRepository repository, IGuidGenerator guidGenerator) + private readonly FileManager _fileManager; + + public FileService(IRepository repository, FileManager fileManager) { - _guidGenerator = guidGenerator; _repository = repository; + _fileManager = fileManager; } /// - /// 下载文件,是否缩略图 + /// 下载文件,支持缩略图 /// /// [Route("file/{code}/{isThumbnail?}")] public async Task Get([FromRoute] Guid code, [FromRoute] bool? isThumbnail) { - var path = await GetReturnPathAsync(code, isThumbnail); - - if (path is null||!File.Exists(path)) + var file = await _repository.GetAsync(x => x.Id == code); + var path = file.GetQueryFileSavePath(isThumbnail); + if (path is null || !File.Exists(path)) { return new NotFoundResult(); - // throw new UserFriendlyException("文件不存在",code:"404"); } - - var steam = await File.ReadAllBytesAsync(path); - - //考虑从路径中获取 - var fileContentType = MimeHelper.GetMimeMapping(Path.GetFileName(path)); - //设置附件下载,下载名称 - //_httpContext.FileAttachmentHandle(file.FileName); - return new FileContentResult(steam, fileContentType ?? @"text/plain"); + return new FileContentResult(steam, file.GetMimeMapping()); } - - public async Task GetReturnPathAsync(Guid code, bool? isThumbnail) - { - var file = await _repository.GetAsync(x => x.Id == code); - if (file is null) - { - return null; - // throw new UserFriendlyException("文件编号未匹配", "404"); - } - var path = file.FilePath; - //如果为缩略图,需要修改路径 - //if (isThumbnail is true) - //{ - // path = $"wwwroot/{FileTypeEnum.Thumbnail}/{file.Id}{Path.GetExtension(file.FileName)}"; - //} - //路径为: 文件路径/文件id+文件扩展名 - return path; - } - + /// /// 上传文件 - /// Todo: 可放入领域层 /// /// public async Task> Post([FromForm] IFormFileCollection file) { - if (file.Count() == 0) + var entities = await _fileManager.CreateAsync(file); + + for (int i = 0; i < file.Count; i++) { - throw new ArgumentException("文件上传为空!"); + var entity= entities[i]; + using (var steam = file[i].OpenReadStream()) + { + await _fileManager.SaveFileAsync(entity,steam); + } } - //批量插入 - List entities = new(); - - foreach (var f in file) - { - FileAggregateRoot data = new(_guidGenerator.Create()); - data.FileSize = (decimal)f.Length / 1024; - data.FileName = f.FileName; - - var type = MimeHelper.GetFileType(f.FileName); - - //落盘文件,文件名为雪花id+自己的扩展名 - string filename = data.Id.ToString() + Path.GetExtension(f.FileName); - string typePath = $"wwwroot/{type}"; - if (!Directory.Exists(typePath)) - { - Directory.CreateDirectory(typePath); - } - var filePath = Path.Combine(typePath, filename); - data.FilePath = filePath; - - - //生成文件 - using (var stream = new FileStream(filePath, FileMode.CreateNew, FileAccess.ReadWrite)) - { - await f.CopyToAsync(stream); - - //如果是图片类型,还需要生成缩略图,当然,如果图片很小,直接复制过去即可 - if (FileTypeEnum.Image.Equals(type)) - { - string thumbnailPath = $"wwwroot/{FileTypeEnum.Thumbnail}"; - if (!Directory.Exists(thumbnailPath)) - { - Directory.CreateDirectory(thumbnailPath); - } - string thumbnailFilePath = Path.Combine(thumbnailPath, filename); - try - { - // _imageSharpManager.ImageCompress(f.FileName, f.OpenReadStream(), thumbnailFilePath); - } - catch - { - var result = new byte[stream.Length]; - await stream.ReadAsync(result, 0, result.Length); - await File.WriteAllBytesAsync(thumbnailFilePath, result); - } - } - - - }; - entities.Add(data); - } - await _repository.InsertManyAsync(entities); return entities.Adapt>(); - - } } -} +} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Entities/FileAggregateRoot.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Entities/FileAggregateRoot.cs index 16beb5c2..4ef11526 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Entities/FileAggregateRoot.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Entities/FileAggregateRoot.cs @@ -7,6 +7,8 @@ using SqlSugar; using Volo.Abp.Auditing; using Volo.Abp.Data; using Volo.Abp.Domain.Entities; +using Yi.Framework.Core.Enums; +using Yi.Framework.Core.Helper; namespace Yi.Framework.Rbac.Domain.Entities { @@ -17,28 +19,140 @@ namespace Yi.Framework.Rbac.Domain.Entities { } - public FileAggregateRoot(Guid fileId) + /// + /// 创建文件 + /// + /// 文件标识id + /// 文件名 + /// 文件大小 + public FileAggregateRoot(Guid fileId, string fileName, decimal fileSize) { this.Id = fileId; + this.FileSize = fileSize; + this.FileName = fileName; + + var type = GetFileType(); + + var savePath = GetSaveFilePath(); + var filePath = Path.Combine(savePath, this.FileName); + this.FilePath = filePath; } - [SugarColumn(IsPrimaryKey = true)] - public override Guid Id { get; protected set; } + /// + /// 检测目录是否存在,不存在便创建 + /// + public void CheckDirectoryOrCreate() + { + var savePath = GetSaveDirPath(); + if (!Directory.Exists(savePath)) + { + Directory.CreateDirectory(savePath); + } + } + + /// + /// 文件类型 + /// + /// + public FileTypeEnum GetFileType() + { + return MimeHelper.GetFileType(this.FileName); + } + + /// + /// 获取文件mime + /// + /// + public string GetMimeMapping() + { + return MimeHelper.GetMimeMapping(this.FileName)??@"text/plain"; + } + + /// + /// 落库目录路径 + /// + /// + public string GetSaveDirPath() + { + return $"wwwroot/{GetFileType()}"; + } + + /// + /// 落库文件路径 + /// + /// + public string GetSaveFilePath() + { + string savefileName = GetSaveFileName(); + return Path.Combine(GetSaveDirPath(), savefileName); + } + + /// + /// 获取保存的文件名 + /// + /// + public string GetSaveFileName() + { + return this.Id.ToString() + Path.GetExtension(this.FileName); + } + + /// + /// 检测,并且返回缩略图的保存路径 + /// + /// + /// + public string GetAndCheakThumbnailSavePath(bool isCheak=false) + { + string thumbnailPath = $"wwwroot/{FileTypeEnum.Thumbnail}"; + if (isCheak) + { + if (!Directory.Exists(thumbnailPath)) + { + Directory.CreateDirectory(thumbnailPath); + } + } + return Path.Combine(thumbnailPath, GetSaveFileName()); + } + + + /// + /// 获取查询的的文件路径 + /// + /// + /// + /// + public string? GetQueryFileSavePath(bool? isThumbnail) + { + string fileSavePath; + //如果为缩略图,需要修改路径 + if (isThumbnail is true) + { + fileSavePath = this.GetAndCheakThumbnailSavePath(); + } + else + { + fileSavePath = this.GetSaveFilePath(); + } + return fileSavePath; + } + /// /// 文件大小 /// [SugarColumn(ColumnName = "FileSize")] - public decimal FileSize { get; set; } + public decimal FileSize { get; internal set; } + /// /// 文件名 /// [SugarColumn(ColumnName = "FileName")] - public string FileName { get; set; } + public string FileName { get; internal set; } + /// /// 文件路径 /// [SugarColumn(ColumnName = "FilePath")] - public string FilePath { get; set; } + public string FilePath { get; internal set; } public DateTime CreationTime { get; set; } public Guid? CreatorId { get; set; } @@ -46,8 +160,5 @@ namespace Yi.Framework.Rbac.Domain.Entities public Guid? LastModifierId { get; set; } public DateTime? LastModificationTime { get; set; } - - [SugarColumn(IsIgnore=true)] - public override ExtraPropertyDictionary ExtraProperties { get; protected set; } } -} +} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Managers/FileManager.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Managers/FileManager.cs new file mode 100644 index 00000000..d6698128 --- /dev/null +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Managers/FileManager.cs @@ -0,0 +1,84 @@ +using Mapster; +using Microsoft.AspNetCore.Http; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.Domain.Services; +using Volo.Abp.Guids; +using Yi.Framework.Core.Enums; +using Yi.Framework.Core.Helper; +using Yi.Framework.Rbac.Domain.Entities; + +namespace Yi.Framework.Rbac.Domain.Managers; + +public class FileManager : DomainService, IFileManager +{ + private IGuidGenerator _guidGenerator; + private readonly IRepository _repository; + + public FileManager(IGuidGenerator guidGenerator, IRepository repository) + { + _guidGenerator = guidGenerator; + _repository = repository; + } + + /// + /// 批量插入数据库 + /// + /// + /// + public async Task> CreateAsync(IEnumerable files) + { + if (files.Count() == 0) + { + throw new ArgumentException("文件上传为空!"); + } + + //批量插入 + List entities = new(); + foreach (var file in files) + { + FileAggregateRoot data = new(_guidGenerator.Create(), file.FileName, (decimal)file.Length / 1024); + data.CheckDirectoryOrCreate(); + entities.Add(data); + } + + await _repository.InsertManyAsync(entities); + return entities; + } + + + /// + /// 保存文件 + /// + /// + /// + public async Task SaveFileAsync(FileAggregateRoot file,Stream fileStream) + { + var filePath = file.GetSaveFilePath(); + + //生成文件 + using (var stream = new FileStream(filePath, FileMode.CreateNew, FileAccess.ReadWrite)) + { + await fileStream.CopyToAsync(stream); + + //如果是图片类型,还需要生成缩略图 + //这里根据自己需求变更,我们的需求是:原始文件与缩略图文件,都要一份 + var fileType=file.GetFileType();; + //如果文件类型是图片,尝试进行压缩 + if (FileTypeEnum.Image.Equals(fileType)) + { + var thumbnailSavePath= file.GetAndCheakThumbnailSavePath(true); + try + { + // _imageSharpManager.ImageCompress(f.FileName, f.OpenReadStream(), thumbnailFilePath); + } + catch + { + //如果失败了,直接复制一份到缩略图上即可 + var result = new byte[stream.Length]; + await stream.ReadAsync(result, 0, result.Length); + await File.WriteAllBytesAsync(thumbnailSavePath, result); + } + } + } + } +} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Managers/IFileManager.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Managers/IFileManager.cs new file mode 100644 index 00000000..838476ab --- /dev/null +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Managers/IFileManager.cs @@ -0,0 +1,6 @@ +namespace Yi.Framework.Rbac.Domain.Managers; + +public interface IFileManager +{ + +} \ No newline at end of file