经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring » 查看文章
spring+angular实现导出excel的实现代码
来源:jb51  时间:2019/2/27 10:37:25  对本文有异议

需求描述

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

选择方式

前台 + 后台

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

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

后台实现

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

创建表格

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

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

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

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

然后设置表头:

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

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

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

输出

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

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

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

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

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

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

  1. OutputStream fos = response.getOutputStream();
  2. response.reset();
  3. String fileName = "test";
  4. fileName = URLEncoder.encode(fileName, "utf8");
  5. response.setHeader("Content-disposition", "attachment;filename="+ fileName+".xlsx");
  6.  
  7. response.setCharacterEncoding("UTF-8");
  8. response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
  9. workbook.write(fos);
  10. fos.close();

后台完成代码:

  1. public void batchExport(HttpServletResponse response) {
  2. logger.debug("创建工作表");
  3. Workbook workbook = new XSSFWorkbook();
  4. Sheet sheet = workbook.createSheet("new sheet");
  5.  
  6. logger.debug("获取所有学生");
  7. List<Student> studentList = (List<Student>) studentRepository.findAll();
  8.  
  9. logger.debug("建立表头");
  10. Row row = sheet.createRow(0);
  11. row.createCell(0).setCellValue("学号");
  12. row.createCell(1).setCellValue("姓名");
  13. row.createCell(2).setCellValue("手机号码");
  14.  
  15. logger.debug("将学生信息写入对应单元格");
  16. int i = 1;
  17. for (Student student : studentList) {
  18. row = sheet.createRow(i);
  19. row.createCell(0).setCellValue(student.getStudentNumber());
  20. row.createCell(1).setCellValue(student.getName());
  21. row.createCell(2).setCellValue(student.getPhoneNumber());
  22. i++;
  23. }
  24.  
  25. OutputStream fos;
  26. try {
  27. fos = response.getOutputStream();
  28. response.reset();
  29. String fileName = "test";
  30. fileName = URLEncoder.encode(fileName, "utf8");
  31. response.setHeader("Content-disposition", "attachment;filename="+ fileName+".xlsx");
  32.  
  33. response.setCharacterEncoding("UTF-8");
  34. response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");// 设置contentType为excel格式
  35. workbook.write(fos);
  36. fos.close();
  37.  
  38. } catch (Exception e) {
  39. e.printStackTrace();
  40. }
  41. }

前台实现

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

  1. // 后台导出路由
  2. const exportUrl = '/api/student/batchExport';
  3.  
  4. // 创建a标签,并点击
  5. let a = document.createElement('a');
  6. document.body.appendChild(a);
  7. a.setAttribute('style', 'display:none');
  8. a.setAttribute('href', exportUrl);
  9. a.click();
  10. URL.revokeObjectURL(exportUrl);
  11.  

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

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

升级

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

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

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

那么,还可以怎么写呢?

file-saver

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

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

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

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

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

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

调整后台

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

  1. String fileName = "test";
  2. fileName = URLEncoder.encode(fileName, "utf8");
  3. response.setHeader("Content-disposition", "attachment;filename="+ fileName+".xlsx");
  4.  
  5. response.setCharacterEncoding("UTF-8");
  6. response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");

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

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

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

总结

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

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

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

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号