13 changed files with 438 additions and 0 deletions
@ -0,0 +1,14 @@ |
|||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public class GetPublicFileInput |
||||
|
{ |
||||
|
[Required] |
||||
|
public string Name { get; set; } |
||||
|
|
||||
|
public string Path { get; set; } |
||||
|
|
||||
|
public string Process { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using System.IO; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Application.Services; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public interface IFileAppService : IApplicationService |
||||
|
{ |
||||
|
Task<OssObjectDto> UploadAsync(UploadPublicFileInput input); |
||||
|
|
||||
|
Task<Stream> GetAsync(GetPublicFileInput input); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public interface IFileValidater |
||||
|
{ |
||||
|
Task ValidationAsync(UploadFile input); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public interface IPrivateFileAppService : IFileAppService |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public interface IPublicFileAppService : IFileAppService |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public class UploadFile |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 总文件大小
|
||||
|
/// </summary>
|
||||
|
[Required] |
||||
|
public long TotalSize { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 文件名
|
||||
|
/// </summary>
|
||||
|
[Required] |
||||
|
public string FileName { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using System.IO; |
||||
|
using Volo.Abp.Auditing; |
||||
|
using Volo.Abp.Validation; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public class UploadPublicFileInput |
||||
|
{ |
||||
|
public string Path { get; set; } |
||||
|
public string Object { get; set; } |
||||
|
public bool Overwrite { get; set; } = true; |
||||
|
|
||||
|
[Required] |
||||
|
[DisableAuditing] |
||||
|
[DisableValidation] |
||||
|
public Stream Content { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,84 @@ |
|||||
|
using LINGYUN.Abp.Features.LimitValidation; |
||||
|
using LINGYUN.Abp.OssManagement.Features; |
||||
|
using System; |
||||
|
using System.IO; |
||||
|
using System.Threading.Tasks; |
||||
|
using System.Web; |
||||
|
using Volo.Abp.Features; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public abstract class FileAppServiceBase : OssManagementApplicationServiceBase, IFileAppService |
||||
|
{ |
||||
|
private readonly IFileValidater _fileValidater; |
||||
|
private readonly IOssContainerFactory _ossContainerFactory; |
||||
|
|
||||
|
protected FileAppServiceBase( |
||||
|
IFileValidater fileValidater, |
||||
|
IOssContainerFactory ossContainerFactory) |
||||
|
{ |
||||
|
_fileValidater = fileValidater; |
||||
|
_ossContainerFactory = ossContainerFactory; |
||||
|
} |
||||
|
|
||||
|
[RequiresFeature(AbpOssManagementFeatureNames.OssObject.UploadFile)] |
||||
|
[RequiresLimitFeature( |
||||
|
AbpOssManagementFeatureNames.OssObject.UploadLimit, |
||||
|
AbpOssManagementFeatureNames.OssObject.UploadInterval, |
||||
|
LimitPolicy.Month)] |
||||
|
public virtual async Task<OssObjectDto> UploadAsync(UploadPublicFileInput input) |
||||
|
{ |
||||
|
await _fileValidater.ValidationAsync(new UploadFile |
||||
|
{ |
||||
|
TotalSize = input.Content.Length, |
||||
|
FileName = input.Object |
||||
|
}); |
||||
|
|
||||
|
var oss = _ossContainerFactory.Create(); |
||||
|
|
||||
|
var createOssObjectRequest = new CreateOssObjectRequest( |
||||
|
GetCurrentBucket(), |
||||
|
HttpUtility.UrlDecode(input.Object), |
||||
|
input.Content, |
||||
|
GetCurrentPath(HttpUtility.UrlDecode(input.Path))) |
||||
|
{ |
||||
|
Overwrite = input.Overwrite |
||||
|
}; |
||||
|
|
||||
|
var ossObject = await oss.CreateObjectAsync(createOssObjectRequest); |
||||
|
|
||||
|
return ObjectMapper.Map<OssObject, OssObjectDto>(ossObject); |
||||
|
} |
||||
|
|
||||
|
[RequiresFeature(AbpOssManagementFeatureNames.OssObject.DownloadFile)] |
||||
|
[RequiresLimitFeature( |
||||
|
AbpOssManagementFeatureNames.OssObject.DownloadLimit, |
||||
|
AbpOssManagementFeatureNames.OssObject.DownloadInterval, |
||||
|
LimitPolicy.Month)] |
||||
|
public virtual async Task<Stream> GetAsync(GetPublicFileInput input) |
||||
|
{ |
||||
|
var ossObjectRequest = new GetOssObjectRequest( |
||||
|
GetCurrentBucket(), |
||||
|
// 需要处理特殊字符
|
||||
|
HttpUtility.UrlDecode(input.Name), |
||||
|
GetCurrentPath(HttpUtility.UrlDecode(input.Path)), |
||||
|
HttpUtility.UrlDecode(input.Process)); |
||||
|
|
||||
|
var ossContainer = _ossContainerFactory.Create(); |
||||
|
var ossObject = await ossContainer.GetObjectAsync(ossObjectRequest); |
||||
|
|
||||
|
return ossObject.Content; |
||||
|
} |
||||
|
|
||||
|
protected virtual string GetCurrentBucket() |
||||
|
{ |
||||
|
throw new System.NotImplementedException(); |
||||
|
} |
||||
|
|
||||
|
protected virtual string GetCurrentPath(string path) |
||||
|
{ |
||||
|
path = path.RemovePreFix(".").RemovePreFix("/"); |
||||
|
return path; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
using Microsoft.AspNetCore.Authorization; |
||||
|
using Volo.Abp.Users; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 所有登录用户访问私有文件服务接口
|
||||
|
/// bucket限制在users
|
||||
|
/// path限制在用户id
|
||||
|
/// </summary>
|
||||
|
[Authorize] |
||||
|
// 不对外公开,仅通过控制器调用
|
||||
|
//[RemoteService(IsMetadataEnabled = false)]
|
||||
|
public class PrivateFileAppService : FileAppServiceBase, IPrivateFileAppService |
||||
|
{ |
||||
|
public PrivateFileAppService( |
||||
|
IFileValidater fileValidater, |
||||
|
IOssContainerFactory ossContainerFactory) |
||||
|
: base(fileValidater, ossContainerFactory) |
||||
|
{ |
||||
|
} |
||||
|
protected override string GetCurrentBucket() |
||||
|
{ |
||||
|
return "users"; |
||||
|
} |
||||
|
|
||||
|
protected override string GetCurrentPath(string path) |
||||
|
{ |
||||
|
path = base.GetCurrentPath(path); |
||||
|
var userId = CurrentUser.GetId().ToString("N"); |
||||
|
return path.StartsWith(userId) ? path : $"{userId}/{path}"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public class AbpOssManagementOptions |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 静态容器
|
||||
|
/// 不允许被删除
|
||||
|
/// </summary>
|
||||
|
public List<string> StaticBuckets { get; } |
||||
|
|
||||
|
public AbpOssManagementOptions() |
||||
|
{ |
||||
|
StaticBuckets = new List<string> |
||||
|
{ |
||||
|
"public", |
||||
|
"users", |
||||
|
"system", |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
public void AddStaticBucket(string bucket) |
||||
|
{ |
||||
|
Check.NotNullOrWhiteSpace(bucket, nameof(bucket)); |
||||
|
|
||||
|
StaticBuckets.AddIfNotContains(bucket); |
||||
|
} |
||||
|
|
||||
|
public bool CheckStaticBucket(string bucket) |
||||
|
{ |
||||
|
return StaticBuckets.Any(bck => bck.Equals(bucket)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,89 @@ |
|||||
|
using LINGYUN.Abp.OssManagement.Localization; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using System.IO; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.AspNetCore.Mvc; |
||||
|
using Volo.Abp.Http; |
||||
|
using Volo.Abp.Validation; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
[Area("oss-management")] |
||||
|
[Route("api/files/private")] |
||||
|
[RemoteService(false)] |
||||
|
[ApiExplorerSettings(IgnoreApi = true)] |
||||
|
public class PrivateFilesController : AbpController |
||||
|
{ |
||||
|
private readonly IPrivateFileAppService _privateFileAppService; |
||||
|
|
||||
|
public PrivateFilesController( |
||||
|
IPrivateFileAppService privateFileAppService) |
||||
|
{ |
||||
|
_privateFileAppService = privateFileAppService; |
||||
|
|
||||
|
LocalizationResource = typeof(AbpOssManagementResource); |
||||
|
} |
||||
|
|
||||
|
[HttpPost] |
||||
|
[Route("{path}")] |
||||
|
[Route("{path}/{name}")] |
||||
|
public virtual async Task<OssObjectDto> UploadAsync(string path, string name) |
||||
|
{ |
||||
|
if (Request.ContentLength <= 0) |
||||
|
{ |
||||
|
ThrowValidationException(L["FileNotBeNullOrEmpty"], "File"); |
||||
|
} |
||||
|
|
||||
|
var file = Request.Form.Files[0]; |
||||
|
var fileName = name ?? file.FileName; |
||||
|
|
||||
|
var createOssObjectInput = new UploadPublicFileInput |
||||
|
{ |
||||
|
Path = path, |
||||
|
Object = fileName, |
||||
|
Content = file.OpenReadStream(), |
||||
|
Overwrite = true |
||||
|
}; |
||||
|
|
||||
|
return await _privateFileAppService.UploadAsync(createOssObjectInput); |
||||
|
} |
||||
|
|
||||
|
[HttpGet] |
||||
|
[Route("{name}")] |
||||
|
[Route("{name}/{process}")] |
||||
|
[Route("p/{path}/{name}")] |
||||
|
[Route("p/{path}/{name}/{process}")] |
||||
|
public virtual async Task<IActionResult> GetAsync(string path, string name, string process) |
||||
|
{ |
||||
|
var input = new GetPublicFileInput |
||||
|
{ |
||||
|
Name = name, |
||||
|
Path = path, |
||||
|
Process = process |
||||
|
}; |
||||
|
var fileStream = await _privateFileAppService.GetAsync(input); |
||||
|
|
||||
|
if (fileStream.IsNullOrEmpty()) |
||||
|
{ |
||||
|
return NotFound(); |
||||
|
} |
||||
|
|
||||
|
return File( |
||||
|
fileStream, |
||||
|
MimeTypes.GetByExtension(Path.GetExtension(input.Name)) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
private static void ThrowValidationException(string message, string memberName) |
||||
|
{ |
||||
|
throw new AbpValidationException(message, |
||||
|
new List<ValidationResult> |
||||
|
{ |
||||
|
new ValidationResult(message, new[] {memberName}) |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,89 @@ |
|||||
|
using LINGYUN.Abp.OssManagement.Localization; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using System.IO; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.AspNetCore.Mvc; |
||||
|
using Volo.Abp.Http; |
||||
|
using Volo.Abp.Validation; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
[Area("oss-management")] |
||||
|
[Route("api/files/public")] |
||||
|
[RemoteService(false)] |
||||
|
[ApiExplorerSettings(IgnoreApi = true)] |
||||
|
public class PublicFilesController : AbpController |
||||
|
{ |
||||
|
private readonly IPublicFileAppService _publicFileAppService; |
||||
|
|
||||
|
public PublicFilesController( |
||||
|
IPublicFileAppService publicFileAppService) |
||||
|
{ |
||||
|
_publicFileAppService = publicFileAppService; |
||||
|
|
||||
|
LocalizationResource = typeof(AbpOssManagementResource); |
||||
|
} |
||||
|
|
||||
|
[HttpPost] |
||||
|
[Route("{path}")] |
||||
|
[Route("{path}/{name}")] |
||||
|
public virtual async Task<OssObjectDto> UploadAsync(string path, string name) |
||||
|
{ |
||||
|
if (Request.ContentLength <= 0) |
||||
|
{ |
||||
|
ThrowValidationException(L["FileNotBeNullOrEmpty"], "File"); |
||||
|
} |
||||
|
|
||||
|
var file = Request.Form.Files[0]; |
||||
|
var fileName = name ?? file.FileName; |
||||
|
|
||||
|
var createOssObjectInput = new UploadPublicFileInput |
||||
|
{ |
||||
|
Path = path, |
||||
|
Object = fileName, |
||||
|
Content = file.OpenReadStream(), |
||||
|
Overwrite = true |
||||
|
}; |
||||
|
|
||||
|
return await _publicFileAppService.UploadAsync(createOssObjectInput); |
||||
|
} |
||||
|
|
||||
|
[HttpGet] |
||||
|
[Route("{name}")] |
||||
|
[Route("{name}/{process}")] |
||||
|
[Route("p/{path}/{name}")] |
||||
|
[Route("p/{path}/{name}/{process}")] |
||||
|
public virtual async Task<IActionResult> GetAsync(string path, string name, string process) |
||||
|
{ |
||||
|
var input = new GetPublicFileInput |
||||
|
{ |
||||
|
Name = name, |
||||
|
Path = path, |
||||
|
Process = process |
||||
|
}; |
||||
|
var fileStream = await _publicFileAppService.GetAsync(input); |
||||
|
|
||||
|
if (fileStream.IsNullOrEmpty()) |
||||
|
{ |
||||
|
return NotFound(); |
||||
|
} |
||||
|
|
||||
|
return File( |
||||
|
fileStream, |
||||
|
MimeTypes.GetByExtension(Path.GetExtension(input.Name)) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
private static void ThrowValidationException(string message, string memberName) |
||||
|
{ |
||||
|
throw new AbpValidationException(message, |
||||
|
new List<ValidationResult> |
||||
|
{ |
||||
|
new ValidationResult(message, new[] {memberName}) |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.AspNetCore.Mvc; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement.SettingManagement |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpOssManagementApplicationContractsModule), |
||||
|
typeof(AbpAspNetCoreMvcModule))] |
||||
|
public class AbpOssManagementSettingManagementModule : AbpModule |
||||
|
{ |
||||
|
public override void PreConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
PreConfigure<IMvcBuilder>(mvcBuilder => |
||||
|
{ |
||||
|
mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpOssManagementSettingManagementModule).Assembly); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue