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 相关文章推荐
web页面数据展示新想法(json)
Jun 08 Javascript
jquery中动态效果小结
Dec 16 Javascript
基于jQuery的输入框无值自动显示指定数据的实现代码
Jan 24 Javascript
event.X和event.clientX的区别分析
Oct 06 Javascript
jquery focus(fn),blur(fn)方法实例代码
Dec 16 Javascript
JS获取元素多层嵌套思路详解
May 16 Javascript
精彩的Bootstrap案例分享 重点在注释!(选项卡、栅格布局)
Jul 01 Javascript
jQuery 全选 全部选 反选 实现代码
Aug 17 Javascript
需要牢记的JavaScript基础知识
Sep 25 Javascript
jquery.pager.js分页实现详解
Jul 29 jQuery
关于layui表单中按钮自动提交的解决方法
Sep 09 Javascript
JS数组的常用10种方法详解
May 08 Javascript
开发中常用的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
php5 apache 2.2 webservice 创建与配置(java)
2011/01/27 PHP
PHP获取MSN好友列表类的实现代码
2013/06/23 PHP
php中current、next与reset函数用法实例
2014/11/17 PHP
discuz图片顺序混乱解决方案
2015/07/29 PHP
jQuery在IE下使用未闭合的xml代码创建元素时的Bug介绍
2012/01/10 Javascript
基于jQuery+Cookie实现的防止刷新的在线考试倒计时
2015/06/19 Javascript
jQuery实现下拉框多选 jquery-multiselect 的实例代码
2016/07/14 Javascript
H5实现仿flash效果的实现代码
2017/09/29 Javascript
vue-cli项目代理proxyTable配置exclude的方法
2018/09/20 Javascript
vue.js的vue-cli脚手架中使用百度地图API的实例
2019/01/21 Javascript
使用VUE实现在table中文字信息超过5个隐藏鼠标移到时弹窗显示全部
2019/09/16 Javascript
[29:23]2014 DOTA2国际邀请赛中国区预选赛 LGD-GAMING VS CIS 第一场1
2014/05/23 DOTA
Python 命令行非阻塞输入的小例子
2013/09/27 Python
实例讲解Python中的私有属性
2014/08/21 Python
详解Python安装scrapy的正确姿势
2018/06/26 Python
python3中os.path模块下常用的用法总结【推荐】
2018/09/16 Python
python linecache 处理固定格式文本数据的方法
2019/01/08 Python
Python学习笔记之Django创建第一个数据库模型的方法
2019/08/07 Python
Pandas中DataFrame基本函数整理(小结)
2020/07/20 Python
HTML5之web workers_动力节点Java学院整理
2017/07/17 HTML / CSS
HTML5触摸事件实现移动端简易进度条的实现方法
2018/05/04 HTML / CSS
西班牙网上书店:Casa del Libro
2016/11/01 全球购物
美国汽配连锁巨头Pep Boys官网:轮胎更换、汽车维修服务和汽车零部件
2017/01/14 全球购物
数控加工专业毕业生自荐信
2013/09/27 职场文书
临床医师专业个人自我评价范文
2013/11/07 职场文书
工程承包协议书范本
2014/09/29 职场文书
企业党的群众路线教育实践活动学习心得体会
2014/10/31 职场文书
世界红十字日活动总结
2015/02/10 职场文书
美术教师求职信范文
2015/03/20 职场文书
培训计划通知
2015/07/15 职场文书
运动会通讯稿100字
2015/07/20 职场文书
企业管理制度设计时要注意的几种“常见病”!
2019/04/19 职场文书
2019年国庆祝福语(70句)
2019/09/19 职场文书
Python学习之os包使用教程详解
2022/03/21 Python
Nginx动静分离配置实现与说明
2022/04/07 Servers
Mysql 数据库中的 redo log 和 binlog 写入策略
2022/04/26 MySQL