转载

spring + angular 实现导出excel

需求描述

要求批量导出数据,以 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 请求,主要是他并不能触发浏览器的下载,在发起请求后,并没有正确的生成文件,具体是什么还不清楚。后面弄明白后我会再更新这篇文章。

总结

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

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

原文  https://segmentfault.com/a/1190000018313073
正文到此结束
Loading...