spring+angular实现导出excel的实现代码


Posted in Javascript onFebruary 27, 2019

需求描述

要求批量导出数据,以excel的格式。

选择方式

前台 + 后台

之前在别的项目中也遇到过导出的问题,解决方式是直接在前台导出将表格导出。

这次没有选择前台导出的方式,是由于需要导出所有的数据,所以考虑直接在后台获取所有的数据,然后就直接导出,最后前台触发导出API。

后台实现

导出使用的是POI,在上一篇文章中,我已做了基本的介绍,这里就不做介绍配置了,参照:POI实现将导入Excel文件

创建表格

首先先建立一张表,这里要建立.xlsx格式的表格,使用XSSFWorkbook:

Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("new sheet");

接着创建表格的行和单元格:

Row row = sheet.createRow(0);
row.createCell(0);

然后设置表头:

row.createCell(0).setCellValue("学号");
row.createCell(1).setCellValue("姓名");
row.createCell(2).setCellValue("手机号码");

最后获取所有的数据,对应的填写到单元格中:

int i = 1;
for (Student student : studentList) {
  row = sheet.createRow(i);
  row.createCell(0).setCellValue(student.getStudentNumber());
  row.createCell(1).setCellValue(student.getName());
  row.createCell(2).setCellValue(student.getPhoneNumber());
  i++;
}

输出

这部分是纠结比较久的,反复试了很多次。

一开始是直接以文件输出流的形式输出的:

FileOutputStream output = new FileOutputStream("test.xlsx");
workbook.write(output);

这样可以正确生成文件,但是问题是,它会生成在项目的根目录下。

而我们想要的效果是,下载在本地自己的文件夹中。

要解决这个问题,需要添加相应信息,返回给浏览器:

OutputStream fos = response.getOutputStream();
response.reset();
String fileName = "test";
fileName = URLEncoder.encode(fileName, "utf8");
response.setHeader("Content-disposition", "attachment;filename="+ fileName+".xlsx");

response.setCharacterEncoding("UTF-8");
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
workbook.write(fos);
fos.close();

后台完成代码:

public void batchExport(HttpServletResponse response) {
  logger.debug("创建工作表");
  Workbook workbook = new XSSFWorkbook();
  Sheet sheet = workbook.createSheet("new sheet");

  logger.debug("获取所有学生");
  List<Student> studentList = (List<Student>) studentRepository.findAll();

  logger.debug("建立表头");
  Row row = sheet.createRow(0);
  row.createCell(0).setCellValue("学号");
  row.createCell(1).setCellValue("姓名");
  row.createCell(2).setCellValue("手机号码");

  logger.debug("将学生信息写入对应单元格");
  int i = 1;
  for (Student student : studentList) {
    row = sheet.createRow(i);
    row.createCell(0).setCellValue(student.getStudentNumber());
    row.createCell(1).setCellValue(student.getName());
    row.createCell(2).setCellValue(student.getPhoneNumber()); 
    i++;
  }

  OutputStream fos;
  try {
    fos = response.getOutputStream();
    response.reset();
    String fileName = "test";
    fileName = URLEncoder.encode(fileName, "utf8");
    response.setHeader("Content-disposition", "attachment;filename="+ fileName+".xlsx");

    response.setCharacterEncoding("UTF-8");
    response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");// 设置contentType为excel格式
    workbook.write(fos);
    fos.close();

  } catch (Exception e) {
      e.printStackTrace();
  }
}

前台实现

在前台调用的时候,也经历了多次失败,google了很多篇文章,各种各样的写法都有,自己也是试了试,前台后台都对照做了很多尝试,但基本都是有问题的。这里我值给出我最后选择配套后台的方法。

// 后台导出路由
const exportUrl = '/api/student/batchExport';

// 创建a标签,并点击
let a = document.createElement('a');
document.body.appendChild(a);
a.setAttribute('style', 'display:none');
a.setAttribute('href', exportUrl);
a.click();
URL.revokeObjectURL(exportUrl);

最后的实现还是一种比较简单的方法,创建了一个a标签,然后隐式点击。

注意到这里我没有使用http请求,主要是他并不能触发浏览器的下载,在发起请求后,并没有正确的生成文件,具体是什么还不清楚。后面弄明白后我会再更新这篇文章。

升级

上面的形式,在导出所有的数据的时候是没有问题的,但是如果我想带一些参数呢?

另外,我们的项目是建立在nginx同源的基础上,一旦出现跨域问题,前台向后台请求,浏览器是不会默认携带Cookie的,每次请求都将会被看作是一个新的请求。

所以上面的解决办法有所限制。

那么,还可以怎么写呢?

file-saver

这里我将借助FileSaver来帮助我在前台生成excel文件。

this.http.get('student/batchExport', { responseType: 'blob'})
  .subscribe(data => {
    let blob = new Blob([data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8'});
    saveAs(blob, 'test.xlsx');
  });

用httpClient发起get请求,声明:响应类型为blob。

blob是一个用来存储二进制文件的对象。

然后创建一个blob对象,类型为excel格式。

最后,利用file-saver中的saveAs函数,将blob对象生成文件名为'test.xlsx'的excel文件。

调整后台

这里后台大部分和前面的是一样的,但是明眼人会发现,前台使用后面的方法后,下面的代码就多余了:

String fileName = "test";
fileName = URLEncoder.encode(fileName, "utf8");
response.setHeader("Content-disposition", "attachment;filename="+ fileName+".xlsx");

response.setCharacterEncoding("UTF-8");
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");

是的,我们将这一部分交由前台负责,所以后台对应的这部分就可以删除了,只使用response获取输出流就可以了:

OutputStream fos = response.getOutputStream();
workbook.write(fos);
fos.close();

好了,使用这种方法,我们就可以在发起http请求的时候,添加我们想要的参数了。

总结

我们在google的时候,很多时候,我们并不能一下子就找到我们想要的东西,但是并不是说这在做无用功,因为我们往往会在一些类似的文章中找到灵感。

所以,当我们没有直接找到我们想要的结果的时候,不妨大胆的做一些尝试,因为我们会在一次又一次失败的尝试中,慢慢的了解问题的原理到底是怎么回事。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js模拟淘宝网的多级选择菜单实现方法
Aug 18 Javascript
Bootstrap实现水平排列的表单
Jul 04 Javascript
jquery插件treegrid树状表格的使用方法详解(.Net平台)
Jan 03 Javascript
浅谈JavaScript中的apply/call/bind和this的使用
Feb 26 Javascript
值得分享和收藏的xmlplus组件学习教程
May 05 Javascript
基于ES6作用域和解构赋值详解
Nov 03 Javascript
Javascript中JSON数据分组优化实践及JS操作JSON总结
Dec 22 Javascript
Vue.js中的computed工作原理
Mar 22 Javascript
JavaScript引用类型Date常见用法实例分析
Aug 08 Javascript
VUE中v-on:click事件中获取当前dom元素的代码
Aug 22 Javascript
JavaScript实现拖拽盒子效果
Feb 06 Javascript
vue中的循环对象属性和属性值用法
Sep 04 Javascript
react native 原生模块桥接的简单说明小结
Feb 26 #Javascript
JavaScript实现获取两个排序数组的中位数算法示例
Feb 26 #Javascript
小程序hover-class点击态效果实现
Feb 26 #Javascript
JS实现计算小于非负数n的素数的数量算法示例
Feb 26 #Javascript
vue使用Font Awesome的方法步骤
Feb 26 #Javascript
JS实现的杨辉三角【帕斯卡三角形】算法示例
Feb 26 #Javascript
create-react-app使用antd按需加载的样式无效问题的解决
Feb 26 #Javascript
You might like
关于ThinkPhp 框架表单验证及ajax验证问题
2017/07/19 PHP
PHP使用反向Ajax技术实现在线客服系统详解
2019/07/01 PHP
30个最佳jQuery Lightbox效果插件分享
2011/04/11 Javascript
JQuery拖拽元素改变大小尺寸实现代码
2012/12/10 Javascript
JavaScript加入收藏夹功能(兼容IE、firefox、chrome)
2014/05/05 Javascript
jQuery中:gt选择器用法实例
2014/12/29 Javascript
JS实现的简洁纵向滑动菜单(滑动门)效果
2015/10/19 Javascript
设置jQueryUI DatePicker默认语言为中文
2016/06/04 Javascript
基于jQuery实现页面搜索功能
2020/03/26 Javascript
js实现弹窗居中的简单实例
2016/10/09 Javascript
ionic cordova一次上传多张图片(类似input file提交表单)的实现方法
2016/12/16 Javascript
js简单实现网页换肤功能
2017/04/07 Javascript
react-redux中connect()方法详细解析
2017/05/27 Javascript
详解vue2.0监听属性的使用心得及搭配计算属性的使用
2018/07/18 Javascript
Vue移动端实现图片上传及超过1M压缩上传
2019/12/23 Javascript
Python中字典的基本知识初步介绍
2015/05/21 Python
将Python的Django框架与认证系统整合的方法
2015/07/24 Python
详解Python3之数据指纹MD5校验与对比
2019/06/11 Python
Python中的 ansible 动态Inventory 脚本
2020/01/19 Python
解决tensorflow训练时内存持续增加并占满的问题
2020/01/19 Python
Pytorch转onnx、torchscript方式
2020/05/25 Python
python保留格式汇总各部门excel内容的实现思路
2020/06/01 Python
PyQt5.6+pycharm配置以及pyinstaller生成exe(小白教程)
2020/06/02 Python
css3利用transform变形结合事件完成扇形导航
2020/10/26 HTML / CSS
迪卡侬印尼体育用品商店:Decathlon印尼
2020/03/11 全球购物
银行办理业务介绍信
2014/01/18 职场文书
优秀幼教自荐信
2014/02/03 职场文书
关于母亲节的感言
2014/02/04 职场文书
促销活动总结报告
2014/04/26 职场文书
二年级上册数学教学计划
2015/01/20 职场文书
中秋节晚会开场白
2015/05/29 职场文书
放假通知怎么写
2015/08/18 职场文书
2016年暑期见闻作文
2015/11/25 职场文书
机关单位2016年法制宣传日活动总结
2016/04/01 职场文书
2016年法制宣传月活动总结
2016/04/01 职场文书
分析Netty直接内存原理及应用
2021/06/14 Java/Android