refactor: 重构文件模块

This commit is contained in:
橙子
2024-12-21 18:00:43 +08:00
parent 48dc89c43d
commit 6c409bfa00
5 changed files with 243 additions and 106 deletions

View File

@@ -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<string> GetReturnPathAsync(Guid code, bool? isThumbnail);
Task<List<FileGetListOutputDto>> Post(IFormFileCollection file);
/// <summary>
/// 下载文件,支持缩略图
/// </summary>
/// <returns></returns>
Task<IActionResult> Get([FromRoute] Guid code, [FromRoute] bool? isThumbnail);
/// <summary>
/// 上传文件
/// </summary>
/// <returns></returns>
Task<List<FileGetListOutputDto>> Post([FromForm] IFormFileCollection file);
}
}

View File

@@ -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<FileAggregateRoot> _repository;
private IGuidGenerator _guidGenerator;
public FileService(IRepository<FileAggregateRoot> repository, IGuidGenerator guidGenerator)
private readonly FileManager _fileManager;
public FileService(IRepository<FileAggregateRoot> repository, FileManager fileManager)
{
_guidGenerator = guidGenerator;
_repository = repository;
_fileManager = fileManager;
}
/// <summary>
/// 下载文件,是否缩略图
/// 下载文件,支持缩略图
/// </summary>
/// <returns></returns>
[Route("file/{code}/{isThumbnail?}")]
public async Task<IActionResult> 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<string?> 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;
}
/// <summary>
/// 上传文件
/// Todo: 可放入领域层
/// </summary>
/// <returns></returns>
public async Task<List<FileGetListOutputDto>> 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<FileAggregateRoot> 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<List<FileGetListOutputDto>>();
}
}
}
}

View File

@@ -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)
/// <summary>
/// 创建文件
/// </summary>
/// <param name="fileId">文件标识id</param>
/// <param name="fileName">文件名</param>
/// <param name="fileSize">文件大小</param>
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; }
/// <summary>
/// 检测目录是否存在,不存在便创建
/// </summary>
public void CheckDirectoryOrCreate()
{
var savePath = GetSaveDirPath();
if (!Directory.Exists(savePath))
{
Directory.CreateDirectory(savePath);
}
}
/// <summary>
/// 文件类型
/// </summary>
/// <returns></returns>
public FileTypeEnum GetFileType()
{
return MimeHelper.GetFileType(this.FileName);
}
/// <summary>
/// 获取文件mime
/// </summary>
/// <returns></returns>
public string GetMimeMapping()
{
return MimeHelper.GetMimeMapping(this.FileName)??@"text/plain";
}
/// <summary>
/// 落库目录路径
/// </summary>
/// <returns></returns>
public string GetSaveDirPath()
{
return $"wwwroot/{GetFileType()}";
}
/// <summary>
/// 落库文件路径
/// </summary>
/// <returns></returns>
public string GetSaveFilePath()
{
string savefileName = GetSaveFileName();
return Path.Combine(GetSaveDirPath(), savefileName);
}
/// <summary>
/// 获取保存的文件名
/// </summary>
/// <returns></returns>
public string GetSaveFileName()
{
return this.Id.ToString() + Path.GetExtension(this.FileName);
}
/// <summary>
/// 检测,并且返回缩略图的保存路径
/// </summary>
/// <param name="saveFileName"></param>
/// <returns></returns>
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());
}
/// <summary>
/// 获取查询的的文件路径
/// </summary>
/// <param name="file"></param>
/// <param name="isThumbnail"></param>
/// <returns></returns>
public string? GetQueryFileSavePath(bool? isThumbnail)
{
string fileSavePath;
//如果为缩略图,需要修改路径
if (isThumbnail is true)
{
fileSavePath = this.GetAndCheakThumbnailSavePath();
}
else
{
fileSavePath = this.GetSaveFilePath();
}
return fileSavePath;
}
/// <summary>
/// 文件大小
///</summary>
[SugarColumn(ColumnName = "FileSize")]
public decimal FileSize { get; set; }
public decimal FileSize { get; internal set; }
/// <summary>
/// 文件名
///</summary>
[SugarColumn(ColumnName = "FileName")]
public string FileName { get; set; }
public string FileName { get; internal set; }
/// <summary>
/// 文件路径
///</summary>
[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; }
}
}
}

View File

@@ -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<FileAggregateRoot> _repository;
public FileManager(IGuidGenerator guidGenerator, IRepository<FileAggregateRoot> repository)
{
_guidGenerator = guidGenerator;
_repository = repository;
}
/// <summary>
/// 批量插入数据库
/// </summary>
/// <param name="files"></param>
/// <exception cref="ArgumentException"></exception>
public async Task<List<FileAggregateRoot>> CreateAsync(IEnumerable<IFormFile> files)
{
if (files.Count() == 0)
{
throw new ArgumentException("文件上传为空!");
}
//批量插入
List<FileAggregateRoot> 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;
}
/// <summary>
/// 保存文件
/// </summary>
/// <param name="file"></param>
/// <param name="fileStream"></param>
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);
}
}
}
}
}

View File

@@ -0,0 +1,6 @@
namespace Yi.Framework.Rbac.Domain.Managers;
public interface IFileManager
{
}