40 changed files with 1301 additions and 5 deletions
@ -0,0 +1,16 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.Ddd.Application" Version="3.0.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.FileManagement.Domain.Shared\LINGYUN.Abp.FileManagement.Domain.Shared.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,11 @@ |
|||||
|
using Volo.Abp.Application; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.FileManagement |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpDddApplicationModule))] |
||||
|
public class AbpFileManagementApplicationContractsModule : AbpModule |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
|
namespace LINGYUN.Abp.FileManagement |
||||
|
{ |
||||
|
public class FileCopyOrMoveDto |
||||
|
{ |
||||
|
[Required] |
||||
|
[StringLength(255)] |
||||
|
public string Path { get; set; } |
||||
|
|
||||
|
[Required] |
||||
|
[StringLength(255)] |
||||
|
public string Name { get; set; } |
||||
|
|
||||
|
[Required] |
||||
|
[StringLength(255)] |
||||
|
public string ToPath { get; set; } |
||||
|
|
||||
|
[StringLength(255)] |
||||
|
public string ToName { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,39 @@ |
|||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using Volo.Abp.Auditing; |
||||
|
|
||||
|
namespace LINGYUN.Abp.FileManagement |
||||
|
{ |
||||
|
public class FileCreateDto |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 文件名
|
||||
|
/// </summary>
|
||||
|
[Required] |
||||
|
[StringLength(255)] |
||||
|
public string Name { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 文件路径
|
||||
|
/// </summary>
|
||||
|
[StringLength(255)] |
||||
|
public string Path { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 文件数据,前端无需传递此参数,由控制器传递
|
||||
|
/// </summary>
|
||||
|
[DisableAuditing] |
||||
|
public byte[] Data { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 当前字节数
|
||||
|
/// </summary>
|
||||
|
[Required] |
||||
|
public int CurrentByte { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 最大字节数
|
||||
|
/// </summary>
|
||||
|
[Required] |
||||
|
public int TotalByte { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 是否覆盖文件
|
||||
|
/// </summary>
|
||||
|
public bool Rewrite { get; set; } = false; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
|
namespace LINGYUN.Abp.FileManagement |
||||
|
{ |
||||
|
public class FileDeleteDto |
||||
|
{ |
||||
|
[Required] |
||||
|
[StringLength(255)] |
||||
|
public string Path { get; set; } |
||||
|
|
||||
|
[Required] |
||||
|
[StringLength(255)] |
||||
|
public string Name { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace LINGYUN.Abp.FileManagement |
||||
|
{ |
||||
|
public class FileSystemDto |
||||
|
{ |
||||
|
public FileSystemType Type { get; set; } |
||||
|
public string Name { get; set; } |
||||
|
public string Parent { get; set; } |
||||
|
public long? Size { get; set; } |
||||
|
public DateTime CreationTime { get; set; } |
||||
|
public DateTime? LastModificationTime { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
|
namespace LINGYUN.Abp.FileManagement |
||||
|
{ |
||||
|
public class FileSystemGetDto |
||||
|
{ |
||||
|
[Required] |
||||
|
[StringLength(255)] |
||||
|
public string Path { get; set; } |
||||
|
|
||||
|
[Required] |
||||
|
[StringLength(255)] |
||||
|
public string Name { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
namespace LINGYUN.Abp.FileManagement |
||||
|
{ |
||||
|
public enum FileSystemType |
||||
|
{ |
||||
|
Folder = 0, |
||||
|
File = 1 |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
|
namespace LINGYUN.Abp.FileManagement |
||||
|
{ |
||||
|
public class FileSystemUpdateDto |
||||
|
{ |
||||
|
[Required] |
||||
|
[StringLength(255)] |
||||
|
public string NewName { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
|
namespace LINGYUN.Abp.FileManagement |
||||
|
{ |
||||
|
public class FolderCopyDto |
||||
|
{ |
||||
|
[Required] |
||||
|
[StringLength(255)] |
||||
|
public string CopyToPath { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
|
namespace LINGYUN.Abp.FileManagement |
||||
|
{ |
||||
|
public class FolderCreateDto |
||||
|
{ |
||||
|
[Required] |
||||
|
[StringLength(255)] |
||||
|
public string Path { get; set; } |
||||
|
|
||||
|
public string Parent { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
|
namespace LINGYUN.Abp.FileManagement |
||||
|
{ |
||||
|
public class FolderMoveDto |
||||
|
{ |
||||
|
[Required] |
||||
|
[StringLength(255)] |
||||
|
public string MoveToPath { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace LINGYUN.Abp.FileManagement |
||||
|
{ |
||||
|
public class GetFileSystemListDto : PagedAndSortedResultRequestDto |
||||
|
{ |
||||
|
// TODO: Windows最大路径长度,超过了貌似也无效了吧
|
||||
|
[StringLength(255)] |
||||
|
public string Parent { get; set; } |
||||
|
|
||||
|
public string Filter { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,35 @@ |
|||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using System.IO; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
using Volo.Abp.Application.Services; |
||||
|
|
||||
|
namespace LINGYUN.Abp.FileManagement |
||||
|
{ |
||||
|
public interface IFileSystemAppService : IApplicationService |
||||
|
{ |
||||
|
Task<FileSystemDto> GetAsync(FileSystemGetDto input); |
||||
|
|
||||
|
Task<PagedResultDto<FileSystemDto>> GetListAsync(GetFileSystemListDto input); |
||||
|
|
||||
|
Task CreateFolderAsync(FolderCreateDto input); |
||||
|
|
||||
|
Task<FileSystemDto> UpdateAsync([Required, StringLength(255)] string name, FileSystemUpdateDto input); |
||||
|
|
||||
|
Task DeleteFolderAsync([Required, StringLength(255)] string path); |
||||
|
|
||||
|
Task MoveFolderAsync([Required, StringLength(255)] string path, FolderMoveDto input); |
||||
|
|
||||
|
Task CopyFolderAsync([Required, StringLength(255)] string path, FolderCopyDto input); |
||||
|
|
||||
|
Task CreateFileAsync(FileCreateDto input); |
||||
|
|
||||
|
Task DeleteFileAsync(FileDeleteDto input); |
||||
|
|
||||
|
Task MoveFileAsync(FileCopyOrMoveDto input); |
||||
|
|
||||
|
Task CopyFileAsync(FileCopyOrMoveDto input); |
||||
|
|
||||
|
Task<Stream> DownloadFileAsync(FileSystemGetDto input); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
using LINGYUN.Abp.FileManagement.Localization; |
||||
|
using Volo.Abp.Authorization.Permissions; |
||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace LINGYUN.Abp.FileManagement.Permissions |
||||
|
{ |
||||
|
public class AbpFileManagementPermissionDefinitionProvider : PermissionDefinitionProvider |
||||
|
{ |
||||
|
public override void Define(IPermissionDefinitionContext context) |
||||
|
{ |
||||
|
var fileManagement = context.AddGroup(AbpFileManagementPermissions.GroupName, L("Permission:FileManagement")); |
||||
|
|
||||
|
var fileSystem = fileManagement.AddPermission(AbpFileManagementPermissions.FileSystem.Default, L("Permission:FileSystem")); |
||||
|
fileSystem.AddChild(AbpFileManagementPermissions.FileSystem.Create, L("Permission:CreateFolder")); |
||||
|
fileSystem.AddChild(AbpFileManagementPermissions.FileSystem.Delete, L("Permission:DeleteFolder")); |
||||
|
fileSystem.AddChild(AbpFileManagementPermissions.FileSystem.Update, L("Permission:UpdateFolder")); |
||||
|
fileSystem.AddChild(AbpFileManagementPermissions.FileSystem.Copy, L("Permission:CopyFolder")); |
||||
|
fileSystem.AddChild(AbpFileManagementPermissions.FileSystem.Move, L("Permission:MoveFolder")); |
||||
|
|
||||
|
var fileManager = fileSystem.AddChild(AbpFileManagementPermissions.FileSystem.FileManager.Default, L("Permission:FileManager")); |
||||
|
fileManager.AddChild(AbpFileManagementPermissions.FileSystem.FileManager.Create, L("Permission:AppendFile")); |
||||
|
fileManager.AddChild(AbpFileManagementPermissions.FileSystem.FileManager.Update, L("Permission:UpdateFile")); |
||||
|
fileManager.AddChild(AbpFileManagementPermissions.FileSystem.FileManager.Delete, L("Permission:DeleteFile")); |
||||
|
fileManager.AddChild(AbpFileManagementPermissions.FileSystem.FileManager.Copy, L("Permission:CopyFile")); |
||||
|
fileManager.AddChild(AbpFileManagementPermissions.FileSystem.FileManager.Move, L("Permission:MoveFile")); |
||||
|
fileManager.AddChild(AbpFileManagementPermissions.FileSystem.FileManager.Download, L("Permission:DownloadFile")); |
||||
|
} |
||||
|
|
||||
|
private static LocalizableString L(string name) |
||||
|
{ |
||||
|
return LocalizableString.Create<AbpFileManagementResource>(name); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
namespace LINGYUN.Abp.FileManagement.Permissions |
||||
|
{ |
||||
|
public class AbpFileManagementPermissions |
||||
|
{ |
||||
|
public const string GroupName = "Abp.FileManagement"; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 文件系统
|
||||
|
/// </summary>
|
||||
|
public class FileSystem |
||||
|
{ |
||||
|
public const string Default = GroupName + ".FileSystem"; |
||||
|
|
||||
|
public const string Create = Default + ".Create"; |
||||
|
|
||||
|
public const string Delete = Default + ".Delete"; |
||||
|
|
||||
|
public const string Update = Default + ".Update"; |
||||
|
|
||||
|
public const string Copy = Default + ".Copy"; |
||||
|
|
||||
|
public const string Move = Default + ".Move"; |
||||
|
/// <summary>
|
||||
|
/// 文件管理
|
||||
|
/// </summary>
|
||||
|
public class FileManager |
||||
|
{ |
||||
|
public const string Default = FileSystem.Default + ".FileManager"; |
||||
|
|
||||
|
public const string Create = Default + ".Create"; |
||||
|
|
||||
|
public const string Copy = Default + ".Copy"; |
||||
|
|
||||
|
public const string Delete = Default + ".Delete"; |
||||
|
|
||||
|
public const string Update = Default + ".Update"; |
||||
|
|
||||
|
public const string Move = Default + ".Move"; |
||||
|
|
||||
|
public const string Download = Default + ".Download"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.FileManagement.Application.Contracts\LINGYUN.Abp.FileManagement.Application.Contracts.csproj" /> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.FileManagement.Domain\LINGYUN.Abp.FileManagement.Domain.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,12 @@ |
|||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.FileManagement |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpFileManagementDomainModule), |
||||
|
typeof(AbpFileManagementApplicationContractsModule))] |
||||
|
public class AbpFileManagementApplicationModule : AbpModule |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
using Volo.Abp.Application.Services; |
||||
|
|
||||
|
namespace LINGYUN.Abp.FileManagement |
||||
|
{ |
||||
|
public class FileManagementApplicationServiceBase : ApplicationService |
||||
|
{ |
||||
|
protected FileManagementApplicationServiceBase() |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,392 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using System.IO; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
using Volo.Abp.BlobStoring; |
||||
|
using Volo.Abp.BlobStoring.FileSystem; |
||||
|
|
||||
|
namespace LINGYUN.Abp.FileManagement |
||||
|
{ |
||||
|
public class FileSystemAppService : FileManagementApplicationServiceBase, IFileSystemAppService |
||||
|
{ |
||||
|
protected IBlobContainer<FileSystemContainer> BlobContainer { get; } |
||||
|
protected IBlobContainerConfigurationProvider BlobContainerConfigurationProvider { get; } |
||||
|
public FileSystemAppService( |
||||
|
IBlobContainer<FileSystemContainer> blobContainer, |
||||
|
IBlobContainerConfigurationProvider blobContainerConfigurationProvider) |
||||
|
{ |
||||
|
BlobContainer = blobContainer; |
||||
|
BlobContainerConfigurationProvider = blobContainerConfigurationProvider; |
||||
|
} |
||||
|
|
||||
|
public virtual Task CopyFileAsync(FileCopyOrMoveDto input) |
||||
|
{ |
||||
|
string fileSystemPath = GetFileSystemPath(input.Path); |
||||
|
var fileFullName = Path.Combine(fileSystemPath, input.Name); |
||||
|
if (!File.Exists(fileFullName)) |
||||
|
{ |
||||
|
throw new UserFriendlyException("指定的文件不存在!"); |
||||
|
} |
||||
|
var copyToFilePath = GetFileSystemPath(input.ToPath); |
||||
|
var copyToFileFullName = Path.Combine(copyToFilePath, input.ToName ?? input.Name); |
||||
|
if (File.Exists(copyToFileFullName)) |
||||
|
{ |
||||
|
throw new UserFriendlyException("指定的路径中已经有相同的文件名存在!"); |
||||
|
} |
||||
|
|
||||
|
File.Copy(fileFullName, copyToFileFullName); |
||||
|
|
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
|
||||
|
public virtual Task CopyFolderAsync([Required, StringLength(255)] string path, FolderCopyDto input) |
||||
|
{ |
||||
|
string fileSystemPath = GetFileSystemPath(path); |
||||
|
if (!Directory.Exists(fileSystemPath)) |
||||
|
{ |
||||
|
throw new UserFriendlyException("指定目录不存在!"); |
||||
|
} |
||||
|
var copyToFilePath = GetFileSystemPath(input.CopyToPath); |
||||
|
if (Directory.Exists(copyToFilePath)) |
||||
|
{ |
||||
|
throw new UserFriendlyException("指定的路径中已经有同名的目录存在!"); |
||||
|
} |
||||
|
|
||||
|
CopyDirectory(fileSystemPath, copyToFilePath); |
||||
|
|
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task CreateFileAsync(FileCreateDto input) |
||||
|
{ |
||||
|
string fileSystemPath = GetFileSystemPath(input.Path); |
||||
|
var fileFullName = Path.Combine(fileSystemPath, input.Name); |
||||
|
if (File.Exists(fileFullName) && !input.Rewrite) |
||||
|
{ |
||||
|
throw new UserFriendlyException("指定的文件已经存在!"); |
||||
|
} |
||||
|
await BlobContainer.SaveAsync(input.Name, input.Data, input.Rewrite); |
||||
|
} |
||||
|
|
||||
|
public virtual Task CreateFolderAsync(FolderCreateDto input) |
||||
|
{ |
||||
|
string fileSystemPath = GetFileSystemBashPath(); |
||||
|
if (!input.Parent.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
fileSystemPath = GetFileSystemPath(input.Parent); |
||||
|
} |
||||
|
var newFloderPath = Path.Combine(fileSystemPath, input.Path); |
||||
|
if (Directory.Exists(newFloderPath)) |
||||
|
{ |
||||
|
throw new UserFriendlyException("指定目录已经存在!"); |
||||
|
} |
||||
|
Directory.CreateDirectory(newFloderPath); |
||||
|
|
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
|
||||
|
public virtual Task DeleteFileAsync(FileDeleteDto input) |
||||
|
{ |
||||
|
var fileSystemPath = GetFileSystemPath(input.Path); |
||||
|
fileSystemPath = Path.Combine(fileSystemPath, input.Name); |
||||
|
if (File.Exists(fileSystemPath)) |
||||
|
{ |
||||
|
File.Delete(fileSystemPath); |
||||
|
} |
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
|
||||
|
public virtual Task DeleteFolderAsync([Required, StringLength(255)] string path) |
||||
|
{ |
||||
|
string fileSystemPath = GetFileSystemPath(path); |
||||
|
if (!Directory.Exists(fileSystemPath)) |
||||
|
{ |
||||
|
throw new UserFriendlyException("指定目录不存在!"); |
||||
|
} |
||||
|
var fileSystemChildrenPath = Directory.GetDirectories(fileSystemPath); |
||||
|
if (fileSystemChildrenPath.Length > 0) |
||||
|
{ |
||||
|
throw new UserFriendlyException("指定的目录不为空,不可删除此目录!"); |
||||
|
} |
||||
|
var fileSystemPathFiles = Directory.GetFiles(fileSystemPath); |
||||
|
if (fileSystemPathFiles.Length > 0) |
||||
|
{ |
||||
|
throw new UserFriendlyException("指定的目录不为空,不可删除此目录!"); |
||||
|
} |
||||
|
Directory.Delete(fileSystemPath); |
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<Stream> DownloadFileAsync(FileSystemGetDto input) |
||||
|
{ |
||||
|
var fileSystemPath = GetFileSystemPath(input.Path); |
||||
|
fileSystemPath = Path.Combine(fileSystemPath, input.Name); |
||||
|
var blobName = GetFileSystemRelativePath(fileSystemPath); |
||||
|
|
||||
|
return await BlobContainer.GetAsync(blobName); |
||||
|
} |
||||
|
|
||||
|
public virtual Task<FileSystemDto> GetAsync(FileSystemGetDto input) |
||||
|
{ |
||||
|
var fileSystemPath = GetFileSystemPath(input.Path); |
||||
|
fileSystemPath = Path.Combine(fileSystemPath, input.Name); |
||||
|
if (File.Exists(fileSystemPath)) |
||||
|
{ |
||||
|
var fileInfo = new FileInfo(fileSystemPath); |
||||
|
var fileSystem = new FileSystemDto |
||||
|
{ |
||||
|
Type = FileSystemType.File, |
||||
|
Name = fileInfo.Name, |
||||
|
Size = fileInfo.Length, |
||||
|
CreationTime = fileInfo.CreationTime, |
||||
|
LastModificationTime = fileInfo.LastWriteTime |
||||
|
}; |
||||
|
if (fileInfo.Directory?.Parent != null && !fileInfo.Directory.Parent.Name.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
fileSystem.Parent = GetFileSystemRelativePath(fileInfo.Directory.Parent.FullName); |
||||
|
} |
||||
|
return Task.FromResult(fileSystem); |
||||
|
} |
||||
|
if (Directory.Exists(fileSystemPath)) |
||||
|
{ |
||||
|
var directoryInfo = new DirectoryInfo(fileSystemPath); |
||||
|
var fileSystem = new FileSystemDto |
||||
|
{ |
||||
|
Type = FileSystemType.Folder, |
||||
|
Name = directoryInfo.Name, |
||||
|
CreationTime = directoryInfo.CreationTime, |
||||
|
LastModificationTime = directoryInfo.LastWriteTime |
||||
|
}; |
||||
|
if (directoryInfo.Parent != null && !directoryInfo.Parent.Name.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
fileSystem.Parent = GetFileSystemRelativePath(directoryInfo.Parent.FullName); |
||||
|
} |
||||
|
return Task.FromResult(fileSystem); |
||||
|
} |
||||
|
throw new UserFriendlyException("文件或目录不存在!"); |
||||
|
} |
||||
|
|
||||
|
public virtual Task<PagedResultDto<FileSystemDto>> GetListAsync(GetFileSystemListDto input) |
||||
|
{ |
||||
|
List<FileSystemDto> fileSystems = new List<FileSystemDto>(); |
||||
|
|
||||
|
string fileSystemPath = GetFileSystemBashPath(); |
||||
|
if (!input.Parent.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
fileSystemPath = GetFileSystemPath(input.Parent); |
||||
|
} |
||||
|
var directoryInfo = new DirectoryInfo(fileSystemPath); |
||||
|
// 查询全部
|
||||
|
var fileSystemInfos = directoryInfo.GetFileSystemInfos(); |
||||
|
// 指定搜索条件查询目录
|
||||
|
FileSystemInfo[] fileSystemInfoSearchChildren;// = directoryInfo.GetDirectories(input.Filter ?? "*", SearchOption.TopDirectoryOnly);
|
||||
|
if (!input.Filter.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
var searchPattern = $"*{input.Filter}*"; |
||||
|
fileSystemInfoSearchChildren = directoryInfo.GetFileSystemInfos(searchPattern); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
fileSystemInfoSearchChildren = directoryInfo.GetFileSystemInfos(); |
||||
|
} |
||||
|
|
||||
|
fileSystemInfoSearchChildren = fileSystemInfoSearchChildren |
||||
|
.Skip((input.SkipCount - 1) * input.MaxResultCount) |
||||
|
.Take(input.MaxResultCount) |
||||
|
.ToArray(); |
||||
|
|
||||
|
foreach (var fileSystemInfo in fileSystemInfoSearchChildren) |
||||
|
{ |
||||
|
var fileSystem = new FileSystemDto |
||||
|
{ |
||||
|
Name = fileSystemInfo.Name, |
||||
|
CreationTime = fileSystemInfo.CreationTime, |
||||
|
LastModificationTime = fileSystemInfo.LastWriteTime, |
||||
|
}; |
||||
|
if (fileSystemInfo is FileInfo fileInfo) |
||||
|
{ |
||||
|
fileSystem.Type = FileSystemType.File; |
||||
|
fileSystem.Size = fileInfo.Length; |
||||
|
if (fileInfo.Directory?.Parent != null && !fileInfo.Directory.Parent.Name.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
fileSystem.Parent = GetFileSystemRelativePath(fileInfo.Directory.Parent.FullName); |
||||
|
} |
||||
|
} |
||||
|
else if (fileSystemInfo is DirectoryInfo directory) |
||||
|
{ |
||||
|
fileSystem.Type = FileSystemType.Folder; |
||||
|
if (directory.Parent != null && !directory.Parent.Name.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
fileSystem.Parent = GetFileSystemRelativePath(directory.Parent.FullName); |
||||
|
} |
||||
|
} |
||||
|
fileSystems.Add(fileSystem); |
||||
|
} |
||||
|
|
||||
|
return Task.FromResult(new PagedResultDto<FileSystemDto>( |
||||
|
fileSystemInfos.Length, fileSystems |
||||
|
)); |
||||
|
} |
||||
|
|
||||
|
public virtual Task MoveFileAsync(FileCopyOrMoveDto input) |
||||
|
{ |
||||
|
string fileSystemPath = GetFileSystemPath(input.Path); |
||||
|
fileSystemPath = Path.Combine(fileSystemPath, input.Name); |
||||
|
if (!File.Exists(fileSystemPath)) |
||||
|
{ |
||||
|
throw new UserFriendlyException("指定目录不存在!"); |
||||
|
} |
||||
|
var moveToFilePath = GetFileSystemPath(input.ToPath); |
||||
|
moveToFilePath = Path.Combine(moveToFilePath, input.ToName ?? input.Name); |
||||
|
if (Directory.Exists(moveToFilePath)) |
||||
|
{ |
||||
|
throw new UserFriendlyException("指定的路径中已经有同名的文件存在!"); |
||||
|
} |
||||
|
|
||||
|
File.Move(fileSystemPath, moveToFilePath); |
||||
|
|
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
|
||||
|
public virtual Task MoveFolderAsync([Required, StringLength(255)] string path, FolderMoveDto input) |
||||
|
{ |
||||
|
string fileSystemPath = GetFileSystemPath(path); |
||||
|
if (!Directory.Exists(fileSystemPath)) |
||||
|
{ |
||||
|
throw new UserFriendlyException("指定目录不存在!"); |
||||
|
} |
||||
|
var moveToFilePath = GetFileSystemPath(input.MoveToPath); |
||||
|
if (Directory.Exists(moveToFilePath)) |
||||
|
{ |
||||
|
throw new UserFriendlyException("指定的路径中已经有同名的目录存在!"); |
||||
|
} |
||||
|
|
||||
|
Directory.Move(fileSystemPath, moveToFilePath); |
||||
|
|
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
|
||||
|
public virtual Task<FileSystemDto> UpdateAsync([Required, StringLength(255)] string name, FileSystemUpdateDto input) |
||||
|
{ |
||||
|
string fileSystemPath = GetFileSystemPath(name); |
||||
|
var renameFilePath = GetFileSystemPath(input.NewName); |
||||
|
if (File.Exists(fileSystemPath)) |
||||
|
{ |
||||
|
if (File.Exists(renameFilePath)) |
||||
|
{ |
||||
|
throw new UserFriendlyException("指定的文件名已经存在!"); |
||||
|
} |
||||
|
File.Move(fileSystemPath, renameFilePath); |
||||
|
|
||||
|
var fileInfo = new FileInfo(renameFilePath); |
||||
|
var fileSystem = new FileSystemDto |
||||
|
{ |
||||
|
Type = FileSystemType.File, |
||||
|
Name = fileInfo.Name, |
||||
|
Size = fileInfo.Length, |
||||
|
CreationTime = fileInfo.CreationTime, |
||||
|
LastModificationTime = fileInfo.LastWriteTime |
||||
|
}; |
||||
|
if (fileInfo.Directory?.Parent != null && !fileInfo.Directory.Parent.Name.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
fileSystem.Parent = GetFileSystemRelativePath(fileInfo.Directory.Parent.FullName); |
||||
|
} |
||||
|
return Task.FromResult(fileSystem); |
||||
|
} |
||||
|
if (Directory.Exists(fileSystemPath)) |
||||
|
{ |
||||
|
if (Directory.Exists(renameFilePath)) |
||||
|
{ |
||||
|
throw new UserFriendlyException("指定的路径中已经有同名的目录存在!"); |
||||
|
} |
||||
|
|
||||
|
Directory.Move(fileSystemPath, renameFilePath); |
||||
|
|
||||
|
var directoryInfo = new DirectoryInfo(renameFilePath); |
||||
|
var fileSystem = new FileSystemDto |
||||
|
{ |
||||
|
Type = FileSystemType.Folder, |
||||
|
Name = directoryInfo.Name, |
||||
|
CreationTime = directoryInfo.CreationTime, |
||||
|
LastModificationTime = directoryInfo.LastWriteTime |
||||
|
}; |
||||
|
if (directoryInfo.Parent != null && !directoryInfo.Parent.Name.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
fileSystem.Parent = GetFileSystemRelativePath(directoryInfo.Parent.FullName); |
||||
|
} |
||||
|
return Task.FromResult(fileSystem); |
||||
|
} |
||||
|
throw new UserFriendlyException("文件或目录不存在!"); |
||||
|
} |
||||
|
|
||||
|
protected virtual string GetFileSystemRelativePath(string path) |
||||
|
{ |
||||
|
return path.Replace(Directory.GetCurrentDirectory(), ""); |
||||
|
} |
||||
|
|
||||
|
protected virtual string GetFileSystemPath(string path) |
||||
|
{ |
||||
|
var fileSystemConfiguration = GetFileSystemBlobProviderConfiguration(); |
||||
|
var blobPath = GetFileSystemBashPath(); |
||||
|
|
||||
|
if (fileSystemConfiguration.AppendContainerNameToBasePath) |
||||
|
{ |
||||
|
blobPath = Path.Combine(blobPath, path); |
||||
|
} |
||||
|
|
||||
|
return blobPath; |
||||
|
} |
||||
|
|
||||
|
protected virtual string GetFileSystemBashPath() |
||||
|
{ |
||||
|
var fileSystemConfiguration = GetFileSystemBlobProviderConfiguration(); |
||||
|
var blobPath = fileSystemConfiguration.BasePath; |
||||
|
blobPath = Path.Combine(Directory.GetCurrentDirectory(), blobPath); |
||||
|
if (CurrentTenant.Id == null) |
||||
|
{ |
||||
|
blobPath = Path.Combine(blobPath, "host"); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
blobPath = Path.Combine(blobPath, "tenants", CurrentTenant.Id.Value.ToString("D")); |
||||
|
} |
||||
|
|
||||
|
return blobPath; |
||||
|
} |
||||
|
|
||||
|
protected virtual FileSystemBlobProviderConfiguration GetFileSystemBlobProviderConfiguration() |
||||
|
{ |
||||
|
var blobConfiguration = BlobContainerConfigurationProvider |
||||
|
.Get<FileSystemContainer>(); |
||||
|
return blobConfiguration.GetFileSystemConfiguration(); |
||||
|
} |
||||
|
|
||||
|
protected void CopyDirectory(string sourcePath, string copyToPath) |
||||
|
{ |
||||
|
var sourceDirectory = new DirectoryInfo(sourcePath); |
||||
|
var fileSystemInfos = sourceDirectory.GetFileSystemInfos(); |
||||
|
|
||||
|
foreach (var fileSystemInfo in fileSystemInfos) |
||||
|
{ |
||||
|
var copyToFilePath = Path.Combine(copyToPath, fileSystemInfo.Name); |
||||
|
if (fileSystemInfo is DirectoryInfo) |
||||
|
{ |
||||
|
if (!Directory.Exists(copyToFilePath)) |
||||
|
{ |
||||
|
Directory.CreateDirectory(copyToFilePath); |
||||
|
} |
||||
|
CopyDirectory(fileSystemInfo.FullName, copyToFilePath); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
File.Copy(fileSystemInfo.FullName, copyToFilePath, true); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<None Remove="LINGYUN\Abp\FileManagement\Localization\Resources\en.json" /> |
||||
|
<None Remove="LINGYUN\Abp\FileManagement\Localization\Resources\zh-Hans.json" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<EmbeddedResource Include="LINGYUN\Abp\FileManagement\Localization\Resources\en.json" /> |
||||
|
<EmbeddedResource Include="LINGYUN\Abp\FileManagement\Localization\Resources\zh-Hans.json" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.Validation" Version="3.0.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,30 @@ |
|||||
|
using LINGYUN.Abp.FileManagement.Localization; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.Validation; |
||||
|
using Volo.Abp.Validation.Localization; |
||||
|
using Volo.Abp.VirtualFileSystem; |
||||
|
|
||||
|
namespace LINGYUN.Abp.FileManagement |
||||
|
{ |
||||
|
[DependsOn(typeof(AbpValidationModule))] |
||||
|
public class AbpFileManagementDomainSharedModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
Configure<AbpVirtualFileSystemOptions>(options => |
||||
|
{ |
||||
|
options.FileSets.AddEmbedded<AbpFileManagementDomainSharedModule>(); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpLocalizationOptions>(options => |
||||
|
{ |
||||
|
options.Resources |
||||
|
.Add<AbpFileManagementResource>("en") |
||||
|
.AddBaseTypes( |
||||
|
typeof(AbpValidationResource) |
||||
|
).AddVirtualJson("/LINGYUN/Abp/FileManagement/Localization/Resources"); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace LINGYUN.Abp.FileManagement.Localization |
||||
|
{ |
||||
|
[LocalizationResourceName("AbpFileManagement")] |
||||
|
public class AbpFileManagementResource |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
{ |
||||
|
"culture": "en", |
||||
|
"texts": { |
||||
|
"Permission:FileManagement": "File management", |
||||
|
"Permission:FileSystem": "File system", |
||||
|
"Permission:FileManager": "Files", |
||||
|
"Permission:CreateFolder": "Create directory", |
||||
|
"Permission:DeleteFolder": "Delete directory", |
||||
|
"Permission:UpdateFolder": "Edit directory", |
||||
|
"Permission:MoveFolder": "Change directory", |
||||
|
"Permission:CopyFolder": "Copy directory", |
||||
|
"Permission:AppendFile": "Add files", |
||||
|
"Permission:UpdateFile": "Change file", |
||||
|
"Permission:DeleteFile": "Delete file", |
||||
|
"Permission:CopyFile": "Copy file", |
||||
|
"Permission:MoveFile": "Move file", |
||||
|
"Permission:DownloadFile": "Download file", |
||||
|
"UploadFileSizeBeyondLimit": "Upload file size cannot exceed {0} MB!", |
||||
|
"NotAllowedFileExtensionName": "Not allowed file extension: {0}!", |
||||
|
"DisplayName:FileLimitLength": "File limit size", |
||||
|
"Description:FileLimitLength": "Limit size of uploaded file in MB", |
||||
|
"DisplayName:AllowFileExtensions": "File extension", |
||||
|
"Description:AllowFileExtensions": "List of allowed extensions to upload files, with multiple extensions separated by, don't need a notation" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
{ |
||||
|
"culture": "zh-Hans", |
||||
|
"texts": { |
||||
|
"Permission:FileManagement": "文件管理", |
||||
|
"Permission:FileSystem": "文件系统", |
||||
|
"Permission:FileManager": "文件", |
||||
|
"Permission:CreateFolder": "创建目录", |
||||
|
"Permission:DeleteFolder": "删除目录", |
||||
|
"Permission:UpdateFolder": "修改目录", |
||||
|
"Permission:MoveFolder": "变更目录", |
||||
|
"Permission:CopyFolder": "复制目录", |
||||
|
"Permission:AppendFile": "添加文件", |
||||
|
"Permission:UpdateFile": "变更文件", |
||||
|
"Permission:DeleteFile": "删除文件", |
||||
|
"Permission:CopyFile": "复制文件", |
||||
|
"Permission:MoveFile": "移动文件", |
||||
|
"Permission:DownloadFile": "下载文件", |
||||
|
"UploadFileSizeBeyondLimit": "上传文件大小不能超过 {0} MB!", |
||||
|
"NotAllowedFileExtensionName": "不被允许的文件扩展名: {0}!", |
||||
|
"DisplayName:FileLimitLength": "文件限制大小", |
||||
|
"Description:FileLimitLength": "上传文件的限制大小,单位(MB)", |
||||
|
"DisplayName:AllowFileExtensions": "文件扩展名", |
||||
|
"Description:AllowFileExtensions": "允许的上传文件扩展名列表,多个扩展名以,分隔,无需输入.符号" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
namespace LINGYUN.Abp.FileManagement.Settings |
||||
|
{ |
||||
|
public class AbpFileManagementSettingNames |
||||
|
{ |
||||
|
public const string GroupName = "Abp.FileManagement"; |
||||
|
/// <summary>
|
||||
|
/// 文件限制长度
|
||||
|
/// </summary>
|
||||
|
public const string FileLimitLength = GroupName + ".FileLimitLength"; |
||||
|
/// <summary>
|
||||
|
/// 允许的文件扩展名类型
|
||||
|
/// </summary>
|
||||
|
public const string AllowFileExtensions = GroupName + ".AllowFileExtensions"; |
||||
|
|
||||
|
public const int DefaultFileLimitLength = 100; |
||||
|
public const string DefaultAllowFileExtensions = "dll,zip,rar,txt,log,xml,config,json,jpeg,jpg,png,bmp,ico,xlsx,xltx,xls,xlt,docs,dots,doc,dot,pptx,potx,ppt,pot,chm"; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.BlobStoring.FileSystem" Version="3.0.0" /> |
||||
|
<PackageReference Include="Volo.Abp.Ddd.Domain" Version="3.0.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.FileManagement.Domain.Shared\LINGYUN.Abp.FileManagement.Domain.Shared.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,15 @@ |
|||||
|
using Volo.Abp.Domain; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
namespace LINGYUN.Abp.FileManagement |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpDddDomainModule), |
||||
|
typeof(AbpMultiTenancyModule), |
||||
|
typeof(AbpFileManagementDomainSharedModule) |
||||
|
)] |
||||
|
public class AbpFileManagementDomainModule : AbpModule |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using Volo.Abp.BlobStoring; |
||||
|
|
||||
|
namespace LINGYUN.Abp.FileManagement |
||||
|
{ |
||||
|
[BlobContainerName("abp-file-management")] |
||||
|
public class FileSystemContainer |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
using LINGYUN.Abp.FileManagement.Localization; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.Settings; |
||||
|
|
||||
|
namespace LINGYUN.Abp.FileManagement.Settings |
||||
|
{ |
||||
|
public class AbpFileManagementSettingDefinitionProvider : SettingDefinitionProvider |
||||
|
{ |
||||
|
public override void Define(ISettingDefinitionContext context) |
||||
|
{ |
||||
|
context.Add(CreateFileSystemSettings()); |
||||
|
} |
||||
|
|
||||
|
protected SettingDefinition[] CreateFileSystemSettings() |
||||
|
{ |
||||
|
return new SettingDefinition[] |
||||
|
{ |
||||
|
new SettingDefinition( |
||||
|
name: AbpFileManagementSettingNames.FileLimitLength, |
||||
|
defaultValue: AbpFileManagementSettingNames.DefaultFileLimitLength.ToString(), |
||||
|
displayName: L("DisplayName:FileLimitLength"), |
||||
|
description: L("Description:FileLimitLength"), |
||||
|
isVisibleToClients: true) |
||||
|
.WithProviders( |
||||
|
GlobalSettingValueProvider.ProviderName, |
||||
|
TenantSettingValueProvider.ProviderName), |
||||
|
new SettingDefinition( |
||||
|
name: AbpFileManagementSettingNames.AllowFileExtensions, |
||||
|
defaultValue: AbpFileManagementSettingNames.DefaultAllowFileExtensions, |
||||
|
displayName: L("DisplayName:AllowFileExtensions"), |
||||
|
description: L("Description:AllowFileExtensions"), |
||||
|
isVisibleToClients: true) |
||||
|
.WithProviders( |
||||
|
GlobalSettingValueProvider.ProviderName, |
||||
|
TenantSettingValueProvider.ProviderName), |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
protected LocalizableString L(string name) |
||||
|
{ |
||||
|
return LocalizableString.Create<AbpFileManagementResource>(name); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netcoreapp3.1</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.AspNetCore.Mvc" Version="3.0.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.FileManagement.Application.Contracts\LINGYUN.Abp.FileManagement.Application.Contracts.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,21 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.AspNetCore.Mvc; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.FileManagement |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpFileManagementApplicationContractsModule), |
||||
|
typeof(AbpAspNetCoreMvcModule) |
||||
|
)] |
||||
|
public class AbpFileManagementHttpApiModule : AbpModule |
||||
|
{ |
||||
|
public override void PreConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
PreConfigure<IMvcBuilder>(mvcBuilder => |
||||
|
{ |
||||
|
mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpFileManagementHttpApiModule).Assembly); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,240 @@ |
|||||
|
using LINGYUN.Abp.FileManagement.Settings; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Microsoft.AspNetCore.StaticFiles; |
||||
|
using System; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using System.IO; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
using Volo.Abp.AspNetCore.Mvc; |
||||
|
using Volo.Abp.IO; |
||||
|
using Volo.Abp.Settings; |
||||
|
|
||||
|
namespace LINGYUN.Abp.FileManagement |
||||
|
{ |
||||
|
[Controller] |
||||
|
[RemoteService(Name = "AbpFileManagement")] |
||||
|
[Area("file-management")] |
||||
|
[Route("api/file-management/file-system")] |
||||
|
public class FileSystemController : AbpController |
||||
|
{ |
||||
|
protected ISettingProvider SettingProvider { get; } |
||||
|
protected IFileSystemAppService FileSystemAppService { get; } |
||||
|
|
||||
|
public FileSystemController( |
||||
|
ISettingProvider settingProvider, |
||||
|
IFileSystemAppService fileSystemAppService) |
||||
|
{ |
||||
|
SettingProvider = settingProvider; |
||||
|
FileSystemAppService = fileSystemAppService; |
||||
|
} |
||||
|
|
||||
|
[HttpPut] |
||||
|
[Route("files/copy")] |
||||
|
public virtual async Task CopyFileAsync(FileCopyOrMoveDto input) |
||||
|
{ |
||||
|
await FileSystemAppService.CopyFileAsync(input); |
||||
|
} |
||||
|
|
||||
|
[HttpPut] |
||||
|
[Route("folders/copy")] |
||||
|
public virtual async Task CopyFolderAsync([Required, StringLength(255)] string path, FolderCopyDto input) |
||||
|
{ |
||||
|
await FileSystemAppService.CopyFolderAsync(path, input); |
||||
|
} |
||||
|
|
||||
|
[HttpPost] |
||||
|
[Route("files/upload")] |
||||
|
public virtual async Task CreateFileAsync(FileCreateDto input) |
||||
|
{ |
||||
|
// 检查文件大小
|
||||
|
var fileSizeLimited = await SettingProvider |
||||
|
.GetAsync( |
||||
|
AbpFileManagementSettingNames.FileLimitLength, |
||||
|
AbpFileManagementSettingNames.DefaultFileLimitLength); |
||||
|
if (fileSizeLimited * 1024 * 1024 < input.TotalByte) |
||||
|
{ |
||||
|
throw new UserFriendlyException(L["UploadFileSizeBeyondLimit", fileSizeLimited]); |
||||
|
} |
||||
|
// 采用分块模式上传文件
|
||||
|
|
||||
|
// 保存分块到临时目录
|
||||
|
var fileName = input.Name; |
||||
|
// 文件扩展名
|
||||
|
var fileExtensionName = FileHelper.GetExtension(fileName); |
||||
|
var fileAllowExtension = await SettingProvider |
||||
|
.GetOrNullAsync(AbpFileManagementSettingNames.AllowFileExtensions); |
||||
|
if (fileAllowExtension.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
fileAllowExtension = AbpFileManagementSettingNames.DefaultAllowFileExtensions; |
||||
|
} |
||||
|
// 检查文件扩展名
|
||||
|
if (!fileAllowExtension.Split(',') |
||||
|
.Any(fe => fe.Equals(fileExtensionName, StringComparison.CurrentCultureIgnoreCase))) |
||||
|
{ |
||||
|
throw new UserFriendlyException(L["NotAllowedFileExtensionName", fileExtensionName]); |
||||
|
} |
||||
|
// 当前计算机临时目录
|
||||
|
var tempFilePath = Environment.GetFolderPath(Environment.SpecialFolder.Templates); |
||||
|
// 以上传的文件名创建一个临时目录
|
||||
|
tempFilePath = Path.Combine(tempFilePath, "lingyun-abp-file-management", Path.GetFileNameWithoutExtension(fileName)); |
||||
|
// 以上传的分片索引创建临时文件
|
||||
|
var tempSavedFile = Path.Combine(tempFilePath, $"{input.CurrentByte}.{fileExtensionName}"); |
||||
|
if (!Directory.Exists(tempFilePath)) |
||||
|
{ |
||||
|
// 临时目录不存在则创建
|
||||
|
Directory.CreateDirectory(tempFilePath); |
||||
|
} |
||||
|
try |
||||
|
{ |
||||
|
if (HttpContext.RequestAborted.IsCancellationRequested) |
||||
|
{ |
||||
|
// 如果取消请求,删除临时目录
|
||||
|
Directory.Delete(tempFilePath, true); |
||||
|
return; |
||||
|
} |
||||
|
// 保存临时文件
|
||||
|
using (var fs = new FileStream(tempSavedFile, FileMode.Create, FileAccess.Write)) |
||||
|
{ |
||||
|
// 写入当前分片文件
|
||||
|
await Request.Body.CopyToAsync(fs); |
||||
|
} |
||||
|
|
||||
|
if (input.CurrentByte == input.TotalByte) |
||||
|
{ |
||||
|
// 合并文件
|
||||
|
var mergeSavedFile = Path.Combine(tempFilePath, $"{fileName}"); |
||||
|
// 获取并排序所有分片文件
|
||||
|
var mergeFiles = Directory.GetFiles(tempFilePath).OrderBy(f => f.Length).ThenBy(f => f); |
||||
|
// 创建临时合并文件
|
||||
|
using (var mergeSavedFileStream = new FileStream(mergeSavedFile, FileMode.Create)) |
||||
|
{ |
||||
|
foreach (var mergeFile in mergeFiles) |
||||
|
{ |
||||
|
// 读取当前文件字节
|
||||
|
var mergeFileBytes = await FileHelper.ReadAllBytesAsync(mergeFile); |
||||
|
// 写入到合并文件流
|
||||
|
await mergeSavedFileStream.WriteAsync(mergeFileBytes, 0, mergeFileBytes.Length); |
||||
|
// 删除已参与合并的临时文件分片
|
||||
|
FileHelper.DeleteIfExists(mergeFile); |
||||
|
} |
||||
|
// 读取文件数据
|
||||
|
var fileData = await mergeSavedFileStream.GetAllBytesAsync(); |
||||
|
input.Data = fileData; |
||||
|
} |
||||
|
await FileSystemAppService.CreateFileAsync(input); |
||||
|
// 文件保存之后删除临时文件目录
|
||||
|
Directory.Delete(tempFilePath, true); |
||||
|
} |
||||
|
} |
||||
|
catch |
||||
|
{ |
||||
|
// 发生异常删除临时文件目录
|
||||
|
Directory.Delete(tempFilePath, true); |
||||
|
throw; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[HttpPost] |
||||
|
[Route("folders/add")] |
||||
|
public virtual async Task CreateFolderAsync(FolderCreateDto input) |
||||
|
{ |
||||
|
await FileSystemAppService.CreateFolderAsync(input); |
||||
|
} |
||||
|
|
||||
|
[HttpDelete] |
||||
|
[Route("files/delete")] |
||||
|
public virtual async Task DeleteFileAsync(FileDeleteDto input) |
||||
|
{ |
||||
|
await FileSystemAppService.DeleteFileAsync(input); |
||||
|
} |
||||
|
|
||||
|
[HttpDelete] |
||||
|
[Route("folders/delete")] |
||||
|
public virtual async Task DeleteFolderAsync([Required, StringLength(255)] string path) |
||||
|
{ |
||||
|
await FileSystemAppService.DeleteFolderAsync(path); |
||||
|
} |
||||
|
|
||||
|
[HttpGet] |
||||
|
[Route("files/download")] |
||||
|
public virtual async Task DownloadFileAsync(FileSystemGetDto input) |
||||
|
{ |
||||
|
var fileStream = await FileSystemAppService.DownloadFileAsync(input); |
||||
|
|
||||
|
// 得到文件扩展名
|
||||
|
var fileExt = Path.GetExtension(input.Name); |
||||
|
var provider = new FileExtensionContentTypeProvider(); |
||||
|
// Http响应标头的文件类型
|
||||
|
string memi = provider.Mappings[fileExt]; |
||||
|
using (Response.Body) |
||||
|
{ |
||||
|
// Http响应标头的文件类型
|
||||
|
Response.ContentType = memi; |
||||
|
// 文件大小
|
||||
|
byte[] contentBytes = await fileStream.GetAllBytesAsync(); |
||||
|
long contentLength = contentBytes.Length; |
||||
|
// 指定响应内容大小
|
||||
|
Response.ContentLength = contentLength; |
||||
|
// 单个分块大小 2MB
|
||||
|
int bufferSize = 2 * 1024 * 1024; |
||||
|
// 分块总数
|
||||
|
int contentByteCount = Math.DivRem(contentBytes.Length, bufferSize, out int modResult); |
||||
|
for (int index = 0; index < contentByteCount; index++) |
||||
|
{ |
||||
|
// 当前分页传输字节
|
||||
|
byte[] currentTransferBytes = new byte[bufferSize]; |
||||
|
if (index == contentByteCount - 1) |
||||
|
{ |
||||
|
// 最后一个分块和余数大小一起传输
|
||||
|
if (modResult > 0) |
||||
|
{ |
||||
|
currentTransferBytes = new byte[bufferSize + modResult]; |
||||
|
} |
||||
|
} |
||||
|
// 复制文件流中的当前分块区段
|
||||
|
Array.Copy(contentBytes, index * bufferSize, currentTransferBytes, 0, currentTransferBytes.Length); |
||||
|
// 写入响应流
|
||||
|
await Response.Body.WriteAsync(currentTransferBytes, 0, currentTransferBytes.Length); |
||||
|
// 清空缓冲区
|
||||
|
await Response.Body.FlushAsync(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[HttpGet] |
||||
|
[Route("profile")] |
||||
|
public virtual async Task<FileSystemDto> GetAsync(FileSystemGetDto input) |
||||
|
{ |
||||
|
return await FileSystemAppService.GetAsync(input); |
||||
|
} |
||||
|
|
||||
|
[HttpGet] |
||||
|
public virtual async Task<PagedResultDto<FileSystemDto>> GetListAsync(GetFileSystemListDto input) |
||||
|
{ |
||||
|
return await FileSystemAppService.GetListAsync(input); |
||||
|
} |
||||
|
|
||||
|
[HttpPut] |
||||
|
[Route("files/move")] |
||||
|
public virtual async Task MoveFileAsync(FileCopyOrMoveDto input) |
||||
|
{ |
||||
|
await FileSystemAppService.MoveFileAsync(input); |
||||
|
} |
||||
|
|
||||
|
[HttpPut] |
||||
|
[Route("folders/move")] |
||||
|
public virtual async Task MoveFolderAsync([Required, StringLength(255)] string path, FolderMoveDto input) |
||||
|
{ |
||||
|
await FileSystemAppService.MoveFolderAsync(path, input); |
||||
|
} |
||||
|
|
||||
|
[HttpPut] |
||||
|
public virtual async Task<FileSystemDto> UpdateAsync([Required, StringLength(255)] string name, FileSystemUpdateDto input) |
||||
|
{ |
||||
|
return await FileSystemAppService.UpdateAsync(name, input); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue