翼度科技»论坛 编程开发 .net 查看内容

.NET 文件上传服务设计

10

主题

10

帖子

30

积分

新手上路

Rank: 1

积分
30
.NET文件上传服务设计

前言

在b站学习了一个后端小项目,然后发现这个文件上传设计还挺不错,来实现讲解一下。
项目结构如下:

基于策略+工厂模式实现文件上传服务
枚举

在Model层创建即可
  1.     public enum UploadMode
  2.     {
  3.         Local = 1, //本地上传
  4.         Qiniu = 2 //七牛云上传
  5.     }
复制代码
第一步:创建文件策略和工厂

在Service层中创建FileStrategy文件夹,在该文件夹下分别创建Strategy、QiNiuStrategy、LocalStrategy、FileFactory、FileContext

Strategy 文件操作抽象类
  1. /// <summary>
  2. /// 文件操作抽象类
  3. /// </summary>
  4. public abstract class Strategy
  5. {
  6.     public abstract Task<string> Upload(List<IFormFile> formFiles);
  7. }
复制代码
LocalStrategy 本地策略

继承Strategy 文件操作抽象类并实现他里面的方法
后续要实现该方法
  1. public class LocalStrategy:Strategy
  2. {
  3.     public override async Task<string> Upload(List<IFormFile> formFiles)
  4.     {
  5.         throw new NotImplementedException();
  6.     }
  7. }
复制代码
QiNiuStrategy 七牛云策略

同上
  1. public class QiNiuStrategy:Strategy
  2. {
  3.     public override async Task<string> Upload(List<IFormFile> formFiles)
  4.     {
  5.         throw new NotImplementedException();
  6.     }
  7. }
复制代码
FileContext 上下文

在策略模式中通过上下文调用具体的策略
这里的好处就是我如果new LocalStrategy则是本地上传服务,如果是new QiNiuStrategy则是七牛云上传,详情看下方工厂的设计
  1. /// <summary>
  2. /// 上下文,通过这个来调用具体的策略
  3. /// </summary>
  4. public class FileContext
  5. {
  6.     private Strategy _strategy;
  7.     private List<IFormFile> _formFiles;
  8.     public FileContext(Strategy strategy, List<IFormFile> formFiles)
  9.     {
  10.         _formFiles = formFiles;
  11.         _strategy = strategy;
  12.     }
  13.     public async Task<string> ContextInterface()
  14.     {
  15.         return await _strategy.Upload(_formFiles);
  16.     }
  17. }
复制代码
FileFactory 工厂

通过工厂去负责对象的实例化
枚举的作用就来了,更据枚举去判断实例化那一个对象
  1. /// <summary>
  2. /// 工厂类,负责对象的实例化
  3. /// </summary>
  4. public class FileFactory
  5. {
  6.     public static Strategy CreateStrategy(UploadMode mode)
  7.     {
  8.         switch (mode)
  9.         {
  10.             case UploadMode.Qiniu:
  11.                 return new QiNiuStrategy();
  12.             case UploadMode.Local:
  13.                 return new LocalStrategy();
  14.             default:
  15.                 return new QiNiuStrategy();
  16.         }
  17.     }
  18. }
复制代码
第二步:对接服务层

在Interface接口层创建IFileService接口
这里需要安装HttpNuget包,不然没有IFormFile,我下的是Microsoft.AspNetCore.Http/2.2.2
  1. public interface IFileService
  2. {
  3.     Task<string> Upload(List<IFormFile> files, UploadMode mode);
  4. }
复制代码
在Service层创建FileService类实现上面的接口
  1. public class FileService:IFileService
  2. {
  3.     public async Task<string> Upload(List<IFormFile> files, UploadMode mode)
  4.     {
  5.         FileContext fileContext = new FileContext(FileFactory.CreateStrategy(mode), files);
  6.         return await fileContext.ContextInterface();
  7.     }
  8. }
复制代码
上述通过上下文调用具体的策略,通过工厂去创建具体的类,工厂更据传入的枚举作为参数(构造函数传参),通过上下文的ContextInterface就可以完成上传的逻辑了。
策略+工厂的好处就是,以后需要修改上传文件,只需要对策略进行更改和补充即可。意思就是新增一个上传策略,只需要创建一个策略类,然后去工厂类new一个就行了,不需要动Service层的东西。
本地上传功能实现

在本地策略类中实现上传方法
注意var filePath = $"{AppContext.BaseDirectory}/wwwroot";是将文件保存在bin目录下的wwwroot目录了
  1. public class LocalStrategy:Strategy
  2. {
  3.     public override async Task<string> Upload(List<IFormFile> formFiles)
  4.     {
  5.         var res = await Task.Run(() =>
  6.         {
  7.             //存放多个文件路径
  8.             List<string> result = new List<string>();
  9.             foreach (var formFile in formFiles)
  10.             {
  11.                 if (formFile.Length > 0)
  12.                 {
  13.                     var filePath = $"{AppContext.BaseDirectory}/wwwroot";
  14.                     var fileName = $"/{DateTime.Now:yyyyMMddHHmmssffff}{formFile.FileName}";
  15.                     if (!Directory.Exists(filePath))
  16.                     {
  17.                         Directory.CreateDirectory(filePath);
  18.                     }
  19.                     using (var stream = System.IO.File.Create(filePath + fileName))
  20.                     {
  21.                         formFile.CopyTo(stream);
  22.                     }
  23.                     result.Add(fileName);
  24.                 }
  25.             }
  26.             return string.Join(",", result);
  27.         });
  28.         return res;
  29.     }
  30. }
复制代码
七牛云上传功能实现

注册七牛云:https://www.qiniu.com/
从个人中心获取秘钥信息,安装SDK,编写上传逻辑
在Service层安装QiniuNuget包
ak、sk为七牛云的秘钥,在个人中心查看
  1. public class QiNiuStrategy : Strategy
  2. {
  3.     public override async Task<string> Upload(List<IFormFile> formFiles)
  4.     {
  5.         //先上传到本地,才能上传到七牛云,上传完成后本地的文件可删除
  6.         var res = await Task.Run(() =>
  7.         {
  8.             Mac mac = new Mac("ak", "sk");
  9.             List<string> result = new List<string>();
  10.             foreach (var formFile in formFiles)
  11.             {
  12.                 if (formFile.Length > 0)
  13.                 {
  14.                     var filePath_temp = $"{AppContext.BaseDirectory}/Images_temp";
  15.                     var fileName = $"{DateTime.Now:yyyyMMddHHmmssffff}{formFile.FileName}";
  16.                     if (!Directory.Exists(filePath_temp))
  17.                     {
  18.                         Directory.CreateDirectory(filePath_temp);
  19.                     }
  20.                     using (var stream = System.IO.File.Create($"{filePath_temp}/{fileName}"))
  21.                     {
  22.                         formFile.CopyTo(stream);
  23.                     }
  24.                     // 上传文件名
  25.                     string key = fileName;
  26.                     // 本地文件路径
  27.                     string filePath = $"{filePath_temp}/{fileName}";
  28.                     // 存储空间名
  29.                     string Bucket = "pl-static";
  30.                     // 设置上传策略
  31.                     PutPolicy putPolicy = new PutPolicy();
  32.                     // 设置要上传的目标空间
  33.                     putPolicy.Scope = Bucket;
  34.                     // 上传策略的过期时间(单位:秒)
  35.                     //putPolicy.SetExpires(3600);
  36.                     // 文件上传完毕后,在多少天后自动被删除
  37.                     //putPolicy.DeleteAfterDays = 1;
  38.                     // 生成上传token
  39.                     string token = Auth.CreateUploadToken(mac, putPolicy.ToJsonString());
  40.                     Config config = new Config();
  41.                     // 设置上传区域
  42.                     config.Zone = Zone.ZONE_CN_East;
  43.                     // 设置 http 或者 https 上传
  44.                     config.UseHttps = true;
  45.                     config.UseCdnDomains = true;
  46.                     config.ChunkSize = ChunkUnit.U512K;
  47.                     // 表单上传
  48.                     FormUploader target = new FormUploader(config);
  49.                     HttpResult httpResult = target.UploadFile(filePath, key, token, null);
  50.                     result.Add(fileName);
  51.                     //删除备份文件夹
  52.                     Directory.Delete(filePath_temp, true);
  53.                 }
  54.             }
  55.             return string.Join(",", result);
  56.         });
  57.         return res;
  58.     }
  59. }
复制代码
Controller的实现

mode为1则会执行本地上传的逻辑代码,为2则会执行七牛云上传的服务代码。
  1. [Route("api/[controller]/[action]")]
  2. [ApiController]
  3. public class FileController : ControllerBase
  4. {
  5.     private readonly IFileService _fileService;
  6.     public FileController(IFileService fileService)
  7.     {
  8.         _fileService = fileService;
  9.     }
  10.     /// <summary>
  11.     /// 上传文件
  12.     /// </summary>
  13.     /// <param name="file">文件对象</param>
  14.     /// <param name="mode">上传方式:本地或者七牛云</param>
  15.     /// <returns></returns>
  16.     [HttpPost]
  17.     public async Task<ApiResult> UploadFile(List<IFormFile> file, UploadMode mode)
  18.     {
  19.         return ResultHelper.Success(await _fileService.Upload(file, mode));
  20.     }
  21. }
复制代码
测试



返回的图片路径可以根据自己的需求进行更改。
去bin目录查看图片是否上传成功

总结

上述内容就是对于文件上传服务的设计,有其他文件上传需求,比如分片断点上传、上传到其他的服务商,只需要新增策略,完成逻辑代码即可,还是很方便的一种文件上传设计。

来源:https://www.cnblogs.com/ZYPLJ/archive/2023/06/15/17483162.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具