采用 ABP BLOB Storing 进行文件上传管理
最近在用 ABP vNex 写一个服务端后台,涉及到实体文件上传到服务器,并支持查找、删除等常规操作的需求。
第一反应是用 .NET Core 的 Controller 自己实现,要写不少操作逻辑,后来想到自己都用上了ABP 框架帮我实现其他业务需求,为何不试试看 ABP 有没有类似的类库呢?
搜索之下发现了 ABP 果然有现成的类库 BLOB String ,作为一个成熟类库,包含常规的增删改查操作是基本的,我看了一下官方文档,除了对自有服务器文件管理系统的支持,还封装好了对 Azure、Aws、阿里云等云厂商的操作接口,果然是使用现有框架能事半功倍。
下面记录一下我自己的配置使用过程,其实官网更好,我自己写一篇,只是为了加深印象,如果能对其他开发者有一点点的帮助,那是更好了。
一、安装依赖
这里和其他ABP的官方类库一样的引用方法,可以通过 ABP CLI 的 abp add-package Volo.Abp.BlobStoring
命令来执行安装,也可以通过 VS 的 nuGet 包管理器进行可视化安装。我这里使用的是自有服务器,所以还安装了 Volo.Abp.BlobStoring.FileSystem
二级包,如果是要用其他云商的接口,安装相应的包即可。
在后面的使用中发现其实只安装 Volo.Abp.BlobStoring.FileSystem
这个二级包就可以了。
二、配置容器
这个文件管理类库是以容器 Container 概念管理文件的,一个系统中可以有多个 Container ,给分别起名字配置即可。
起名字配置的方法是创建一个简单的类,在名为 BlobContainerName 的 attribute 中配置名字,比如要配置一个存放项目pdf的容器.
using Volo.Abp.BlobStoring; namespace AbpDemo { [BlobContainerName("project-pdf")] public class ProjectPdfContainer { } }
这样配置后,文件上传到服务器上的时候,服务器上会自动创建一个名为”project-pdf“的文件夹存放文件。
因为我使用的是自有服务器存放文件,所以还要配置这个容器服务器的根路径,这个在我们要使用的module文件的 ConfigureServices 方法中注入配置,配置时候注入的类型是刚才定义的容器类名。
Configure<AbpBlobStoringOptions>(options => { options.Containers.Configure<FileBlobContainer>(container => { container.UseFileSystem(fileSystem => { fileSystem.BasePath = "D:\\ProjectFiles"; }); }); });
这个配置方法有个”强大“的地方是可以配置服务器上的任意路径,这比用 ASP.NET Core Controller 自己实现方法部署在IIS上的时候方便很多,因为由于IIS权限的问题,程序只能方便地管理 wwwroot 文件夹下的路径,尤其是在删除和下载文件功能的具体实现上。
三、实现服务
框架容器类库中几个现有的接口方法足以满足新增、删除和下载的功能。
新增
public async Task SaveFileAsync(byte[] bytes) { var blobName = "myName"; await _blobContainer.SaveAsync(blobName, bytes); }
获取(下载)
public async Task<byte[]> GetFileAsync(blobName) { return await _blobContainer.GetAllBytesOrNullAsync(blobName); }
删除
public async Task<byte[]> GetFileAsync(blobName) { return await _blobContainer.DeleteAsync(blobName); }
这些封装好的方法还支持子文件夹的操作,如果要将文件存到文件夹中,只需要载入参的文件名 blobName 前面加上文件夹名称和斜杠“/”即可,系统会自动在“project-pdf”下面再创建一个文件夹再存放文件,获取和删除时候亦然。
四、前端调用
我前端是用 vue+Element 实现的,上传功能用的是 Element 自带的 el-upload 组件,在使用时候将组件的 action 参数配置为空,然后停用 auto-upload 自动上传属性。
自定义一个 formData 变量,将组件选取到的文件 raw 赋给 formData 的 file 键上,然后将 formData 作为 post 请求方法的 data 参数调用即可。
const formData = new FormData() formData.append('file', this.fileToUpload.raw)
// 上传文件 export function uploadFile(data) { return request({ url: '/api/app/project-file/upload-file', method: 'post', data: data, }) }
获取下载的操作在前端要有个一字节流转成文件的操作。因为默认的前端框架是返回json格式的,而上面 ABP BLOB Storing 类库返回的是字节流 blob 格式的,所以我单独封装了一个请求方法。
import axios from 'axios' export function downloadFile(config) { return new Promise((resolve, reject) => { axios({ url: config.url,// 请求地址 method: 'get', params: config.pa, //传给后台的参数,文件名或者包含文件夹的路径 responseType: 'blob'// 表明返回服务器返回的数据类型 }).then(res => { resolve(res) }).catch(err => { reject(err); }); });
在vue组件的method中使用下面的方法即可实现文件的下载。
downloadFile(pConfig).then(res => { let blob = new Blob([res.data]) if ('download' in document.createElement('a')) { // 不是IE浏览器 let url = window.URL.createObjectURL(blob) let link = document.createElement('a') link.style.display = 'none' link.href = url link.setAttribute('download', 'myName') document.body.appendChild(link) link.click() document.body.removeChild(link) // 下载完成移除元素 window.URL.revokeObjectURL(url) // 释放掉blob对象 } else { // IE 10+ window.navigator.msSaveBlob(blob,'myName') } }).catch(err => { this.$message.error("获取下载文件失败" + err) })
上面核心步骤是从后台给的数组转成blob,然后使用 window.URL.createObjectURL(blob) 获取文件下载路径。
留言评论