vue实现Excel文件的上传与下载功能的两种方式


Posted in Javascript onJune 28, 2019

一.前言项目中使用到比较多的关于Excel的前端上传与下载,整理出来,以便后续使用或分析他人。

1.前端vue:模板下载与导入Excel

导入Excel封装了子组件,点击导入按钮可调用子组件,打开文件上传的对话框,上传成功后返回结果

<el-col style="padding: 10px 0 20px;">
    <el-button
     class="pull-right"
     icon="el-icon-upload"
     type="primary"
     size="mini"
     @click="importFile()"
    >批量导入</el-button>
    <el-button
     class="pull-right right-10"
     icon="el-icon-download"
     type="primary"
     size="mini"
     @click="downloadFile('档案模板')"
    >模板下载</el-button>
    <el-button
     size="mini"
     type="primary"
     icon="el-icon-plus"
     class="pull-right"
     @click="addRow"
    >新增</el-button>
    <div class="pull-right">
     <el-input
      placeholder="请输入编码,名称"
      prefix-icon="el-icon-search"
      v-model="FinQueryParams.archiveFilter"
      size="mini"
     ></el-input>
    </div>
   </el-col>

 <!-- 批量导入Dialog开始 -->
  <uploadTemp
   :apiURL="fileUploadUrl"
   ref="refFileUpload"
   :Refresh="Refresh"
   :OtherParams="{brandId: QueryParams.BrandID}"
  ></uploadTemp>
  <!-- 批量导入Dialog结束 -->
importFile() {
  this.$refs.refFileUpload.open();
 } 

向后台提交文件的方法

submitFile() {
   const _this = this;
   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 => {
     console.log(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"
       });
      }
     }
    })
    .catch(function(error) {
     console.log(error);
    });
  },

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

2.模板下载

关于模板下载,之前没有考虑到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);
    }
   });
  },

前端的处理就结束了。

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;
      }

    }
文件下载比较简单

 public async Task<FileStreamResult> 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 async Task<FileStreamResult> 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<UploadErrorDto> uploadErrors { get; set; }
  }
  public class UploadErrorDto
  {
    public string RowIndex { get; set; }
    public string ErrorCol { get; set; }
    public string ErrorData { get; set; }
  } 

 通过以上处理后,我们就可以在前端实现文件的上传了,若上传失败则会返回失败结果

 以上就是整个前后端关于文件上传与下载的实现,想通过日常记录这种方式,来帮助自己更好的掌握基础,稳固自己的技能

总结

以上所述是小编给大家介绍的vue实现Excel文件的上传与下载功能的两种方式,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

Javascript 相关文章推荐
HTML IMG标签 onload 内存溢出导致浏览器CPU占用过高
Mar 09 Javascript
javascript中this做事件参数相关问题解答
Mar 17 Javascript
js 数值转换为3位逗号分隔的示例代码
Feb 19 Javascript
js函数模拟显示桌面.scf程序示例
Apr 20 Javascript
使用AngularJS制作一个简单的RSS阅读器的教程
Jun 18 Javascript
JS获取下拉框显示值和判断单选按钮的方法
Jul 09 Javascript
如何通过js实现图片预览功能【附实例代码】
Mar 30 Javascript
js实现4个方向滚动的球
Mar 06 Javascript
Node.js编写CLI的实例详解
May 17 Javascript
vue 设置proxyTable参数进行代理跨域
Apr 09 Javascript
使用webpack搭建vue项目实现脚手架功能
Mar 15 Javascript
jquery添加div实现消息聊天框
Feb 08 jQuery
开发中常用的25个JavaScript单行代码(小结)
Jun 28 #Javascript
微信小程序身份证验证方法实现详解
Jun 28 #Javascript
jQuery属性选择器用法实例分析
Jun 28 #jQuery
jQuery位置选择器用法实例分析
Jun 28 #jQuery
jQuery层叠选择器用法实例分析
Jun 28 #jQuery
jQuery内容选择器与表单选择器实例分析
Jun 28 #jQuery
jQuery子选择器与可见性选择器实例分析
Jun 28 #jQuery
You might like
学习discuz php 引入文件的方法DISCUZ_ROOT
2009/06/21 PHP
php 字符串替换的方法
2012/01/10 PHP
php使用curl实现ftp文件下载功能
2017/05/16 PHP
js计数器代码
2006/11/04 Javascript
JavaScript 闭包在封装函数时的简单分析
2009/11/28 Javascript
js下将字符串当函数执行的方法
2011/07/13 Javascript
Node.js与Sails ~项目结构与Mvc实现及日志机制
2015/10/14 Javascript
javascript实现网页端解压并查看zip文件
2015/12/15 Javascript
Jquery AJAX POST与GET之间的区别详细介绍
2016/10/17 Javascript
JS Select下拉框(支持输入模糊查询)
2017/02/04 Javascript
深入浅析Vue中的 computed 和 watch
2018/06/06 Javascript
JS实现的全选、全不选及反选功能【案例】
2019/02/19 Javascript
8个有意思的JavaScript面试题
2019/07/30 Javascript
vue中 v-for循环的用法详解
2020/02/19 Javascript
vuex Module将 store 分割成模块的操作
2020/12/07 Vue.js
[03:54]DOTA2英雄梦之声_第06期_昆卡
2014/06/23 DOTA
Python运用于数据分析的简单教程
2015/03/27 Python
python实现解数独程序代码
2017/04/12 Python
实例讲解python中的序列化知识点
2018/10/08 Python
Python脚本按照当前日期创建多级目录
2019/03/01 Python
Python数据存储之 h5py详解
2019/12/26 Python
PyTorch加载自己的数据集实例详解
2020/03/18 Python
Python修改DBF文件指定列
2020/12/19 Python
HTML5自定义属性的问题分析
2019/08/16 HTML / CSS
ReVive利维肤美国官网:RéVive Skincare
2018/04/18 全球购物
Cynthia Rowley官网:全球领先的生活方式品牌
2020/10/27 全球购物
如何设定的weblogic的热启动模式(开发模式)与产品发布模式
2012/09/08 面试题
Ajax实现页面无刷新留言效果
2021/03/24 Javascript
优秀实习自我鉴定
2013/12/04 职场文书
六查六看自查报告
2014/10/14 职场文书
债务纠纷委托书范本
2014/10/14 职场文书
支行行长岗位职责
2015/02/15 职场文书
《藏戏》教学反思
2016/02/23 职场文书
工作计划范文之财务管理
2019/08/09 职场文书
pytorch损失反向传播后梯度为none的问题
2021/05/12 Python
python munch库的使用解析
2021/05/25 Python