4

基于SqlSugar的开发框架循序渐进介绍(26)-- 实现本地上传、FTP上传、阿里云OSS上传...

 1 year ago
source link: https://www.cnblogs.com/wuhuacong/p/17302362.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

在前面介绍的随笔《基于SqlSugar的开发框架循序渐进介绍(7)-- 在文件上传模块中采用选项模式【Options】处理常规上传和FTP文件上传》中介绍过在文件上传处理的过程中,整合了本地文件上传和基于FTP方式的上传文件的处理整合。本篇随笔继续介绍文件上传的处理,基于选项模式【Options】方式整合基于阿里云OSS对象存储的处理方式。

1、选项模式【Options】的处理

文件上传处理应该由程序进行配置,决定使用那种方式,那么这里面我们为了弹性化处理, 在文件上传模块中采用选项模式【Options】处理常规上传和FTP文件上传的配置参数信息。

微软引入选项模式,它是用于配置框架服务使用的设置. 选项模式由Microsoft.Extensions.OptionsNuGet包实现,除了ASP.NET Core应用,它还适用于任何类型的应用程序,如果需要了解,微软的文档详细解释了选项模式。

选项模式的限制之一是你只能解析(注入) IOptions <MyOptions> 并在依赖注入配置完成(即所有模块的ConfigureServices方法完成)后获取选项值。如果你正在开发一个模块,可能需要让开发者能够设置一些选项,并在依赖注入注册阶段使用这些选项. 你可能需要根据选项值配置其他服务或更改依赖注入的注册代码。IOptions<>是单例,因此一旦生成了,除非通过代码的方式更改,它的值是不会更新的。

 之前介绍过的文件上传处理,

一个是本地文件处理,一个是FTP文件处理,它们选择那种方式,依赖于配置参数的信息,如下示意图所示。

8867-20220613113740630-1312381120.png

当我们增加了对象存储OSS方式后,可以扩展下这个图示如下所示。

8867-20230410112443649-316786450.png

在本地文件处理过程中,如果是Web API方式调用服务层,那么就在Web API所在的文件系统中,如果是Winform界面直接调用服务层,那么就是在当前系统中处理文件,这种方式可以有效的管理我们的文件信息。

在FTP文件处理过程中,则是根据选项参数的信息,调用FluentFTP类库进行文件的上传操作。

在OSS对象存储处理过程中,我们一般基于阿里云、腾讯云等这些云服务OSS的处理方式,一般它们会提供相应开发语言的SDK,我们引用并进行整合即可。

基于选项模式,根据我们的处理方式,我们定义一个对象,用于承载上传参数的信息,如下代码所示。

    /// <summary>
    /// 文件上传处理的选项信息
    /// </summary>
    public class UploadSettingOptions
    {
        /// <summary>
        /// 可指定的存储物理地址,如C:\\Attachment,如果没有配置项AttachmentBasePath,则默认一个相对目录。
        /// </summary>
        public string AttachmentBasePath { get; set; }

        /// <summary>
        /// 指定附件上传的方式,如ftp为FTP方式,为空则为普通方式
        /// </summary>
        public string AttachmentUploadType { get; set; }


        /// <summary>
        /// FTP上传配置
        /// </summary>
        public FtpProviderOptions FtpProvider { get; set; }

        /// <summary>
        /// OSS存储的配置
        /// </summary>
        public OSSProviderOptions OSSProvider { get; set; }
    }

其中本地介绍OSS存储处理的配置选项对象如下所示。

    /// <summary>
    /// OSS对象存储配置选项
    /// </summary>
    public sealed class OSSProviderOptions
    {
        /// <summary>
        /// 指定提供商
        /// </summary>
        public OSSProvider Provider { get; set; }
        /// <summary>
        /// 终结点
        /// </summary>
        public string Endpoint { get; set; }
        public string AccessKey { get; set; }
        public string SecretKey { get; set; }
        public string Region { get; set; }
        public bool IsEnableHttps { get; set; } = true;
        public bool IsEnableCache { get; set; }
        public string Bucket { get; set; }
    }

对应WebAPI的appSettngs.json文件配置项内容如下:

8867-20230410113028749-359448608.png

2、阿里云的OSS存储设置处理

对于阿里云的OSS来说,对应的AccesKey和SecretKey自己可以通过查看账户的信息可以获取到。

8867-20230410113509627-1054536210.png

我们开始需要添加一个Bucket节点,用来存放相关的文件,并且需要开启对应的权限,如下所示。

8867-20230410114404560-1848815727.png

一旦正式允许可以上传文件,那么文件存储在对应的Bucket项目中,如下所示。

8867-20230410113947913-704528034.png

 准备好这些前期工作后,我们如果需要在WebAPI端进行OSS存储的处理,可以利用阿里云的OSS 的SDK进行处理即可,如下所示。

8867-20230410114755883-2107527980.png

 SDK的常规使用很简单,我们可以参考它的aliyun-oss-csharp-sdk 案例来上传处理即可。

例如它的上传文件的处理代码如下所示:

    OssClient client = new OssClient(endpoint, accessKeyId, accessKeySecret); 
    client.PutObject(bucketName, key, filePathToUpload);

在文件处理的通用上传处理函数里面,我们根据配置内容选择不同的上传模式。

        /// <summary>
        /// 上传文件(根据配置文件选择合适的上传方式)
        /// </summary>
        /// <param name="info">文件信息(包含流数据)</param>
        /// <returns></returns>
        public async Task<CommonResult> Upload(FileUploadInfo info)
        {
            var uploadType = this._options.AttachmentUploadType;

            if (string.IsNullOrEmpty(uploadType))
            {
                return await this.UploadByNormal(info);
            }
            else if (uploadType.Equals("ftp", StringComparison.OrdinalIgnoreCase))
            {
                return await this.UploadByFTP(info);
            }
            else if(uploadType.Equals("oss", StringComparison.OrdinalIgnoreCase))
            {
                return await this.UploadByOSS(info);
            }
            else
            {
                throw new ArgumentException("AttachmentUploadType配置指定了无效的值, 请置空, 填写ftp或者填写oss。");
            }
        }

由于本篇主要介绍OSS的对象存储方式,因此我们来看看对应的OSS上传处理的操作。

和其他上传(如FTP上传)方式类似,我们也是构建对应的信息后调用OSS的SDK处理即可,如下代码所示。

/// <summary>
/// 使用阿里云的OSS服务上传文件
/// </summary>
/// <param name="info"></param>
/// <returns></returns>
public async Task<CommonResult> UploadByOSS(FileUploadInfo info)
{
    var result = new CommonResult();
    var ossOptions = this._options.OSSProvider;
    if(ossOptions != null)
    {
        //上传获得的相对路径
        string category = info.Category;
        if (string.IsNullOrEmpty(category))
        {
            category = "Photo";
        }

        //OSS的文件路径不能以正斜线(/)或者反斜线(\)字符开头。
        //确定日期时间目录(格式:yyyy-MM),不存在则创建
        string savePath = string.Format("{0}-{1:D2}/{2}", DateTime.Now.Year, DateTime.Now.Month, category);
        var ext = FileUtil.GetExtension(info.FileName);
        var finalName = string.Format("{0}{1}", Guid.NewGuid().ToString(), ext);//FileUtil.GetFileName(file);

        var filePath = string.Concat(savePath, "/", finalName);
        var stream = FileUtil.BytesToStream(info.FileData);

        //使用阿里云的OSS服务上传文件
        var client = new OssClient(ossOptions.Endpoint, ossOptions.AccessKey, ossOptions.SecretKey);
        client.PutObject(ossOptions.Bucket, filePath, stream);

        //基础路径和部分路径
        info.BasePath = $"{(ossOptions.IsEnableHttps ? "https" : "http")}://{ossOptions.Bucket}.{ossOptions.Endpoint}";
        info.SavePath = filePath;
        info.AddTime = DateTime.Now;


        result.Success = await base.InsertAsync(info);
        if (result.Success)
        {
            //记录返回值, Data1为具体的URL路径
            //生成外链地址 方便前端预览
            result.Data1 = info.BasePath.UriCombine(savePath);
            result.Data2 = savePath;
        }
        else
        {
            result.ErrorMessage = "数据写入数据库出错。";
        }
    }
    else
    {
        result.ErrorMessage = "OSS配置信息不正确或没有启用";
    }

    return result;
}

最终我们上传的文件列表如上图所示。

8867-20230410113947913-704528034.png

3、在Vue3+ElementPlus+Vite的前端项目上测试前端上传文件的处理

我们在一个前端的编辑器 @wangeditor 上整合图片上传的处理来展示这个OSS对象保存的操作。案例需要前端项目安装对应的插件,如下所示。

8867-20230410115905824-1465126284.png

 前端页面引用插件对象的代码如下所示

    <div class="wangeditor">
      <Toolbar style="border-bottom: 1px solid #ccc" :editor="editorRef" :defaultConfig="toolbarConfig" :mode="mode" />
      <Editor style="height: 500px; overflow-y: hidden" v-model="valueHtml" :defaultConfig="editorConfig" :mode="mode" @onCreated="handleCreated" />
    </div>

在脚本代码中引入对象的样式和对象。

<script setup lang="ts">
import '@wangeditor/editor/dist/css/style.css'; // 引入 css
import { Editor, Toolbar } from '@wangeditor/editor-for-vue';


defineOptions({
  name: 'Editor'
});

const mode = 'default';
// 编辑器实例,必须用 shallowRef
const editorRef = shallowRef();

为了配置上传图片文件的处理操作,我们需要根据编辑器的介绍,以及我们WebAPI端的处理函数定义,在脚本部分中增加对应的配置信息,如下代码所示

const editorConfig = {
  placeholder: '请输入内容...',
  MENU_CONF: {
    // 配置默认字号
    // 配置上传图片
    uploadImage: {
      // 上传图片请求接口路径
      server: '/api/FileUpload/PostUpload',
      // 后端接收的文件名称
      fieldName: 'multipartFile',
      maxFileSize: 10 * 1024 * 1024, // 上传图片10M
      // 上传的图片类型
      allowedFileTypes: ['image/*'],
      // 自定义增加 http  header
      headers: {
        Authorization: 'Bearer ' + getAccessToken()
      },
      // 自定义上传参数,例如传递验证的 token 等。参数会被添加到 formData 中,一起上传到服务端。
      meta: {
        guid: '',
        folder: '文档图片'
      },
      // 将 meta 拼接到 url 参数中,默认 false
      metaWithUrl: false,
      // 小于该值就插入 base64 格式(而不上传),默认为 0
      base64LimitSize: 10 * 1024, // 10MB
      // 自定义上传图片返回格式【后端返回的格式】
      customInsert(res: any, insertFn: InsertFnType) {
        console.log(res);
        if (!res.success) {
          ElMessage.error('上传文件失败,' + res.error);
          return;
        }
        // 从 res 中找到 url alt href ,然后插入图片 ,根据后端实际返回的字段来
        var result = res.result as Array<ResponseFileInfo>;
        if (result.length > 0) {
          console.log(result[0]);
          insertFn(result[0].url, result[0].name, result[0].url);
        }
      },
      // 单个文件上传成功之后
      onSuccess(file: File, res: any) {
        if (res.success) {
          ElMessage.success(`${file.name} 上传成功`);
          return;
        } else {
          ElMessage.warning(`${file.name} 上传出了点异常`);
          return;
        }
      },
      // 单个文件上传失败
      onFailed(file: File, res: any) {
        console.log(res);
        ElMessage.error(`${file.name} 上传失败`);
      },
      // 上传错误,或者触发 timeout 超时
      onError(file: File, err: any, res: any) {
        console.log(err, res);
        ElMessage.error(`${file.name} 上传出错`);
      }
    }
  }
};

其中主要的就是需要增加授权的令牌头部信息,以及对应上传需要用到的参数,还有就是返回的接口对象里面,需要根据Web API的定义,然后转换为本地识别的类别进行展示即可,如定义的 customInsert 函数

8867-20230410120920466-1013506228.png

 文件上传成功后,可以看到在编辑器中插入了对应的图片文件,图片地址指向的是阿里云OSS的路径。

8867-20230410121126796-2087873872.png

在数据库的文件记录中,我们可以看到对应的路径信息,如下所示。

8867-20230410121418387-1735158222.png

如果我们需要在项目中实现业务的图片上传功能,如下界面所示的效果。

8867-20220725161434078-1516612758.png

可以参考随笔《基于SqlSugar的开发框架循序渐进介绍(13)-- 基于ElementPlus的上传组件进行封装,便于项目使用》介绍内容进行自定义上传文件的处理即可。

<el-form-item label="资料文档">
     <my-upload v-model="viewForm.attachGUID" :data="{ guid: viewForm.attachGUID, folder: '用户图片' }"   disabled />
 </el-form-item>

以上就是我们针对不同的上传方式处理的操作,对于OSS的文件上传,我们通过整合阿里云的OSS的SDK,直接调用进行处理即可,非常方便,对于其他类似的平台,也可以针对它们提供的SDK进行扩展即可。

SqlSugar开发框架介绍:https://www.iqidi.com/Framework/sugarIndex.htm 

系列文章:

基于SqlSugar的开发框架的循序渐进介绍(1)--框架基础类的设计和使用

基于SqlSugar的开发框架循序渐进介绍(2)-- 基于中间表的查询处理

基于SqlSugar的开发框架循序渐进介绍(3)-- 实现代码生成工具Database2Sharp的整合开发

基于SqlSugar的开发框架循序渐进介绍(4)-- 在数据访问基类中对GUID主键进行自动赋值处理 

基于SqlSugar的开发框架循序渐进介绍(5)-- 在服务层使用接口注入方式实现IOC控制反转

基于SqlSugar的开发框架循序渐进介绍(6)-- 在基类接口中注入用户身份信息接口 

基于SqlSugar的开发框架循序渐进介绍(7)-- 在文件上传模块中采用选项模式【Options】处理常规上传和FTP文件上传

 《基于SqlSugar的开发框架循序渐进介绍(8)-- 在基类函数封装实现用户操作日志记录

基于SqlSugar的开发框架循序渐进介绍(9)-- 结合Winform控件实现字段的权限控制

基于SqlSugar的开发框架循序渐进介绍(10)-- 利用axios组件的封装,实现对后端API数据的访问和基类的统一封装处理

基于SqlSugar的开发框架循序渐进介绍(11)-- 使用TypeScript和Vue3的Setup语法糖编写页面和组件的总结

基于SqlSugar的开发框架循序渐进介绍(12)-- 拆分页面模块内容为组件,实现分而治之的处理

基于SqlSugar的开发框架循序渐进介绍(13)-- 基于ElementPlus的上传组件进行封装,便于项目使用

基于SqlSugar的开发框架循序渐进介绍(14)-- 基于Vue3+TypeScript的全局对象的注入和使用

 《基于SqlSugar的开发框架循序渐进介绍(15)-- 整合代码生成工具进行前端界面的生成

基于SqlSugar的开发框架循序渐进介绍(16)-- 工作流模块的功能介绍

基于SqlSugar的开发框架循序渐进介绍(17)-- 基于CSRedis实现缓存的处理

 《基于SqlSugar的开发框架循序渐进介绍(18)-- 基于代码生成工具Database2Sharp,快速生成Vue3+TypeScript的前端界面和Winform端界面

基于SqlSugar的开发框架循序渐进介绍(19)-- 基于UniApp+Vue的移动前端的功能介绍

基于SqlSugar的开发框架循序渐进介绍(20)-- 在基于UniApp+Vue的移动端实现多条件查询的处理

基于SqlSugar的开发框架循序渐进介绍(21)-- 在工作流列表页面中增加一些转义信息的输出,在后端进行内容转换

 《基于SqlSugar的开发框架循序渐进介绍(22)-- Vue3+TypeScript的前端工作流模块中实现统一的表单编辑和表单详情查看处理 

基于SqlSugar的开发框架循序渐进介绍(23)-- Winform端管理系统中平滑增加对Web API对接的需求

基于SqlSugar的开发框架循序渐进介绍(24)-- 使用Serialize.Linq对Lambda表达式进行序列化和反序列化 

 基于SqlSugar的开发框架循序渐进介绍(25)-- 基于SignalR实现多端的消息通讯

基于SqlSugar的开发框架循序渐进介绍(26)-- 实现本地上传、FTP上传、阿里云OSS上传三者合一处理


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK