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 相关文章推荐
YUI 读码日记之 YAHOO.lang.is*
Mar 22 Javascript
IE innerHTML,outerHTML所引起的问题
Jun 04 Javascript
Javascript 判断Flash是否加载完成的代码
Apr 12 Javascript
javascript数组去重方法终极总结
Jun 05 Javascript
使用node.js 获取客户端信息代码分享
Nov 26 Javascript
开启BootStrap学习之旅
May 04 Javascript
js实现可控制左右方向的无缝滚动效果
May 29 Javascript
JS中正则表达式只有3种匹配模式(没有单行模式)详解
Jul 28 Javascript
JavaScript实现的CRC32函数示例
Nov 23 Javascript
JavaScript hasOwnProperty() 函数实例详解
Aug 04 Javascript
详解React项目的服务端渲染改造(koa2+webpack3.11)
Mar 19 Javascript
JavaScript隐式类型转换代码实例
May 29 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
使用Apache的rewrite技术
2006/06/22 PHP
用PHP4访问Oracle815
2006/10/09 PHP
PHP实现通过正则表达式替换回调的内容标签
2015/06/15 PHP
PHP实现可自定义样式的分页类
2016/03/29 PHP
浏览器加载、渲染和解析过程黑箱简析
2012/11/29 Javascript
当自定义数据属性为json格式字符串时jQuery的data api问题探讨
2013/02/18 Javascript
LABjs、RequireJS、SeaJS的区别
2014/03/04 Javascript
邮箱下拉自动填充选择示例代码附图
2014/04/03 Javascript
JavaScript不刷新实现浏览器的前进后退功能
2014/11/05 Javascript
jQuery中attr()与prop()函数用法实例详解(附用法区别)
2015/12/29 Javascript
AngularJs ng-route路由详解及实例代码
2016/09/14 Javascript
AngularJS $injector 依赖注入详解
2016/09/14 Javascript
node.js文件上传处理示例
2016/10/27 Javascript
JavaScript数据结构之二叉树的遍历算法示例
2017/04/13 Javascript
ionic2屏幕适配实现适配手机、平板等设备的示例代码
2017/08/11 Javascript
vue升级之路之vue-router的使用教程
2018/08/14 Javascript
[01:05:52]DOTA2-DPC中国联赛 正赛 Ehome vs Aster BO3 第一场 2月2日
2021/03/11 DOTA
python3抓取中文网页的方法
2015/07/28 Python
深度定制Python的Flask框架开发环境的一些技巧总结
2016/07/12 Python
python+pillow绘制矩阵盖尔圆简单实例
2018/01/16 Python
python保存网页图片到本地的方法
2018/07/24 Python
Django的models模型的具体使用
2019/07/15 Python
Pytorch 抽取vgg各层并进行定制化处理的方法
2019/08/20 Python
Python+OpenCv制作证件图片生成器的操作方法
2019/08/21 Python
Python使用grequests(gevent+requests)并发发送请求过程解析
2019/09/25 Python
python opencv如何实现图片绘制
2020/01/19 Python
安全资料员岗位职责
2013/12/14 职场文书
《理想的风筝》教学反思
2014/04/11 职场文书
学校教研活动总结
2014/07/02 职场文书
《中国梦我的梦》小学生演讲稿
2014/08/20 职场文书
综合实践活动报告
2015/02/05 职场文书
社区党员干部承诺书
2015/05/04 职场文书
承诺书范本大全
2015/05/04 职场文书
教师节班会开场白
2015/06/01 职场文书
预备党员半年考察意见
2015/06/01 职场文书
2019大学生暑期实习心得总结
2019/08/21 职场文书