asp.net zero 8.2 学习-12- abp 文件上传、获取、删除 约定不等于承诺〃 2021-07-26 19:47 777阅读 0赞 ## 1. 页面布局 ## 我们先按照第二讲的方法 [创建一个页面][Link 1] 创建出一个空页面。 先创建一个Controller,比如MetronicController,再创建一个Action方法:UploadFile,再给UploadFile方法添加一个视图,复制空页面的内容到该视图UploadFile.cshtml 接着写上传文件的form表单 整体视图如下: @using EDU.SIS.Web.Areas.app.Startup @using EDU.SIS.Authorization @{ ViewBag.CurrentPageName = appPageNames.Common.MetronicUploadFile; } <!-- 文件上传 --> <div class="kt-content kt-grid__item kt-grid__item--fluid kt-grid kt-grid--hor"> <div class="kt-subheader kt-grid__item"> <div class="@(await GetContainerClass())"> <!--标题和副标题start--> <div class="kt-subheader__main"> <h3 class="kt-subheader__title"> <span>文件上传</span> </h3> </div> <!--标题和副标题end--> </div> </div> <div class="@(await GetContainerClass()) kt-grid__item kt-grid__item--fluid"> <div class="kt-portlet kt-portlet--mobile"> <div class="kt-portlet__body"> <form class="kt-form kt-form--center kt-form--label-right" id="kt_form_upload"> <div class="kt-portlet__body"> <div class="form-group kt-form__group row"> <label class="col-form-label col-lg-3 col-sm-12">附件上传</label> <div class="col-lg-4 col-md-9 col-sm-12"> <div class="input-group"> <input id="txt_uploadFileId" type="hidden" /> <input id="txt_fileName" type="text" class="form-control kt-input" name="fileName" readonly autocomplete="off" placeholder="附件名称"> <div class="input-group-append"> <span class="btn btn-primary fileinput-button"> <i class="glyphicon glyphicon-plus"></i> <span>选择文件</span> <input id="fileupload" type="file" name="files" accept="image/*"> </span> </div> </div> <span class="kt-form__help">上传进度</span> <div id="progress" class="progress"> <div class="progress-bar progress-bar-success"></div> </div> </div> </div> <div class="form-group kt-form__group row"> <label class="col-form-label col-lg-3 col-sm-12">获取附件</label> <div class="col-lg-4 col-md-9 col-sm-12"> <div class="input-group"> <input id="txt_enclosureId" type="text" class="form-control kt-input" name="enclosureId" required autocomplete="off" placeholder="请输入附件ID"> <div class="input-group-append"> <button id="btn_get_enclosure" class="btn btn-primary" type="button">附件详情</button> </div> </div> <span class="kt-form__help">附件详情将在控制台输出</span> </div> </div> <div class="form-group kt-form__group row"> <label class="col-form-label col-lg-3 col-sm-12">删除附件</label> <div class="col-lg-4 col-md-9 col-sm-12"> <div class="input-group"> <input id="txt_fileToDeleteId" type="text" class="form-control kt-input" name="fileToDeleteId" required autocomplete="off" placeholder="请输入附件ID"> <div class="input-group-append"> <button id="btn_delete_file" class="btn btn-primary" type="button">附件详情</button> </div> </div> <span class="kt-form__help">删除附件</span> </div> </div> </div> </form> </div> </div> </div> </div> @section Scripts{ <script src="~/view-resources/Areas/app/Views/Metronic/Index.js"></script> <script> </script> } ## 2. 前端js ## 在页面的Index.js文件种编写javascript脚本,这里使用了一个前端上传文件的jquery插件:jquery.fileupload.js,这个插件是在视图布局文件中已经绑定了压缩打包版app-layout-libs,不用再单独引用。 Index.js源码如下: (function () { $(function () { //--------------------------------- 系统附件上传 ---------------------------------// var url = abp.appPath + 'app/Metronic/UploadFilePost'; $('#fileupload').fileupload({ url: url, //后台上传服务地址 dataType: 'json', add: function (e, data) { //选择文件后处理方法 var files = data.originalFiles; var isCheckSuccess = true; if (files && files.length > 0) { $(files).each(function (i, obj) { //文件上传大小:10MB var _maxFileSize = 1024 * 1024 * 10; if (obj.size > _maxFileSize) { isCheckSuccess = false; abp.message.error("文件大小不能超过10MB"); return; } //判断文件类型 var acceptFileTypes = /^gif|jpe?g|png|bmp$/i; var name = data.originalFiles[0]["name"]; var index = name.lastIndexOf(".") + 1; var fileType = name.substring(index, name.length); if (!acceptFileTypes.test(fileType)) { isCheckSuccess = false; abp.message.error("只允许上传图片格式文件"); return; } }); } //校验成功后才提交上传数据 if (isCheckSuccess) { //上传按钮禁用状态 $('#fileupload').attr("disabled", "disabled"); $('.fileinput-button').addClass("disabled"); //提交上传数据 data.submit(); } }, done: function (e, response) { //上传完成后结果返回处理 //解除上传按钮禁用状态 $('#fileupload').removeAttr("disabled"); $('.fileinput-button').removeClass("disabled"); var jsonResult = response.result; //判断上传状态 if (jsonResult.success) { var fileUrl = abp.appPath + 'app/Metronic/GetFile?id=' + jsonResult.result.id + '&contentType=' + jsonResult.result.contentType; //注意contentType首字母要小写 var uploadedFile = '<a href="' + fileUrl + '" target="_blank">' + app.localize('UploadedFile') + '</a><br/><br/>' + ' 文件名称: ' + jsonResult.result.defaultFileName; //赋值附件名称 $('#txt_fileName').val(jsonResult.result.defaultFileName); //赋值隐藏域上传附件ID $('#txt_uploadFileId').val(jsonResult.result.id); //赋值获取附件详情文本框 $('#txt_enclosureId').val(jsonResult.result.id); //弹出成功提示框 abp.message.success(jsonResult.result.defaultFileName, app.localize('PostedData'), true); //弹出成功通知 abp.notify.success(app.localize('SavedSuccessfully')); } else { abp.message.error(jsonResult.error.message); } }, progressall: function (e, data) { //上传进度处理 var progress = parseInt(data.loaded / data.total * 100, 10); $('#progress .progress-bar').css( 'width', progress + '%' ); } }); //获取附件上传表单对象 var _$formUpload = $("#kt_form_upload"); //启用表单验证 _$formUpload.validate(); //获取详情按钮点击事件 $('#btn_get_enclosure').on('click', function () { //校验附件ID输入 var _validStatus = $('#txt_enclosureId').valid(); //判断校验结果 if (_validStatus) { var url = abp.appPath + 'app/Metronic/GetFileDetail?id=' + $('#txt_enclosureId').val(); $.get(url, function (data) { console.log(data); abp.notify.success("获取数据详情成功,请前往控制台查看。"); }); } }); //删除附件 $('#btn_delete_file').on('click', function () { //校验附件ID输入 var _validStatus = $('#txt_fileToDeleteId').valid(); if (_validStatus) { var url = abp.appPath + 'app/Metronic/DeleteFile?id=' + $('#txt_fileToDeleteId').val(); $.get(url, function (data) { if (data.success) { abp.notify.success("删除文件成功"); } else { //console.log(data); abp.notify.info("删除文件失败:"+data.error.message); } }) } }); }); })(); ## 3. 后端代码 ## 后端与上传文件相关的代码包括领域实体层的BinaryObject,这里对其扩展,添加了文件类型、大小等相关字段: using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Abp; using Abp.Domain.Entities; namespace EDU.SIS.Storage { /// <summary> /// 附件实体 /// </summary> [Table("AppBinaryObjects")] public class BinaryObject : Entity<Guid>, IMayHaveTenant { /// <summary> /// 租户ID /// </summary> public virtual int? TenantId { get; set; } /// <summary> /// 文件类型【拓展字段】 /// </summary> public virtual string ContentType { get; set; } /// <summary> /// 文件名称【拓展字段】 /// </summary> public virtual string FileName { get; set; } /// <summary> /// 文件大小【拓展字段】 /// </summary> public virtual long FileSize { get; set; } /// <summary> /// 二进制数据 /// </summary> [Required] public virtual byte[] Bytes { get; set; } public BinaryObject() { Id = SequentialGuidGenerator.Instance.Create(); } public BinaryObject(int? tenantId, byte[] bytes) : this() { TenantId = tenantId; Bytes = bytes; } } } 还包括IBinaryObjectManager、DbBinaryObjectManager实现文件上传的领域服务,未修改。 接下来就是在Controller中编写上传文件处理、获取文件详情等方法: /// <summary> /// 上传文件界面 /// </summary> /// <returns></returns> [HttpGet] public IActionResult UploadFile() { return View(); } /// <summary> /// 文件上传 /// </summary> /// <returns></returns> [HttpPost] public async Task<JsonResult> UploadFilePost() { try { //获取上传对象 var file = Request.Form.Files.First(); //判断是否选择文件 if (file == null) { throw new UserFriendlyException(L("File_Empty_Error")); } //判断文件大小(单位:字节) if (file.Length > 10485760) //10MB = 1024 * 1024 *10 { throw new UserFriendlyException(L("File_SizeLimit_Error")); } //将文件流转为二进制数据 byte[] fileBytes; using (var stream = file.OpenReadStream()) { fileBytes = stream.GetAllBytes(); } //创建附件对象 var fileObject = new BinaryObject() { TenantId = AbpSession.TenantId, Bytes = fileBytes, ContentType = file.ContentType, FileName = file.FileName, FileSize = file.Length }; //上传文件存储路径 string destPath = _webHostEnvironment.WebRootPath + "\\uploads\\"; if (!Directory.Exists(destPath)) { Directory.CreateDirectory(destPath); } //生成随机文件名 var fileExtension = Path.GetExtension(file.FileName).ToLowerInvariant(); string fileName = fileObject.Id + fileExtension;//需要查找没有扩展名的文件?? string filePath = Path.Combine(destPath, fileName); //存放文件到本地 using (FileStream fs = System.IO.File.Create(filePath)) { file.CopyTo(fs); fs.Flush(); } //附件对象保存到数据库 await _binaryObjectManager.SaveAsync(fileObject); //返回给前端上传结果 return Json(new AjaxResponse(new { id = fileObject.Id, contentType = file.ContentType, defaultFileName = file.FileName })); } catch (UserFriendlyException ex) { return Json(new AjaxResponse(new ErrorInfo(ex.Message))); } catch(Exception ex) { return Json(new AjaxResponse(new ErrorInfo(ex.Message))); } } /// <summary> /// 删除文件 /// </summary> /// <param name="id"></param> /// <returns></returns> public async Task<IActionResult> DeleteFile(string id) { try { var fileId = new Guid(id); var fileToDelete = await _binaryObjectManager.GetOrNullAsync(fileId); if (fileToDelete != null) { //string filePath = _webHostEnvironment.WebRootPath + "\\uploads\\"+ fileToDelete.FileName; await _binaryObjectManager.DeleteAsync(fileId); return Json(new AjaxResponse(true)); } else { return Json(new AjaxResponse(new ErrorInfo { Message = "文件不存在或删除文件失败" })); } } catch (Exception) { return Json(new AjaxResponse(new ErrorInfo { Message = "文件ID无效" })); } } /// <summary> /// 获取附件 /// </summary> /// <param name="id">附件ID</param> /// <param name="contentType">附件类型</param> /// <returns></returns> public async Task<IActionResult> GetFile(Guid id, string contentType) { var fileObject = await _binaryObjectManager.GetOrNullAsync(id); if (fileObject == null) { return StatusCode((int)HttpStatusCode.NotFound); } return File(fileObject.Bytes, contentType); } /// <summary> /// 获取附件详情 /// </summary> /// <param name="id">附件ID</param> /// <returns></returns> [HttpGet] public async Task<IActionResult> GetFileDetail(Guid id) { var fileObject = await _binaryObjectManager.GetOrNullAsync(id); if (fileObject == null) { return StatusCode((int)HttpStatusCode.NotFound); } return Json(new AjaxResponse(new { id = fileObject.Id, fileName = fileObject.FileName, contentType = fileObject.ContentType, fileSize = fileObject.FileSize, fileSizeFormat = FormatFileSize(fileObject.FileSize), bytes = fileObject.Bytes, tenantId = fileObject.TenantId, downloadUrl = string.Format("{0}app/Metronic/GetFile?id={1}&contentType={2}", _appConfiguration["App:WebSiteRootAddress"], fileObject.Id, fileObject.ContentType) })); } 这里abp官方上传的文件都是存放在数据库中,对于存放大的文件很不科学。可以修改代码存放到本地,也可以参考Magicodes.Storage这个开源库,实现本地存储或者云端OSS存储。 ## 4. 系统文件上传大小限制 ## 系统文件上传大小限制可以在代码中实现,也可以通过配置实现,但是最大不会超过配置内规定的大小,在MVC项目的Web.config中修改最大上传大小限制 ... <security> <requestFiltering> <!-- 文件上传大小限制:500M(默认值:30000000字节(28.6 MB),最大值:4GB) --> <requestLimits maxAllowedContentLength="524288000" /> </requestFiltering> </security> </system.webServer> <system.web> <!-- 文件上传大小为:500M (默认为:4M,最大值:2TB),上传超时时间为:120秒(默认值:90秒) --> <httpRuntime maxRequestLength="512000" executionTimeout="120" /> </system.web> ## 5. 测试 ## ![format_png][] [Link 1]: https://www.cnblogs.com/AlexanderZhao/p/12353245.html [format_png]: /images/20210726/c57d3c04c03943eea259c4ab24e7df2d.png
还没有评论,来说两句吧...