资讯专栏INFORMATION COLUMN

想在Java中实现Excel和Csv的导出吗?看这就对了

olle / 522人阅读

摘要:将查询到的结果生成和文件,再以字节流的形式返回给前端。则是用于创建字节输出流,在导出文件的代码结尾,通过工具类中的复制文件函数将字节流写入到输出流中,从而将文件以字节流的形式返回给客户端。

title: 想在Java中实现Excel和Csv的导出吗?看这就对了
date: 2019-03-01 20:07:07
tags: Java
keywords: Java导出Excel和Csv

description: 前言

最近在项目中遇到一个需求,需要后端提供一个下载Csv和Excel表格的接口。这个接口接收前端的查询参数,针对这些参数对数据库做查询操作。将查询到的结果生成Excel和Csv文件,再以字节流的形式返回给前端。

前端拿到这个流文件之后,最开始用ajax来接收,但是前端发送的请求却被浏览器cancel掉了。后来发现,发展了如此之久的Ajax居然不支持流文件下载。后来前端换成了最原始的XMLHttpRequest,才修复了这个问题。

首先给出项目源码的地址。这是源码,欢迎大家star或者提MR。

Csv 新建controller

先来一个简单的例子。首先在controller中新建这样一个接口。

@GetMapping("csv")
public void csv(
        HttpServletRequest request,
        HttpServletResponse response
) throws IOException {
    String fileName = this.getFileName(request, "测试数据.csv");
    response.setContentType(MediaType.APPLICATION_OCTET_STREAM.toString());
    response.setHeader("Content-Disposition", "attachment; filename="" + fileName + "";");

    LinkedHashMap header = new LinkedHashMap<>();
    LinkedHashMap body = new LinkedHashMap<>();
    header.put("1", "姓名");
    header.put("2", "年龄");
    List> data = new ArrayList<>();
    body.put("1", "小明");
    body.put("2", "小王");
    data.add(header);
    data.add(body);
    data.add(body);
    data.add(body);
    FileCopyUtils.copy(ExportUtil.exportCSV(data), response.getOutputStream());
}

其中this.getFileName(request, "测试数据.csv")函数是用来获取导出文件名的函数。多带带提出来是因为不同浏览器使用的默认的编码不同。例如,如果使用默认的UTF-8编码。在chrome浏览器中下载会出现中文乱码。代码如下。

private String getFileName(HttpServletRequest request, String name) throws UnsupportedEncodingException {
    String userAgent = request.getHeader("USER-AGENT");
    return userAgent.contains("Mozilla") ? new String(name.getBytes(), "ISO8859-1") : name;
}

response.getOutputStream()则是用于创建字节输出流,在导出csv文件的controller代码结尾,通过工具类中的复制文件函数将字节流写入到输出流中,从而将csv文件以字节流的形式返回给客户端。

当前端通过http请求访问服务器接口的时候,http中的所有的请求信息都会封装在HttpServletRequest对象中。例如,你可以通过这个对象获取到请求的URL地址,请求的方式,请求的客户端IP和完整主机名,Web服务器的IP和完整主机名,请求行中的参数,获取请求头的参数等等。

针对每一次的HTTP请求,服务器会自动创建一个HttpServletResponse对象和请求对象相对应。响应对象可以对当前的请求进行重定向,自定义响应体的头部,设置返回流等等。

新建导出工具类

我们新建一个导出工具类,来专门负责导出各种格式的文件。代码如下。

public class ExportUtil {

    public static byte[] exportCSV(List> exportData) {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        BufferedWriter buffCvsWriter = null;
        try {
            buffCvsWriter = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8));
            // 将body数据写入表格
            for (Iterator> iterator = exportData.iterator(); iterator.hasNext(); ) {
                fillDataToCsv(buffCvsWriter, iterator.next());
                if (iterator.hasNext()) {
                    buffCvsWriter.newLine();
                }
            }
            // 刷新缓冲
            buffCvsWriter.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 释放资源
            if (buffCvsWriter != null) {
                try {
                    buffCvsWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return out.toByteArray();
    }

    private static void fillDataToCsv(BufferedWriter buffCvsWriter, LinkedHashMap row) throws IOException {
        Map.Entry propertyEntry;
        for (Iterator propertyIterator = row.entrySet().iterator(); propertyIterator.hasNext(); ) {
            propertyEntry = propertyIterator.next();
            buffCvsWriter.write(""" + propertyEntry.getValue().toString() + """);
            if (propertyIterator.hasNext()) {
                buffCvsWriter.write(",");
            }
        }
    }
}

fillDataToCsv主要是抽离出来为csv填充一行一行的数据的。

运行

然后运行项目,调用http://localhost:8080/csv,就可以下载示例的csv文件。示例如下。

Excel 新建controller

新建下载xlsx文件的接口。

@GetMapping("xlsx")
public void xlsx(
        HttpServletRequest request,
        HttpServletResponse response
) throws IOException {
    String fileName = this.getFileName(request, "测试数据.xlsx");
    response.setContentType(MediaType.APPLICATION_OCTET_STREAM.toString());
    response.setHeader("Content-Disposition", "attachment; filename="" + fileName + "";");

    List> datas = new ArrayList<>();
    LinkedHashMap data = new LinkedHashMap<>();
    data.put("1", "姓名");
    data.put("2", "年龄");
    datas.add(data);
    for (int i = 0; i < 5; i++) {
        data = new LinkedHashMap<>();
        data.put("1", "小青");
        data.put("2", "小白");
        datas.add(data);
    }

    Map>> tableData = new HashMap<>();
    tableData.put("日报表", datas);
    tableData.put("周报表", datas);
    tableData.put("月报表", datas);

    FileCopyUtils.copy(ExportUtil.exportXlsx(tableData), response.getOutputStream());
}
补充工具类

上面新建的导出工具类中,只有导出csv的函数,接下来我们要添加导出xlsx的函数。

public static byte[] exportXlsx(Map>> tableData) {
    ByteArrayOutputStream out = new ByteArrayOutputStream();

    try {
        HSSFWorkbook workbook = new HSSFWorkbook();
        // 创建多个sheet
        for (Map.Entry>> entry : tableData.entrySet()) {
            fillDataToXlsx(workbook.createSheet(entry.getKey()), entry.getValue());
        }

        workbook.write(out);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return out.toByteArray();
}

/**
 * 将linkedHashMap中的数据,写入xlsx表格中
 *
 * @param sheet
 * @param data
 */
private static void fillDataToXlsx(HSSFSheet sheet, List> data) {
    HSSFRow currRow;
    HSSFCell cell;
    LinkedHashMap row;
    Map.Entry propertyEntry;
    int rowIndex = 0;
    int cellIndex = 0;
    for (Iterator> iterator = data.iterator(); iterator.hasNext(); ) {
        row = iterator.next();
        currRow = sheet.createRow(rowIndex++);
        for (Iterator propertyIterator = row.entrySet().iterator(); propertyIterator.hasNext(); ) {
            propertyEntry = propertyIterator.next();
            if (propertyIterator.hasNext()) {
                String value = String.valueOf(propertyEntry.getValue());
                cell = currRow.createCell(cellIndex++);
                cell.setCellValue(value);
            } else {
                String value = String.valueOf(propertyEntry.getValue());
                cell = currRow.createCell(cellIndex++);
                cell.setCellValue(value);
                break;
            }
        }
        if (iterator.hasNext()) {
            cellIndex = 0;
        }
    }
}

fillDataToXlsx的用途与csv一样,为xlsx文件的每一行刷上数据。

运行

然后运行项目,调用http://localhost:8080/xlsx,就可以下载示例的csv文件。示例如下。

项目地址

最后再次给出项目地址,大家如果没有理解到其中的一些地方,不妨把项目clone下来,自己亲自操作一波。

参考

这是在解决请求被浏览器cancel掉的过程中,很重要的一个参考,分享给大家。

https://www.cnblogs.com/cdemo...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/73642.html

相关文章

  • 【HTML5版】导出Table数据并保存为Excel

    摘要:首发我的博客最近接到这么个需求,要把显示的数据导出成表。之,发现又成了一座分水岭。后来开放标准,可以导出格式的文件,就有了用武之地,导出数据并保存为有了更好的选择。输出内容套用模版之后,我们就有了完整的表格数据。至此,此项功能宣告圆满。 首发我的博客 http://blog.meathill.com/tech/js/export-table-data-into-a-excel-f...

    abson 评论0 收藏0
  • 在 Laravel 5 中使用 Laravel Excel Excel/CSV 文件导入导出

    摘要:本文非原创,基于学院在中使用实现文件导入导出功能这篇文章在实际中测试调整。简介在中集成套件中的,从而方便我们以优雅的富有表现力的代码实现文件的导入和导出。 本文非原创,基于laravel 学院《在 Laravel 5 中使用 Laravel Excel 实现 Excel/CSV 文件导入导出功能》 这篇文章在实际中测试调整。 showImg(https://segmentfault.c...

    XFLY 评论0 收藏0
  • Vue 2019开发者图谱

    摘要:为了便于您更清晰的理解的体系架构,在这里我将为您展示年开发者知识图谱,它包含了所有开发过程中的关键部分。在数据展示前端导入导出图表面板数据绑定等场景无需大量代码开发和测试,可极大节省企业研发成本并降低交付风险。 作为 Vue 的初学者,您或许已经听过很多关于它的专业术语了,例如:单页面应用程序、异步组件、服务器端呈现等,您可能还听过和Vue经常一起被提到的工具和库,如Vuex、Webp...

    cgspine 评论0 收藏0
  • JavaScript中错误正确处理方式,你用对了

    摘要:单元测试会体现出以上错误处理程序的作用如果出现问题,错误处理程序就会返回。同时错误会展开堆栈,这对调试非常有帮助。展开堆栈处理异常的一种方式是在调用堆栈的顶部加入。确保你的错误处理处在相同域中,这样会保留原始消息,堆栈和自定义错误对象。 JavaScript的事件驱动范式增添了丰富的语言,也是让使用JavaScript编程变得更加多样化。如果将浏览器设想为JavaScript的事件驱动...

    chaos_G 评论0 收藏0
  • PHP高效导出Excel(CSV)

    摘要:,是逗号分隔值的英文缩写,通常都是纯文本文件。如果你导出的没有什么高级用法的话,只是做导出数据用那么建议使用本方法要比要高效的多。二十万数据导出大概需要到秒。 CSV,是Comma Separated Value(逗号分隔值)的英文缩写,通常都是纯文本文件。如果你导出的Excel没有什么高级用法的话,只是做导出数据用那么建议使用本方法,要比PHPexcel要高效的多。二十万数据导出大概...

    DoINsiSt 评论0 收藏0

发表评论

0条评论

olle

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<