63 changed files with 3156 additions and 281 deletions
@ -0,0 +1,38 @@ |
|||||
|
namespace Lion.AbpPro.FileManagement.Files; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 创建文件
|
||||
|
/// </summary>
|
||||
|
public class CreateFileObjectInput |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 文件Provider
|
||||
|
/// </summary>
|
||||
|
[Required(ErrorMessage = "文件Provider不能为空")] |
||||
|
public string ProviderKey { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 文件扩展名
|
||||
|
/// </summary>
|
||||
|
[Required(ErrorMessage = "文件扩展名不能为空")] |
||||
|
public string FileExtension { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 二进制数据
|
||||
|
/// </summary>
|
||||
|
[Required(ErrorMessage = "二进制数据不能为空")] |
||||
|
public long Bytes { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 文件大小
|
||||
|
/// </summary>
|
||||
|
[Required(ErrorMessage = "文件大小不能为空")] |
||||
|
public long FileSize { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 文件名称
|
||||
|
/// </summary>
|
||||
|
[Required(ErrorMessage = "文件名称不能为空")] |
||||
|
public string ContentType { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 文件名称
|
||||
|
/// </summary>
|
||||
|
[Required(ErrorMessage = "文件名称不能为空")] |
||||
|
public string FileName { get; set; } |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
namespace Lion.AbpPro.FileManagement.Files; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 删除文件
|
||||
|
/// </summary>
|
||||
|
public class DeleteFileObjectInput |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 文件Id
|
||||
|
/// </summary>
|
||||
|
public Guid Id { get; set; } |
||||
|
} |
||||
@ -1,8 +0,0 @@ |
|||||
namespace Lion.AbpPro.FileManagement.Files.Dto; |
|
||||
|
|
||||
public class CreateFileInput |
|
||||
{ |
|
||||
[Required(ErrorMessage = "文件名不能为空")] public string FileName { get; set; } |
|
||||
|
|
||||
[Required(ErrorMessage = "文件地址不能为空")] public string FilePath { get; set; } |
|
||||
} |
|
||||
@ -1,19 +0,0 @@ |
|||||
namespace Lion.AbpPro.FileManagement.Files.Dto; |
|
||||
|
|
||||
public class FileTokenOutput |
|
||||
{ |
|
||||
public string AccessKeyId { get; set; } |
|
||||
|
|
||||
public string AccessKeySecret { get; set; } |
|
||||
|
|
||||
public string Token { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// 过期时间
|
|
||||
/// </summary>
|
|
||||
public string Expiration { get; set; } |
|
||||
|
|
||||
public string Bucket { get; set; } |
|
||||
|
|
||||
public string Region { get; set; } |
|
||||
} |
|
||||
@ -1,14 +0,0 @@ |
|||||
namespace Lion.AbpPro.FileManagement.Files.Dto; |
|
||||
|
|
||||
public class PagingFileOutput |
|
||||
{ |
|
||||
public Guid Id { get; set; } |
|
||||
|
|
||||
public Guid? TenantId { get; set; } |
|
||||
|
|
||||
public string FileName { get; set; } |
|
||||
|
|
||||
public string FilePath { get; set; } |
|
||||
|
|
||||
public DateTime CreationTime { get; set; } |
|
||||
} |
|
||||
@ -1,6 +0,0 @@ |
|||||
namespace Lion.AbpPro.FileManagement.Files.Dto; |
|
||||
|
|
||||
public class PagingFileInput : PagingBase |
|
||||
{ |
|
||||
public string Filter { get; set; } |
|
||||
} |
|
||||
@ -0,0 +1,9 @@ |
|||||
|
namespace Lion.AbpPro.FileManagement.Files; |
||||
|
|
||||
|
public class GetFileObjectInput |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 文件Id
|
||||
|
/// </summary>
|
||||
|
public Guid Id { get; set; } |
||||
|
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
namespace Lion.AbpPro.FileManagement.Files; |
||||
|
|
||||
|
public class GetFileObjectOutput |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 文件Id
|
||||
|
/// </summary>
|
||||
|
public Guid Id { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 文件Provider
|
||||
|
/// </summary>
|
||||
|
public string ProviderKey { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 文件扩展名
|
||||
|
/// </summary>
|
||||
|
public string FileExtension { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 二进制数据
|
||||
|
/// </summary>
|
||||
|
public byte[] Bytes { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 文件大小
|
||||
|
/// </summary>
|
||||
|
public long FileSize { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 文件名称
|
||||
|
/// </summary>
|
||||
|
public string ContentType { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 文件名称
|
||||
|
/// </summary>
|
||||
|
public string FileName { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 创建时间
|
||||
|
/// </summary>
|
||||
|
public DateTime CreationTime { get; set; } |
||||
|
} |
||||
@ -1,15 +1,28 @@ |
|||||
using System.Collections.Generic; |
using Microsoft.AspNetCore.Http; |
||||
using System.Threading.Tasks; |
|
||||
using Lion.AbpPro.FileManagement.Files.Dto; |
|
||||
using Volo.Abp.Application.Dtos; |
using Volo.Abp.Application.Dtos; |
||||
using Volo.Abp.Application.Services; |
using Volo.Abp.Application.Services; |
||||
|
|
||||
namespace Lion.AbpPro.FileManagement.Files; |
namespace Lion.AbpPro.FileManagement.Files; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 文件
|
||||
|
/// </summary>
|
||||
public interface IFileAppService : IApplicationService |
public interface IFileAppService : IApplicationService |
||||
{ |
{ |
||||
Task<FileTokenOutput> GetFileTokenAsync(); |
/// <summary>
|
||||
Task CreateAsync(CreateFileInput input); |
/// 分页查询文件
|
||||
|
/// </summary>
|
||||
|
Task<PagedResultDto<PageFileObjectOutput>> PageAsync(PageFileObjectInput input); |
||||
|
|
||||
Task<PagedResultDto<PagingFileOutput>> PagingAsync(PagingFileInput input); |
/// <summary>
|
||||
|
/// 上传文件
|
||||
|
/// </summary>
|
||||
|
Task<List<UploadOutput>> UploadAsync(List<IFormFile> files); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 删除文件
|
||||
|
/// </summary>
|
||||
|
Task DeleteAsync(DeleteFileObjectInput input); |
||||
|
|
||||
|
Task<GetFileObjectOutput> GetAsync(GetFileObjectInput input); |
||||
} |
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
namespace Lion.AbpPro.FileManagement.Files; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 分页查询文件
|
||||
|
/// </summary>
|
||||
|
public class PageFileObjectInput : PagingBase |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 开始创建时间
|
||||
|
/// </summary>
|
||||
|
public DateTime? StartCreationTime { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 结束创建时间
|
||||
|
/// </summary>
|
||||
|
public DateTime? EndCreationTime { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 文件名称
|
||||
|
/// </summary>
|
||||
|
public string FileName { get; set; } |
||||
|
} |
||||
@ -0,0 +1,47 @@ |
|||||
|
namespace Lion.AbpPro.FileManagement.Files; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 分页查询文件
|
||||
|
/// </summary>
|
||||
|
public class PageFileObjectOutput |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 文件Id
|
||||
|
/// </summary>
|
||||
|
public Guid Id { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 文件Provider
|
||||
|
/// </summary>
|
||||
|
public string ProviderKey { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 文件扩展名
|
||||
|
/// </summary>
|
||||
|
public string FileExtension { get; set; } |
||||
|
|
||||
|
// /// <summary>
|
||||
|
// /// 二进制数据
|
||||
|
// /// </summary>
|
||||
|
// public byte[] Bytes { get; set; }
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 文件大小
|
||||
|
/// </summary>
|
||||
|
public long FileSize { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 文件名称
|
||||
|
/// </summary>
|
||||
|
public string ContentType { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 文件名称
|
||||
|
/// </summary>
|
||||
|
public string FileName { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 创建时间
|
||||
|
/// </summary>
|
||||
|
public DateTime CreationTime { get; set; } |
||||
|
} |
||||
@ -0,0 +1,43 @@ |
|||||
|
namespace Lion.AbpPro.FileManagement.Files; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 更新文件
|
||||
|
/// </summary>
|
||||
|
public class UpdateFileInput |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 文件Id
|
||||
|
/// </summary>
|
||||
|
public Guid Id { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 文件Provider
|
||||
|
/// </summary>
|
||||
|
[Required(ErrorMessage = "文件Provider不能为空")] |
||||
|
public string ProviderKey { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 文件扩展名
|
||||
|
/// </summary>
|
||||
|
[Required(ErrorMessage = "文件扩展名不能为空")] |
||||
|
public string FileExtension { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 二进制数据
|
||||
|
/// </summary>
|
||||
|
[Required(ErrorMessage = "二进制数据不能为空")] |
||||
|
public long Bytes { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 文件大小
|
||||
|
/// </summary>
|
||||
|
[Required(ErrorMessage = "文件大小不能为空")] |
||||
|
public long FileSize { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 文件名称
|
||||
|
/// </summary>
|
||||
|
[Required(ErrorMessage = "文件名称不能为空")] |
||||
|
public string ContentType { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 文件名称
|
||||
|
/// </summary>
|
||||
|
[Required(ErrorMessage = "文件名称不能为空")] |
||||
|
public string FileName { get; set; } |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
namespace Lion.AbpPro.FileManagement.Files; |
||||
|
|
||||
|
public class UploadOutput |
||||
|
{ |
||||
|
public Guid Id { get; set; } |
||||
|
|
||||
|
public string Name { get; set; } |
||||
|
|
||||
|
public bool Success { get; set; } |
||||
|
|
||||
|
|
||||
|
public string Path { get; set; } |
||||
|
} |
||||
@ -1,9 +1,12 @@ |
|||||
|
using Lion.AbpPro.FileManagement.Files; |
||||
|
|
||||
namespace Lion.AbpPro.FileManagement; |
namespace Lion.AbpPro.FileManagement; |
||||
|
|
||||
public class FileManagementApplicationAutoMapperProfile : Profile |
public class FileManagementApplicationAutoMapperProfile : Profile |
||||
{ |
{ |
||||
public FileManagementApplicationAutoMapperProfile() |
public FileManagementApplicationAutoMapperProfile() |
||||
{ |
{ |
||||
CreateMap<Lion.AbpPro.FileManagement.Files.File, PagingFileOutput>(); |
CreateMap<Files.FileObjectDto, PageFileObjectOutput>(); |
||||
|
CreateMap<Files.FileObjectDto, GetFileObjectOutput>(); |
||||
} |
} |
||||
} |
} |
||||
@ -1,59 +1,97 @@ |
|||||
namespace Lion.AbpPro.FileManagement.Files; |
using Lion.AbpPro.FileManagement.Provider; |
||||
|
using Microsoft.AspNetCore.Http; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
|
||||
[Authorize(FileManagementPermissions.FileManagement.Default)] |
namespace Lion.AbpPro.FileManagement.Files; |
||||
public class FileAppService : FileManagementAppService, IFileAppService |
|
||||
|
/// <summary>
|
||||
|
/// 文件
|
||||
|
/// </summary>
|
||||
|
[Authorize] |
||||
|
public class FileAppService : ApplicationService, IFileAppService |
||||
{ |
{ |
||||
private readonly IFileManager _fileManager; |
private readonly FileObjectManager _fileObjectManager; |
||||
private readonly IConfiguration _configuration; |
private readonly IFileProvider _fileProvider; |
||||
|
|
||||
public FileAppService(IFileManager fileManager, IConfiguration configuration) |
public FileAppService(FileObjectManager fileObjectManager, IFileProvider fileProvider) |
||||
{ |
{ |
||||
_fileManager = fileManager; |
_fileObjectManager = fileObjectManager; |
||||
_configuration = configuration; |
_fileProvider = fileProvider; |
||||
} |
} |
||||
|
|
||||
public virtual async Task<FileTokenOutput> GetFileTokenAsync() |
/// <summary>
|
||||
|
/// 分页查询文件
|
||||
|
/// </summary>
|
||||
|
public async Task<PagedResultDto<PageFileObjectOutput>> PageAsync(PageFileObjectInput input) |
||||
{ |
{ |
||||
// 如何设置 sts https://help.aliyun.com/document_detail/100624.html
|
var result = new PagedResultDto<PageFileObjectOutput>(); |
||||
var regionId = _configuration.GetValue<string>("AliYun:OSS:RegionId"); |
var totalCount = await _fileObjectManager.GetCountAsync(input.FileName, input.StartCreationTime, input.EndCreationTime); |
||||
var accessKeyId = _configuration.GetValue<string>("AliYun:OSS:AccessKeyId"); |
result.TotalCount = totalCount; |
||||
var accessKeySecret = _configuration.GetValue<string>("AliYun:OSS:AccessKeySecret"); |
if (totalCount <= 0) return result; |
||||
var profile = DefaultProfile.GetProfile(regionId, accessKeyId, accessKeySecret); |
var list = await _fileObjectManager.GetListAsync(input.FileName, input.StartCreationTime, input.EndCreationTime, input.PageSize, input.SkipCount); |
||||
var client = new DefaultAcsClient(profile); |
result.Items = ObjectMapper.Map<List<FileObjectDto>, List<PageFileObjectOutput>>(list); |
||||
var request = new AssumeRoleRequest() |
return result; |
||||
{ |
} |
||||
RoleArn = _configuration.GetValue<string>("AliYun:OSS:RoleArn"), |
|
||||
RoleSessionName = "Lion.AbpPro" |
|
||||
}; |
|
||||
var response = client.GetAcsResponse(request); |
|
||||
|
|
||||
var result = new FileTokenOutput() |
public async Task<List<UploadOutput>> UploadAsync(List<IFormFile> files) |
||||
|
{ |
||||
|
var result = new List<UploadOutput>(); |
||||
|
foreach (var formFile in files) |
||||
{ |
{ |
||||
AccessKeyId = response.Credentials.AccessKeyId, |
try |
||||
AccessKeySecret = response.Credentials.AccessKeySecret, |
{ |
||||
Token = response.Credentials.SecurityToken, |
var item = new UploadOutput(); |
||||
Expiration = response.Credentials.Expiration, |
// 获取文件的二进制数据
|
||||
Region = _configuration.GetValue<string>("AliYun:OSS:RegionId"), |
using var memoryStream = new MemoryStream(); |
||||
Bucket = _configuration.GetValue<string>("AliYun:OSS:ContainerName"), |
await formFile.CopyToAsync(memoryStream); |
||||
}; |
var fileBytes = memoryStream.ToArray(); |
||||
return await Task.FromResult(result); |
|
||||
|
// 这里可以对 fileBytes 进行后续处理,例如保存到数据库或文件系统等
|
||||
|
// 示例:将文件保存到数据库
|
||||
|
var updateResult = await _fileProvider.UploadAsync(new UpdateDto() |
||||
|
{ |
||||
|
FileName = formFile.FileName, |
||||
|
Bytes = fileBytes, |
||||
|
ContentType = formFile.ContentType, |
||||
|
FileSize = formFile.Length |
||||
|
}); |
||||
|
|
||||
|
result.Add(new UploadOutput() |
||||
|
{ |
||||
|
Id = updateResult.Id, |
||||
|
Name = updateResult.FileName, |
||||
|
Path = updateResult.FilePath, |
||||
|
Success = true |
||||
|
}); |
||||
|
} |
||||
|
catch (Exception e) |
||||
|
{ |
||||
|
Logger.LogError(e, "上传文件失败"); |
||||
|
result.Add(new UploadOutput() |
||||
|
{ |
||||
|
Id = Guid.Empty, |
||||
|
Name = formFile.FileName, |
||||
|
Path = string.Empty, |
||||
|
Success = false |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
} |
} |
||||
|
|
||||
[Authorize(FileManagementPermissions.FileManagement.Upload)] |
|
||||
public virtual async Task CreateAsync(CreateFileInput input) |
/// <summary>
|
||||
|
/// 删除文件
|
||||
|
/// </summary>
|
||||
|
public Task DeleteAsync(DeleteFileObjectInput input) |
||||
{ |
{ |
||||
await _fileManager.CreateAsync(input.FileName, input.FilePath); |
return _fileObjectManager.DeleteAsync(input.Id); |
||||
} |
} |
||||
|
|
||||
public virtual async Task<PagedResultDto<PagingFileOutput>> PagingAsync(PagingFileInput input) |
public async Task<GetFileObjectOutput> GetAsync(GetFileObjectInput input) |
||||
{ |
{ |
||||
var result = new PagedResultDto<PagingFileOutput>(); |
var file = await _fileObjectManager.GetAsync(input.Id); |
||||
var totalCount = await _fileManager.CountAsync(input.Filter); |
return ObjectMapper.Map<FileObjectDto, GetFileObjectOutput>(file); |
||||
result.TotalCount = totalCount; |
|
||||
if (totalCount <= 0) return result; |
|
||||
var entities = await _fileManager.PagingAsync(input.Filter, input.PageSize, |
|
||||
input.SkipCount); |
|
||||
result.Items = ObjectMapper.Map<List<File>, List<PagingFileOutput>>(entities); |
|
||||
return result; |
|
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,51 @@ |
|||||
|
namespace Lion.AbpPro.FileManagement.Files; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 文件
|
||||
|
/// </summary>
|
||||
|
public class FileObjectDto |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 主键Id
|
||||
|
/// </summary>
|
||||
|
public Guid Id { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 创建时间
|
||||
|
/// </summary>
|
||||
|
public DateTime CreationTime { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 文件Provider
|
||||
|
/// </summary>
|
||||
|
public string ProviderKey { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 文件扩展名
|
||||
|
/// </summary>
|
||||
|
public string FileExtension { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 二进制数据
|
||||
|
/// </summary>
|
||||
|
public byte[] Bytes { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 文件大小
|
||||
|
/// </summary>
|
||||
|
public long FileSize { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 文件名称
|
||||
|
/// </summary>
|
||||
|
public string ContentType { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 文件名称
|
||||
|
/// </summary>
|
||||
|
public string FileName { get; set; } |
||||
|
|
||||
|
|
||||
|
private const string CacheKeyFormat = "i:{0}"; |
||||
|
|
||||
|
public static string CalculateCacheKey(Guid id) |
||||
|
{ |
||||
|
return string.Format(CacheKeyFormat, id); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
namespace Lion.AbpPro.FileManagement.Provider; |
||||
|
|
||||
|
public class UpdateDto |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 二进制数据
|
||||
|
/// </summary>
|
||||
|
public byte[] Bytes { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 文件大小
|
||||
|
/// </summary>
|
||||
|
public long FileSize { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 文件名称
|
||||
|
/// </summary>
|
||||
|
public string ContentType { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 文件名称
|
||||
|
/// </summary>
|
||||
|
public string FileName { get; set; } |
||||
|
|
||||
|
public Dictionary<string, object> ExtraProperties { get; set; } |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
namespace Lion.AbpPro.FileManagement.Provider; |
||||
|
|
||||
|
public class UpdateResult |
||||
|
{ |
||||
|
public Guid Id { get; set; } |
||||
|
|
||||
|
public string FileName { get; set; } |
||||
|
|
||||
|
public string FilePath { get; set; } |
||||
|
|
||||
|
public UpdateResult() |
||||
|
{ |
||||
|
ExtraProperties = new Dictionary<string, object>(); |
||||
|
} |
||||
|
|
||||
|
public Dictionary<string, object> ExtraProperties { get; set; } |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using AutoMapper; |
||||
|
using Lion.AbpPro.FileManagement.Files; |
||||
|
|
||||
|
namespace Lion.AbpPro.FileManagement |
||||
|
{ |
||||
|
public class FileManagementDomainAutoMapperProfile : Profile |
||||
|
{ |
||||
|
public FileManagementDomainAutoMapperProfile() |
||||
|
{ |
||||
|
CreateMap<FileObject, FileObjectDto>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,9 +1,16 @@ |
|||||
|
using Volo.Abp.AutoMapper; |
||||
|
|
||||
namespace Lion.AbpPro.FileManagement; |
namespace Lion.AbpPro.FileManagement; |
||||
|
|
||||
[DependsOn( |
[DependsOn( |
||||
typeof(AbpDddDomainModule), |
typeof(AbpDddDomainModule), |
||||
|
typeof(AbpAutoMapperModule), |
||||
typeof(FileManagementDomainSharedModule) |
typeof(FileManagementDomainSharedModule) |
||||
)] |
)] |
||||
public class FileManagementDomainModule : AbpModule |
public class FileManagementDomainModule : AbpModule |
||||
{ |
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
Configure<AbpAutoMapperOptions>(options => { options.AddMaps<FileManagementDomainModule>(); }); |
||||
|
} |
||||
} |
} |
||||
@ -1,22 +0,0 @@ |
|||||
namespace Lion.AbpPro.FileManagement.Files; |
|
||||
|
|
||||
public class File: FullAuditedAggregateRoot<Guid>, IMultiTenant |
|
||||
{ |
|
||||
public Guid? TenantId { get; private set; } |
|
||||
|
|
||||
public string FileName { get; private set; } |
|
||||
|
|
||||
public string FilePath { get; private set; } |
|
||||
|
|
||||
private File() |
|
||||
{ |
|
||||
|
|
||||
} |
|
||||
|
|
||||
public File(Guid id, Guid? tenantId, string fileName, string filePath) : base(id) |
|
||||
{ |
|
||||
TenantId = tenantId; |
|
||||
FileName = fileName; |
|
||||
FilePath = filePath; |
|
||||
} |
|
||||
} |
|
||||
@ -1,33 +0,0 @@ |
|||||
namespace Lion.AbpPro.FileManagement.Files; |
|
||||
|
|
||||
public class FileManager : DomainService, IFileManager |
|
||||
{ |
|
||||
private readonly IFileRepository _fileRepository; |
|
||||
|
|
||||
public FileManager(IFileRepository fileRepository) |
|
||||
{ |
|
||||
_fileRepository = fileRepository; |
|
||||
} |
|
||||
|
|
||||
public virtual async Task CreateAsync(string fileName, string filePath) |
|
||||
{ |
|
||||
Check.NotNullOrWhiteSpace(fileName, nameof(fileName)); |
|
||||
Check.NotNullOrWhiteSpace(filePath, nameof(filePath)); |
|
||||
var entity = new File(GuidGenerator.Create(), CurrentTenant.Id, fileName, filePath); |
|
||||
await _fileRepository.InsertAsync(entity); |
|
||||
} |
|
||||
|
|
||||
public virtual async Task<List<File>> PagingAsync( |
|
||||
string filter = null, |
|
||||
int maxResultCount = 10, |
|
||||
int skipCount = 0) |
|
||||
{ |
|
||||
return await _fileRepository.GetPagingListAsync(filter, maxResultCount, skipCount); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
public virtual async Task<long> CountAsync(string filter = null) |
|
||||
{ |
|
||||
return await _fileRepository.GetPagingCountAsync(filter); |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,137 @@ |
|||||
|
using Lion.AbpPro.Core; |
||||
|
|
||||
|
namespace Lion.AbpPro.FileManagement.Files; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 文件
|
||||
|
/// </summary>
|
||||
|
public class FileObject : FullAuditedAggregateRoot<Guid>, IMultiTenant |
||||
|
{ |
||||
|
|
||||
|
|
||||
|
public FileObject( |
||||
|
Guid id, |
||||
|
string providerKey, |
||||
|
byte[] bytes, |
||||
|
long fileSize, |
||||
|
string contentType, |
||||
|
string fileName, |
||||
|
Guid? tenantId = null |
||||
|
) : base(id) |
||||
|
{ |
||||
|
SetProviderKey(providerKey); |
||||
|
SetBytes(bytes); |
||||
|
SetFileSize(fileSize); |
||||
|
SetContentType(contentType); |
||||
|
SetFileName(fileName); |
||||
|
TenantId = tenantId; |
||||
|
} |
||||
|
|
||||
|
public Guid? TenantId { get; private set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 文件名称
|
||||
|
/// </summary>
|
||||
|
public string FileName { get; private set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 文件名称
|
||||
|
/// </summary>
|
||||
|
public string ContentType { get; private set; } |
||||
|
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 文件大小
|
||||
|
/// </summary>
|
||||
|
public long FileSize { get; private set; } |
||||
|
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 文件扩展名
|
||||
|
/// </summary>
|
||||
|
public string FileExtension { get; private set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 二进制数据
|
||||
|
/// </summary>
|
||||
|
public byte[] Bytes { get; private set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 文件Provider
|
||||
|
/// </summary>
|
||||
|
public string ProviderKey { get; private set; } |
||||
|
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 设置文件Provider
|
||||
|
/// </summary>
|
||||
|
private void SetProviderKey(string providerKey) |
||||
|
{ |
||||
|
Guard.NotNullOrWhiteSpace(providerKey, nameof(providerKey), 128, 0); |
||||
|
ProviderKey = providerKey; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 设置文件扩展名
|
||||
|
/// </summary>
|
||||
|
private void SetFileExtension(string fileExtension) |
||||
|
{ |
||||
|
Guard.NotNullOrWhiteSpace(fileExtension, nameof(fileExtension), 36, 0); |
||||
|
FileExtension = fileExtension; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 设置二进制数据
|
||||
|
/// </summary>
|
||||
|
private void SetBytes(byte[] bytes) |
||||
|
{ |
||||
|
Bytes = bytes; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 设置文件大小
|
||||
|
/// </summary>
|
||||
|
private void SetFileSize(long fileSize) |
||||
|
{ |
||||
|
FileSize = fileSize; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 设置文件名称
|
||||
|
/// </summary>
|
||||
|
private void SetContentType(string contentType) |
||||
|
{ |
||||
|
Guard.NotNullOrWhiteSpace(contentType, nameof(contentType), 128, 0); |
||||
|
ContentType = contentType; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 设置文件名称
|
||||
|
/// </summary>
|
||||
|
private void SetFileName(string fileName) |
||||
|
{ |
||||
|
Guard.NotNullOrWhiteSpace(fileName, nameof(fileName), 128, 0); |
||||
|
SetFileExtension(Path.GetExtension(fileName)); |
||||
|
FileName = fileName; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 更新文件
|
||||
|
/// </summary>
|
||||
|
public void Update( |
||||
|
string providerKey, |
||||
|
string fileExtension, |
||||
|
byte[] bytes, |
||||
|
long fileSize, |
||||
|
string contentType, |
||||
|
string fileName |
||||
|
) |
||||
|
{ |
||||
|
SetProviderKey(providerKey); |
||||
|
SetFileExtension(fileExtension); |
||||
|
SetBytes(bytes); |
||||
|
SetFileSize(fileSize); |
||||
|
SetContentType(contentType); |
||||
|
SetFileName(fileName); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,65 @@ |
|||||
|
using Volo.Abp.ObjectMapping; |
||||
|
|
||||
|
namespace Lion.AbpPro.FileManagement.Files; |
||||
|
|
||||
|
public class FileObjectManager : DomainService |
||||
|
{ |
||||
|
private readonly IFileObjectRepository _fileObjectRepository; |
||||
|
private readonly IObjectMapper _objectMapper; |
||||
|
private readonly ICurrentTenant _currentTenant; |
||||
|
|
||||
|
public FileObjectManager(IFileObjectRepository iIFileObjectRepository, IObjectMapper objectMapper, ICurrentTenant currentTenant) |
||||
|
{ |
||||
|
_fileObjectRepository = iIFileObjectRepository; |
||||
|
_objectMapper = objectMapper; |
||||
|
_currentTenant = currentTenant; |
||||
|
} |
||||
|
|
||||
|
public async Task<List<FileObjectDto>> GetListAsync(string fileName, DateTime? startDateTime = null, DateTime? endDateTime = null, int maxResultCount = 10, int skipCount = 0) |
||||
|
{ |
||||
|
return await _fileObjectRepository.GetListAsync(fileName, startDateTime, endDateTime, maxResultCount, skipCount); |
||||
|
} |
||||
|
|
||||
|
public async Task<long> GetCountAsync(string fileName, DateTime? startDateTime = null, DateTime? endDateTime = null) |
||||
|
{ |
||||
|
return await _fileObjectRepository.GetCountAsync(fileName, startDateTime, endDateTime); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 创建文件
|
||||
|
/// </summary>
|
||||
|
public async Task<FileObjectDto> CreateAsync( |
||||
|
Guid id, |
||||
|
string fileName, |
||||
|
byte[] bytes, |
||||
|
long fileSize, |
||||
|
string contentType, |
||||
|
string providerKey |
||||
|
) |
||||
|
{ |
||||
|
var entity = new FileObject(id, providerKey, bytes, fileSize, contentType, fileName, _currentTenant.Id); |
||||
|
entity = await _fileObjectRepository.InsertAsync(entity); |
||||
|
return _objectMapper.Map<FileObject, FileObjectDto>(entity); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 删除文件
|
||||
|
/// </summary>
|
||||
|
public async Task DeleteAsync(Guid id) |
||||
|
{ |
||||
|
var entity = await _fileObjectRepository.FindAsync(id); |
||||
|
if (entity == null) throw new UserFriendlyException($"文件不存在"); |
||||
|
await _fileObjectRepository.DeleteAsync(entity); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 删除文件
|
||||
|
/// </summary>
|
||||
|
public async Task<FileObjectDto> GetAsync(Guid id) |
||||
|
{ |
||||
|
var entity = await _fileObjectRepository.FindAsync(id); |
||||
|
if (entity == null) throw new UserFriendlyException($"文件不存在"); |
||||
|
return _objectMapper.Map<FileObject, FileObjectDto>(entity); |
||||
|
} |
||||
|
} |
||||
@ -1,15 +0,0 @@ |
|||||
namespace Lion.AbpPro.FileManagement.Files; |
|
||||
|
|
||||
public interface IFileManager |
|
||||
{ |
|
||||
Task CreateAsync(string fileName, string filePath); |
|
||||
|
|
||||
Task<List<File>> PagingAsync( |
|
||||
string filter = null, |
|
||||
int maxResultCount = 10, |
|
||||
int skipCount = 0); |
|
||||
|
|
||||
Task<long> CountAsync(string filter = null); |
|
||||
IAbpLazyServiceProvider LazyServiceProvider { get; set; } |
|
||||
IServiceProvider ServiceProvider { get; set; } |
|
||||
} |
|
||||
@ -0,0 +1,8 @@ |
|||||
|
namespace Lion.AbpPro.FileManagement.Files; |
||||
|
|
||||
|
public interface IFileObjectRepository : IBasicRepository<FileObject, Guid> |
||||
|
{ |
||||
|
Task<List<FileObjectDto>> GetListAsync(string fileName, DateTime? startDateTime = null, DateTime? endDateTime = null, int maxResultCount = 10, int skipCount = 0); |
||||
|
|
||||
|
Task<long> GetCountAsync(string fileName, DateTime? startDateTime = null, DateTime? endDateTime = null); |
||||
|
} |
||||
@ -1,13 +0,0 @@ |
|||||
namespace Lion.AbpPro.FileManagement.Files; |
|
||||
|
|
||||
public interface IFileRepository: IRepository<File, Guid> |
|
||||
{ |
|
||||
Task<List<File>> GetPagingListAsync( |
|
||||
string filter = null, |
|
||||
int maxResultCount = 10, |
|
||||
int skipCount = 0, |
|
||||
CancellationToken cancellationToken = default); |
|
||||
|
|
||||
Task<long> GetPagingCountAsync(string filter = null, |
|
||||
CancellationToken cancellationToken = default); |
|
||||
} |
|
||||
@ -0,0 +1,30 @@ |
|||||
|
using Lion.AbpPro.FileManagement.Files; |
||||
|
using Volo.Abp.Guids; |
||||
|
|
||||
|
namespace Lion.AbpPro.FileManagement.Provider; |
||||
|
|
||||
|
public class DatabaseFileProvider : IFileProvider, ITransientDependency |
||||
|
{ |
||||
|
public const string Name = nameof(DatabaseFileProvider); |
||||
|
private readonly FileObjectManager _fileObjectManager; |
||||
|
private readonly IGuidGenerator _guidGenerator; |
||||
|
|
||||
|
public DatabaseFileProvider(FileObjectManager fileObjectManager, IGuidGenerator guidGenerator) |
||||
|
{ |
||||
|
_fileObjectManager = fileObjectManager; |
||||
|
_guidGenerator = guidGenerator; |
||||
|
} |
||||
|
|
||||
|
public async Task<UpdateResult> UploadAsync(UpdateDto input) |
||||
|
{ |
||||
|
var id = _guidGenerator.Create(); |
||||
|
var fileName = id + "_" + input.FileName; |
||||
|
await _fileObjectManager.CreateAsync(id, fileName, input.Bytes, input.FileSize, input.ContentType, Name); |
||||
|
return new UpdateResult() |
||||
|
{ |
||||
|
Id = id, |
||||
|
FileName = fileName, |
||||
|
FilePath = fileName |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
namespace Lion.AbpPro.FileManagement.Provider; |
||||
|
|
||||
|
public interface IFileProvider |
||||
|
{ |
||||
|
Task<UpdateResult> UploadAsync(UpdateDto input); |
||||
|
} |
||||
@ -0,0 +1,49 @@ |
|||||
|
using System.Linq.Dynamic.Core; |
||||
|
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; |
||||
|
using Volo.Abp.EntityFrameworkCore; |
||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
|
||||
|
namespace Lion.AbpPro.FileManagement.EntityFrameworkCore.Files; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 文件 仓储Ef core 实现
|
||||
|
/// </summary>
|
||||
|
public class EfCoreFileObjectRepository : |
||||
|
EfCoreRepository<FileManagementDbContext, FileObject, Guid>, |
||||
|
IFileObjectRepository |
||||
|
{ |
||||
|
public EfCoreFileObjectRepository(IDbContextProvider<FileManagementDbContext> dbContextProvider) : base(dbContextProvider) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public async Task<List<FileObjectDto>> GetListAsync(string fileName, DateTime? startDateTime = null, DateTime? endDateTime = null,int maxResultCount = 10, int skipCount = 0) |
||||
|
{ |
||||
|
return await (await GetDbSetAsync()) |
||||
|
.WhereIf(fileName.IsNotNullOrWhiteSpace(),e=>e.FileName.Contains(fileName)) |
||||
|
.WhereIf(startDateTime.HasValue, e => e.CreationTime >= startDateTime.Value) |
||||
|
.WhereIf(endDateTime.HasValue, e => e.CreationTime <= endDateTime.Value) |
||||
|
.OrderByDescending(e => e.CreationTime) |
||||
|
.PageBy(skipCount, maxResultCount) |
||||
|
.Select(e => new FileObjectDto |
||||
|
{ |
||||
|
|
||||
|
Id = e.Id, |
||||
|
CreationTime = e.CreationTime, |
||||
|
FileName = e.FileName, |
||||
|
FileSize = e.FileSize, |
||||
|
FileExtension = e.FileExtension, |
||||
|
ContentType = e.ContentType, |
||||
|
ProviderKey = e.ProviderKey |
||||
|
}) // 选择指定字段
|
||||
|
.ToListAsync(); |
||||
|
} |
||||
|
|
||||
|
public async Task<long> GetCountAsync(string fileName, DateTime? startDateTime = null, DateTime? endDateTime = null) |
||||
|
{ |
||||
|
return await (await GetDbSetAsync()) |
||||
|
.WhereIf(fileName.IsNotNullOrWhiteSpace(),e=>e.FileName.Contains(fileName)) |
||||
|
.WhereIf(startDateTime.HasValue, e => e.CreationTime >= startDateTime.Value) |
||||
|
.WhereIf(endDateTime.HasValue, e => e.CreationTime <= endDateTime.Value) |
||||
|
.CountAsync(); |
||||
|
} |
||||
|
} |
||||
@ -1,31 +0,0 @@ |
|||||
namespace Lion.AbpPro.FileManagement.EntityFrameworkCore.Files; |
|
||||
|
|
||||
public class EfCoreFileRepository: EfCoreRepository<IFileManagementDbContext,Lion.AbpPro.FileManagement.Files.File, Guid>, IFileRepository |
|
||||
{ |
|
||||
public EfCoreFileRepository(IDbContextProvider<IFileManagementDbContext> dbContextProvider) : base(dbContextProvider) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
public async Task<List<Lion.AbpPro.FileManagement.Files.File>> GetPagingListAsync( |
|
||||
string filter = null, |
|
||||
int maxResultCount = 10, |
|
||||
int skipCount = 0, |
|
||||
CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
return await (await GetDbSetAsync()) |
|
||||
.WhereIf(!filter.IsNullOrWhiteSpace(), |
|
||||
e => (e.FileName.Contains(filter))) |
|
||||
.OrderByDescending(e => e.CreationTime) |
|
||||
.PageBy(skipCount, maxResultCount) |
|
||||
.ToListAsync(GetCancellationToken(cancellationToken)); |
|
||||
} |
|
||||
|
|
||||
public async Task<long> GetPagingCountAsync(string filter = null, |
|
||||
CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
return await (await GetDbSetAsync()) |
|
||||
.WhereIf(!filter.IsNullOrWhiteSpace(), |
|
||||
e => (e.FileName.Contains(filter))) |
|
||||
.CountAsync(cancellationToken: cancellationToken); |
|
||||
} |
|
||||
} |
|
||||
File diff suppressed because it is too large
@ -0,0 +1,61 @@ |
|||||
|
using System; |
||||
|
using Microsoft.EntityFrameworkCore.Migrations; |
||||
|
|
||||
|
#nullable disable |
||||
|
|
||||
|
namespace Lion.AbpPro.Migrations |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
public partial class _102 : Migration |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
protected override void Up(MigrationBuilder migrationBuilder) |
||||
|
{ |
||||
|
migrationBuilder.CreateTable( |
||||
|
name: "AbpFileObjects", |
||||
|
columns: table => new |
||||
|
{ |
||||
|
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"), |
||||
|
TenantId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"), |
||||
|
FileName = table.Column<string>(type: "varchar(128)", maxLength: 128, nullable: false, comment: "文件名称") |
||||
|
.Annotation("MySql:CharSet", "utf8mb4"), |
||||
|
ContentType = table.Column<string>(type: "varchar(128)", maxLength: 128, nullable: false, comment: "文件名称") |
||||
|
.Annotation("MySql:CharSet", "utf8mb4"), |
||||
|
FileSize = table.Column<long>(type: "bigint", nullable: false, comment: "文件大小"), |
||||
|
FileExtension = table.Column<string>(type: "varchar(36)", maxLength: 36, nullable: false, comment: "文件扩展名") |
||||
|
.Annotation("MySql:CharSet", "utf8mb4"), |
||||
|
Bytes = table.Column<byte[]>(type: "longblob", nullable: true, comment: "二进制数据"), |
||||
|
ProviderKey = table.Column<string>(type: "varchar(128)", maxLength: 128, nullable: false, comment: "文件Provider") |
||||
|
.Annotation("MySql:CharSet", "utf8mb4"), |
||||
|
ExtraProperties = table.Column<string>(type: "longtext", nullable: false) |
||||
|
.Annotation("MySql:CharSet", "utf8mb4"), |
||||
|
ConcurrencyStamp = table.Column<string>(type: "varchar(40)", maxLength: 40, nullable: false) |
||||
|
.Annotation("MySql:CharSet", "utf8mb4"), |
||||
|
CreationTime = table.Column<DateTime>(type: "datetime(6)", nullable: false), |
||||
|
CreatorId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"), |
||||
|
LastModificationTime = table.Column<DateTime>(type: "datetime(6)", nullable: true), |
||||
|
LastModifierId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"), |
||||
|
IsDeleted = table.Column<bool>(type: "tinyint(1)", nullable: false, defaultValue: false), |
||||
|
DeleterId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"), |
||||
|
DeletionTime = table.Column<DateTime>(type: "datetime(6)", nullable: true) |
||||
|
}, |
||||
|
constraints: table => |
||||
|
{ |
||||
|
table.PrimaryKey("PK_AbpFileObjects", x => x.Id); |
||||
|
}) |
||||
|
.Annotation("MySql:CharSet", "utf8mb4"); |
||||
|
|
||||
|
migrationBuilder.CreateIndex( |
||||
|
name: "IX_AbpFileObjects_FileName", |
||||
|
table: "AbpFileObjects", |
||||
|
column: "FileName"); |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
protected override void Down(MigrationBuilder migrationBuilder) |
||||
|
{ |
||||
|
migrationBuilder.DropTable( |
||||
|
name: "AbpFileObjects"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue