美文网首页
asp.net zero 8.2 学习-12- abp 文件上传

asp.net zero 8.2 学习-12- abp 文件上传

作者: 水静莲香2019 | 来源:发表于2020-05-11 23:33 被阅读0次

    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. 测试

    image

    相关文章

      网友评论

          本文标题:asp.net zero 8.2 学习-12- abp 文件上传

          本文链接:https://www.haomeiwen.com/subject/agpmnhtx.html