在我們很多模塊里面,都需要使用到一些諸如圖片、Excel文件、PDF文件等附件的管理,一般我們傾向於把它獨立為一個公用的附件管理模塊,這樣可以有效的統一管理附件的信息。本篇隨筆介紹附件內容的管理,包括可以對圖片進行預覽,對其他文件實現信息的查看和下載等操作,以及后端提供對應的附件上傳等處理。
1、附件管理的界面
和其他模塊一樣,我們可以對附件記錄表里面的信息進行管理,一般情況下,我們管理的附件都是諸如圖片、Excel文件、PDF文件等附件的管理。
附件表是一個綜合管理這些文件的記錄表,雖然附件一般是獨立上傳到服務器端的文件系統里面,不過也需要記錄這些文件的名稱、類別名稱、大小、后綴名、創建時間、創建人等信息。
數據庫設計表如下所示。
記錄明細大概如下所示。
為了管理好這些文件信息,我們在界面提供一些條件供查詢,如下是管理界面。
為了快速的進行檢索,我們提供了兩個樹形列表進行查詢,可以按照文件類型,以及按照類別名稱查詢,類別是我們在上傳的時候指定的一個附件的類別名稱。
按文件類型分類如下所示
按類別名稱分類如下所示。
而樹形列表的信息展示,我們使用了自定義的樹列表控件,非常方便,並極大減少了界面代碼,界面代碼如下所示。
<el-tabs value="treeType" type="border-card"> <el-tab-pane name="treeType" label="按文件類型"> <myTree :data="treeType" icon-class="el-icon-price-tag" @nodeClick="nodeTypeClick" /> </el-tab-pane> <el-tab-pane name="treeCategory" label="按類別名稱"> <myTree :data="treeCategory" icon-class="el-icon-price-tag" @nodeClick="nodeCategoryClick" /> </el-tab-pane> </el-tabs>
而樹形列表的類別名稱,我們是從數據庫中動態獲取的,因此需要特殊的API封裝調用。
在ABP框架的后端,應用服務類FileUploadAppService中定義一個獲取類別的列表接口
/// <summary> /// 獲取所有類別(Distinct) /// </summary> /// <returns></returns> public virtual async Task<List<string>> GetAllCategory() { var query = Repository.GetAll().Where(s=> s.Category != null).OrderBy(s => s.Category); var list = query.Select(s => s.Category).Distinct().ToList(); return await Task.FromResult(list); }
在客戶端的API調用類中同時增加一個API處理接口,如下所示。
而Element的前端調用后端的ABP接口,前面很多博客也介紹的很多了,如下是它們的處理過程圖示。
前端根據ABP后端的接口進行前端JS端的類的封裝處理,引入了ES6類的概念實現業務基類接口的統一封裝,簡化代碼。
大多數模塊我們涉及到常規增刪改查等業務接口,那么這些類繼承BaseApi,就會具有相關的接口了,如下所示繼承關系。
其中JS類的BaseApi具有常規的增刪改查接口,如下所示。
在整合ABP后端接口的時候,我們為了方便,一般使用ES6的方式定義一個客戶端的Api調用類,基礎接口封裝在BaseApi類里面,擴展自定義接口放在子類定義,因此前端API封裝類fileupload.js的類關系如下所示。
我們再次回到管理界面,在列表中展示附件信息外,如果是圖片提供預覽,如果是文件則提供下載鏈接,方便處理。
或者
預覽查看圖片文件的時候,我們也需要在明細中列出附件的一些信息,如下界面所示。
以上就是附件管理的設計表,以及管理界面,其中前端主要使用了Vue + Element進行開發,后端還是用ABP的框架提供相關的API接口。
2、附件上傳的處理
在之前隨筆《循序漸進VUE+Element 前端應用開發(23)--- 基於ABP實現前后端的附件上傳,圖片或者附件展示管理》中已經比較詳細的介紹了對附件的上傳處理,我們ABP后端提供了一些API接口給前端界面控件進行調用即可上傳對應的附件
在附件上傳處理的時候,我們就可以通過這樣獲得請求的文件對象了,如下代碼所示。
我們上傳到后端ABP應用服務器的文件,一般情況是不能訪問目錄的,如果需要特別放行,那么需要在ABP服務的Host應用里面,設置靜態文件,允許前端訪問我們的文件路徑。
一般在Host項目的啟動入口設置即可。
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { ............ app.UseStaticFiles(); //指定特定的目錄作為靜態文件目錄,如UploadFiles //是否可以訪問靜態文件 app.UseStaticFiles(new StaticFileOptions { FileProvider = new PhysicalFileProvider(Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "UploadFiles")), RequestPath = "/UploadFiles" }); .........
這樣上傳的文件,在對應目錄里面,就可以通過URL地址訪問了。
另外,前面我們看到的數據記錄里面,沒有絕對的URL地址,一般是為了適應性方便,不需要絕對的地址。
但是前端為了方便,服務器后端返回的接口中,我們一般增加一個絕對的地址信息供查看或者下載文件,那么我們可以在后端對應附件記錄的轉義函數里面增加一個對相對地址轉換為絕對訪問的URL地址的轉換即可。
/// <summary> /// 對記錄進行轉義 /// </summary> /// <param name="item">dto數據對象</param> /// <returns></returns> protected override void ConvertDto(FileUploadDto item) { //轉義相對地址為絕對地址 item.FileUrl = GetFileUrl(item.BasePath, item.SavePath); }
/// <summary> /// 根據記錄的basePath和savePath,以及HttpContext上下文確定絕對路徑 /// </summary> /// <param name="basePath">附件的基礎路徑</param> /// <param name="savePath">附件的保存路徑</param> /// <returns></returns> private string GetFileUrl(string basePath, string savePath) { var httpContext = _httpContext.HttpContext; string serverRealPath = basePath.UriCombine(savePath); if (!Path.IsPathRooted(basePath) && !basePath.StartsWith("http://") && !basePath.StartsWith("https://")) { //如果是相對目錄,加上當前程序的目錄才能定位文件地址 var url = string.Format("{0}://{1}", httpContext.Request.Scheme, httpContext.Request.Host.Value); serverRealPath = url.UriCombine(serverRealPath).Replace('\\', '/'); } return serverRealPath; }
而前端界面中,一般的圖片和附件上傳界面如下所示。
編輯界面下,附件上傳界面,可以加載已有的記錄展示,如下所示。
用圖片列表控件的方式展示圖片信息,如下所示。
如果我們用Element的上傳組件,大概的界面代碼如下所示,主要設置好上傳的API地址,以及給它提供好對應的授權頭部信息即可。
前端界面的代碼如下所示。
<el-form-item label="封面圖片"> <el-upload ref="upload" action="/abp/services/app/FileUpload/PostUpload" list-type="picture-card" :on-preview="handlePictureCardPreview" :on-remove="handleRemove" :on-success="onSuccess" :on-error="onError" accept="image/jpeg,image/gif,image/png,image/bmp" :headers="myHeaders" :file-list="editForm.fileList" > <i class="el-icon-plus" /> </el-upload> <el-dialog :visible.sync="dialogVisible"> <img width="100%" :src="dialogImageUrl" alt=""> </el-dialog> </el-form-item>
其中授權頭部信息,是ABP約定的授權請求頭部信息,如下屬性設置
myHeaders: { Authorization: 'Bearer ' + getToken() }, // 用於上傳文件的身份認證
這樣就可以整合文件上傳的管理操作了,而前端就只需要針對附件信息,做統一的管理即可。
如下是統一的附件管理界面入口。
為了方便讀者理解,我列出一下前面幾篇隨筆的連接,供參考:
循序漸進VUE+Element 前端應用開發(1)--- 開發環境的准備工作
循序漸進VUE+Element 前端應用開發(2)--- Vuex中的API、Store和View的使用
循序漸進VUE+Element 前端應用開發(3)--- 動態菜單和路由的關聯處理
循序漸進VUE+Element 前端應用開發(4)--- 獲取后端數據及產品信息頁面的處理
循序漸進VUE+Element 前端應用開發(5)--- 表格列表頁面的查詢,列表展示和字段轉義處理
循序漸進VUE+Element 前端應用開發(6)--- 常規Element 界面組件的使用
循序漸進VUE+Element 前端應用開發(7)--- 介紹一些常規的JS處理函數
循序漸進VUE+Element 前端應用開發(8)--- 樹列表組件的使用
循序漸進VUE+Element 前端應用開發(9)--- 界面語言國際化的處理
循序漸進VUE+Element 前端應用開發(10)--- 基於vue-echarts處理各種圖表展示
循序漸進VUE+Element 前端應用開發(11)--- 圖標的維護和使用
循序漸進VUE+Element 前端應用開發(12)--- 整合ABP框架的前端登錄處理
循序漸進VUE+Element 前端應用開發(13)--- 前端API接口的封裝處理
循序漸進VUE+Element 前端應用開發(14)--- 根據ABP后端接口實現前端界面展示
循序漸進VUE+Element 前端應用開發(15)--- 用戶管理模塊的處理
循序漸進VUE+Element 前端應用開發(16)--- 組織機構和角色管理模塊的處理
循序漸進VUE+Element 前端應用開發(17)--- 菜單管理
循序漸進VUE+Element 前端應用開發(18)--- 功能點管理及權限控制
循序漸進VUE+Element 前端應用開發(19)--- 后端查詢接口和Vue前端的整合
使用代碼生成工具快速生成基於ABP框架的Vue+Element的前端界面
循序漸進VUE+Element 前端應用開發(20)--- 使用組件封裝簡化界面代碼
循序漸進VUE+Element 前端應用開發(21)--- 省市區縣聯動處理的組件使用
循序漸進VUE+Element 前端應用開發(22)--- 簡化main.js處理代碼,抽取過濾器、全局界面函數、組件注冊等處理邏輯到不同的文件中
循序漸進VUE+Element 前端應用開發(23)--- 基於ABP實現前后端的附件上傳,圖片或者附件展示管理
循序漸進VUE+Element 前端應用開發(24)--- 修改密碼的前端界面和ABP后端設置處理
循序漸進VUE+Element 前端應用開發(25)--- 各種界面組件的使用(1)
循序漸進VUE+Element 前端應用開發(26)--- 各種界面組件的使用(2)
循序漸進VUE+Element 前端應用開發(27)--- 數據表的動態表單設計和數據存儲
循序漸進VUE+Element 前端應用開發(28)--- 附件內容的管理
循序漸進VUE+Element 前端應用開發(29)--- 高級查詢條件的界面設計
部署基於.netcore5.0的ABP框架后台Api服務端,以及使用Nginx部署Vue+Element前端應用
循序漸進VUE+Element 前端應用開發(30)--- ABP后端和Vue+Element前端結合的分頁排序處理
循序漸進VUE+Element 前端應用開發(31)--- 系統的日志管理,包括登錄日志、接口訪問日志、實體變化歷史日志
循序漸進VUE+Element 前端應用開發(32)--- 手機短信動態碼登陸處理
循序漸進VUE+Element 前端應用開發(33)--- 郵件參數配置和模板郵件發送處理
使用Vue-TreeSelect組件實現公司-部門-人員級聯下拉列表的處理
使用Vue-TreeSelect組件的時候,用watch變量方式解決彈出編輯對話框界面無法觸發更新的問題