Vue实现Excel模板文件的上传与下载

Vue实现Excel模板文件的上传与下载

一.前言

越来越多的项目开始使用前后端分离的方式来进行开发了,前端使用的vue来进行页面处理的,所以正常的文件下载和上传肯定是少不了的,因为这也是自己第一次使用vue来进行项目开发,所以抱着学习的态度来记录自己遇到的问题。

1.excel导入

先看代码,导入操作通过弹框来处理,选择要上传的文件后台对上传的文件进行处理。importFile()方法来触发导入文件的对话框

      
              批量导入
              模板下载
              新增
              
 
    
    
  importFile() {
      this.$refs.refFileUpload.open();
    } 

uploadTemp.vue 示例代码如下







接着向后台提交文件的方法

submitFile() {
      const _this = this;
      _this.loading = true;
      if (!_this.files.name) {
        _this.$message.warning("请选择要上传的文件!");
        return false;
      }
      let fileFormData = new FormData();
      //filename是键,file是值,就是要传的文件
      fileFormData.append("file", _this.files, _this.files.name);
      if (_this.OtherParams) {
        const keys = Object.keys(_this.OtherParams);
        keys.forEach(e => {
          fileFormData.append(e, _this.OtherParams[e]);
        });
      }
      let requestConfig = {
        headers: {
          "Content-Type": "multipart/form-data"
        }
      };
      AjaxHelper.post(_this.apiURL, fileFormData, requestConfig)
        .then(res => {
          if (res.success) {
            const result = res.result;
            if (result.errorCount == 0 && result.successCount > 0) {
              _this.$message({
                message: `导入成功,成功${result.successCount}条`,
                type: "success"
              });
              _this.closeFileUpload();
              _this.Refresh();
            } else if (result.errorCount > 0 && result.successCount >= 0) {
              _this.Refresh();
              _this.tableData = result.uploadErrors;
              _this.successCount = result.successCount;
              _this.innerVisible = true;
            } else if (result.errorCount == 0 && result.successCount == 0) {
              _this.$message({
                message: `上传文件中数据为空`,
                type: "error"
              });
            }
            _this.loading = false;
          }
        })
        .catch(function(error) {
          console.log(error);
        });
    },

这是上传文件的调用方法。

2.excel下载

下载主要是通过后台返回文件流的形式在前端浏览器进行下载,不过关于模板下载,之前没有考虑到IE10浏览器的兼容问题,导致在IE10浏览器下文件没法下载,后来百度后找到了解决办法。

downloadFile(name) {
      let requestConfig = {
        headers: {
          "Content-Type": "application/json;application/octet-stream"
        }
      };
      AjaxHelper.post(this.downLoadUrl, requestConfig, {
        responseType: "blob"
      }).then(res => {
        // 处理返回的文件流
        const content = res.data;
        const blob = new Blob([content]);
        var date =
          new Date().getFullYear() +
          "" +
          (new Date().getMonth() + 1) +
          "" +
          new Date().getDate();
        const fileName = date + name + ".xlsx";
        if ("download" in document.createElement("a")) {
          // 非IE下载
          const elink = document.createElement("a");
          elink.download = fileName;
          elink.style.display = "none";
          elink.href = URL.createObjectURL(blob);
          document.body.appendChild(elink);
          elink.click();
          URL.revokeObjectURL(elink.href); // 释放URL 对象
          document.body.removeChild(elink);
        } else {
          // IE10+下载
          navigator.msSaveBlob(blob, fileName);
        }
      });
    },

到此前端vue对于Excel文件的上传和下载的处理就结束了。

3.后端对于文件上传和下载的处理

文件上传

public UploadResult UploadFiles(IFormFile file, Guid brandId)
        {
            try
            {
                UploadResult uploadResult = new UploadResult();
                if (file == null)
                {
                    throw new UserFriendlyException(501, "上传的文件为空,请重新上传");
                }
                string filename = Path.GetFileName(file.FileName);
                string fileEx = Path.GetExtension(filename);//获取上传文件的扩展名
                string NoFileName = Path.GetFileNameWithoutExtension(filename);//获取无扩展名的文件名
                string FileType = ".xls,.xlsx";//定义上传文件的类型字符串
                if (!FileType.Contains(fileEx))
                {
                    throw new UserFriendlyException(501, "无效的文件类型,只支持.xls和.xlsx文件");
                }
                //源数据
                MemoryStream msSource = new MemoryStream();
                file.CopyTo(msSource);
                msSource.Seek(0, SeekOrigin.Begin);
                DataTable sourceExcel = ReadStreamToDataTable(msSource, "", true);

                //模板数据
                string dataDir = _hosting.WebRootPath;//获得当前服务器程序的运行目录  
                dataDir = Path.Combine(dataDir, "ExcelTemplate");
                var path = dataDir + "//档案模版.xlsx";
                MemoryStream msModel = new MemoryStream();
                FileStream stream = new FileStream(path, FileMode.Open);
                stream.CopyTo(msModel);
                msModel.Seek(0, SeekOrigin.Begin);
                DataTable templateExcel = ReadStreamToDataTable(stream, "", true);
                //验证是否同模板相同 
                string columnName = templateExcel.Columns[0].ColumnName;
                if (columnName != sourceExcel.Columns[0].ColumnName)
                {
                    throw new UserFriendlyException(501, "上传的模板文件不正确");
                }
                int sucessCount = 0;
                int errorCount = 0;
                // 处理后台逻辑 执行 插入操作

                uploadResult.SuccessCount = sucessCount;
                uploadResult.ErrorCount = errorCount;
                uploadResult.uploadErrors = errorList;
                return uploadResult;
            }
            catch (Exception ex)
            {
                throw new UserFriendlyException(501, "上传的模板文件不正确");
            }
        }

在这里我们需要将文件流转化为Datable

public static DataTable ReadStreamToDataTable(Stream fileStream, string sheetName = null, bool isFirstRowColumn = true)
        {
            //定义要返回的datatable对象
            DataTable data = new DataTable();
            //excel工作表
            ISheet sheet = null;
            //数据开始行(排除标题行)
            int startRow = 0;
            try
            {
                //根据文件流创建excel数据结构,NPOI的工厂类WorkbookFactory会自动识别excel版本,创建出不同的excel数据结构
                IWorkbook workbook = WorkbookFactory.Create(fileStream);
                //如果有指定工作表名称
                if (!string.IsNullOrEmpty(sheetName))
                {
                    sheet = workbook.GetSheet(sheetName);
                    //如果没有找到指定的sheetName对应的sheet,则尝试获取第一个sheet
                    if (sheet == null)
                    {
                        sheet = workbook.GetSheetAt(0);
                    }
                }
                else
                {
                    //如果没有指定的sheetName,则尝试获取第一个sheet
                    sheet = workbook.GetSheetAt(0);
                }
                if (sheet != null)
                {
                    IRow firstRow = sheet.GetRow(0);
                    //一行最后一个cell的编号 即总的列数
                    int cellCount = firstRow.LastCellNum;
                    //如果第一行是标题列名
                    if (isFirstRowColumn)
                    {
                        for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
                        {
                            ICell cell = firstRow.GetCell(i);
                            if (cell != null)
                            {
                                string cellValue = cell.StringCellValue;
                                if (cellValue != null)
                                {
                                    DataColumn column = new DataColumn(cellValue);
                                    data.Columns.Add(column);
                                }
                            }
                        }
                        startRow = sheet.FirstRowNum + 1;
                    }
                    else
                    {
                        startRow = sheet.FirstRowNum;
                    }
                    //最后一列的标号
                    int rowCount = sheet.LastRowNum;
                    for (int i = startRow; i <= rowCount; ++i)
                    {
                        IRow row = sheet.GetRow(i);
                        if (row == null || row.FirstCellNum < 0) continue; //没有数据的行默认是null       

                        DataRow dataRow = data.NewRow();
                        for (int j = row.FirstCellNum; j < cellCount; ++j)
                        {
                            //同理,没有数据的单元格都默认是null
                            ICell cell = row.GetCell(j);
                            if (cell != null)
                            {
                                if (cell.CellType == CellType.Numeric)
                                {
                                    //判断是否日期类型
                                    if (DateUtil.IsCellDateFormatted(cell))
                                    {
                                        dataRow[j] = row.GetCell(j).DateCellValue;
                                    }
                                    else
                                    {
                                        dataRow[j] = row.GetCell(j).ToString().Trim();
                                    }
                                }
                                else
                                {
                                    dataRow[j] = row.GetCell(j).ToString().Trim();
                                }
                            }
                        }
                        data.Rows.Add(dataRow);
                    }
                }
                return data;
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }

4.文件下载

  public async Task DownloadFiles()
        {
            string dataDir = _hosting.WebRootPath;//获得当前服务器程序的运行目录  
            dataDir = Path.Combine(dataDir, "ExcelTemplate");
            var path = dataDir + "//档案模版.xlsx";
            var memoryStream = new MemoryStream();
            using (var stream = new FileStream(path, FileMode.Open))
            {
                await stream.CopyToAsync(memoryStream);
            }
            memoryStream.Seek(0, SeekOrigin.Begin);
            return new FileStreamResult(memoryStream, "application/octet-stream");//文件流方式,指定文件流对应的ContenType。
        }

文件上传结果通知类

 public class UploadResult
    {
        public int RepeatCount { get; set; }
        public int SuccessCount { get; set; }
        public int FileRepeatCount { get; set; }
        public int ErrorCount { get; set; }

        public List uploadErrors { get; set; }
    }
    public class UploadErrorDto
    {
        public string RowIndex { get; set; }
        public string ErrorCol { get; set; }
        public string ErrorData { get; set; }
    }

到此,文件上传和下载的后端就处理完毕了,通过以上处理后,我们就可以在前端实现文件的上传了,若上传失败则会返回失败结果,该结果是根据自己的业务逻辑来处理的,大家可以根据自己的业务逻辑来进行对应的处理

Vue实现Excel模板文件的上传与下载_第1张图片

5.结语

通过记录自己在项目中使用到的技术点,或者遇到的一些问题,来避免后续再碰到类似问题时无从下手。记录点滴开发日常,和大家分享开发经历和生活感悟。

你可能感兴趣的:(Vue,vue,excel)