Excel工具-HUTOOL-输出Excel

简介: 基于Hutool与Apache POI,封装Excel写入功能,提供ExcelWriter和BigExcelWriter,支持List、Map、Bean等数据类型导出,可自定义样式、多Sheet操作,并避免内存溢出,适用于高效生成Excel文件及Web下载场景。

依赖


cn.hutool
hutool-all
5.3.10


org.apache.poi
poi-ooxml
4.1.2

由来
Excel有读取也便有写出,Hutool针对将数据写出到Excel做了封装。
原理
Hutool将Excel写出封装为ExcelWriter,原理为包装了Workbook对象,每次调用merge(合并单元格)或者write(写出数据)方法后只是将数据写入到Workbook,并不写出文件,只有调用flush或者close方法后才会真正写出文件。
由于机制原因,在写出结束后需要关闭ExcelWriter对象,调用close方法即可关闭,此时才会释放Workbook对象资源,否则带有数据的Workbook一直会常驻内存。
使用例子

  1. 将行列对象写出到Excel
    我们先定义一个嵌套的List,List的元素也是一个List,内层的一个List代表一行数据,每行都有4个单元格,最终list对象代表多行数据。
    List row1 = CollUtil.newArrayList("aa", "bb", "cc", "dd");
    List row2 = CollUtil.newArrayList("aa1", "bb1", "cc1", "dd1");
    List row3 = CollUtil.newArrayList("aa2", "bb2", "cc2", "dd2");
    List row4 = CollUtil.newArrayList("aa3", "bb3", "cc3", "dd3");
    List row5 = CollUtil.newArrayList("aa4", "bb4", "cc4", "dd4");
    List> rows = CollUtil.newArrayList(row1, row2, row3, row4, row5);Copy to clipboardErrorCopied
    然后我们创建ExcelWriter对象后写出数据:
    //通过工具类创建writer
    ExcelWriter writer = ExcelUtil.getWriter("d:/writeTest.xlsx");
    //通过构造方法创建writer
    //ExcelWriter writer = new ExcelWriter("d:/writeTest.xls");
    //跳过当前行,既第一行,非必须,在此演示用
    writer.passCurrentRow();
    //合并单元格后的标题行,使用默认标题样式
    writer.merge(row1.size() - 1, "测试标题");
    //一次性写出内容,强制输出标题
    writer.write(rows, true);
    //关闭writer,释放内存
    writer.close();Copy to clipboardErrorCopied
    效果:
  2. 写出Map数据
    构造数据:
    Map row1 = new LinkedHashMap<>();
    row1.put("姓名", "张三");
    row1.put("年龄", 23);
    row1.put("成绩", 88.32);
    row1.put("是否合格", true);
    row1.put("考试日期", DateUtil.date());
    Map row2 = new LinkedHashMap<>();
    row2.put("姓名", "李四");
    row2.put("年龄", 33);
    row2.put("成绩", 59.50);
    row2.put("是否合格", false);
    row2.put("考试日期", DateUtil.date());
    ArrayList> rows = CollUtil.newArrayList(row1, row2);Copy to clipboardErrorCopied
    写出数据:
    // 通过工具类创建writer
    ExcelWriter writer = ExcelUtil.getWriter("d:/writeMapTest.xlsx");
    // 合并单元格后的标题行,使用默认标题样式
    writer.merge(rows.size() - 1, "一班成绩单");
    // 一次性写出内容,使用默认样式,强制输出标题
    writer.write(rows, true);
    // 关闭writer,释放内存
    writer.close();Copy to clipboardErrorCopied
    效果:
  3. 写出Bean数据
    定义Bean:
    public class TestBean {
    private String name;
    private int age;
    private double score;
    private boolean isPass;
    private Date examDate;
    public String getName() {
     return name;
    
    }
    public void setName(String name) {
     this.name = name;
    
    }
    public int getAge() {
     return age;
    
    }
    public void setAge(int age) {
     this.age = age;
    
    }
    public double getScore() {
     return score;
    
    }
    public void setScore(double score) {
     this.score = score;
    
    }
    public boolean isPass() {
     return isPass;
    
    }
    public void setPass(boolean isPass) {
     this.isPass = isPass;
    
    }
    public Date getExamDate() {
     return examDate;
    
    }
    public void setExamDate(Date examDate) {
     this.examDate = examDate;
    
    }
    }Copy to clipboardErrorCopied
    构造数据:
    TestBean bean1 = new TestBean();
    bean1.setName("张三");
    bean1.setAge(22);
    bean1.setPass(true);
    bean1.setScore(66.30);
    bean1.setExamDate(DateUtil.date());
    TestBean bean2 = new TestBean();
    bean2.setName("李四");
    bean2.setAge(28);
    bean2.setPass(false);
    bean2.setScore(38.50);
    bean2.setExamDate(DateUtil.date());
    List rows = CollUtil.newArrayList(bean1, bean2);Copy to clipboardErrorCopied
    写出数据:
    // 通过工具类创建writer
    ExcelWriter writer = ExcelUtil.getWriter("d:/writeBeanTest.xlsx");
    // 合并单元格后的标题行,使用默认标题样式
    writer.merge(4, "一班成绩单");
    // 一次性写出内容,使用默认样式,强制输出标题
    writer.write(rows, true);
    // 关闭writer,释放内存
    writer.close();Copy to clipboardErrorCopied
    效果:
  4. 自定义Bean的key别名(排序标题)
    在写出Bean的时候,我们可以调用ExcelWriter对象的addHeaderAlias方法自定义Bean中key的别名,这样就可以写出自定义标题了(例如中文)。
    写出数据:
    // 通过工具类创建writer
    ExcelWriter writer = ExcelUtil.getWriter("d:/writeBeanTest.xlsx");
    //自定义标题别名
    writer.addHeaderAlias("name", "姓名");
    writer.addHeaderAlias("age", "年龄");
    writer.addHeaderAlias("score", "分数");
    writer.addHeaderAlias("isPass", "是否通过");
    writer.addHeaderAlias("examDate", "考试时间");
    // 合并单元格后的标题行,使用默认标题样式
    writer.merge(4, "一班成绩单");
    // 一次性写出内容,使用默认样式,强制输出标题
    writer.write(rows, true);
    // 关闭writer,释放内存
    writer.close();Copy to clipboardErrorCopied
    效果:
    提示(since 4.1.5) 默认情况下Excel中写出Bean字段不能保证顺序,此时可以使用addHeaderAlias方法设置标题别名,Bean的写出顺序就会按照标题别名的加入顺序排序。 如果不需要设置标题但是想要排序字段,请调用writer.addHeaderAlias("age", "age")设置一个相同的别名就可以不更换标题。 未设置标题别名的字段不参与排序,会默认排在前面。
  5. 写出到流
    // 通过工具类创建writer,默认创建xls格式
    ExcelWriter writer = ExcelUtil.getWriter();
    //创建xlsx格式的
    //ExcelWriter writer = ExcelUtil.getWriter(true);
    // 一次性写出内容,使用默认样式,强制输出标题
    writer.write(rows, true);
    //out为OutputStream,需要写出到的目标流
    writer.flush(out);
    // 关闭writer,释放内存
    writer.close();Copy to clipboardErrorCopied
  6. 写出到客户端下载(写出到Servlet)
  7. 写出xls
    // 通过工具类创建writer,默认创建xls格式
    ExcelWriter writer = ExcelUtil.getWriter();
    // 一次性写出内容,使用默认样式,强制输出标题
    writer.write(rows, true);
    //out为OutputStream,需要写出到的目标流
    //response为HttpServletResponse对象
    response.setContentType("application/vnd.ms-excel;charset=utf-8");
    //test.xls是弹出下载对话框的文件名,不能为中文,中文请自行编码
    response.setHeader("Content-Disposition","attachment;filename=test.xls");
    ServletOutputStream out=response.getOutputStream();
    writer.flush(out, true);
    // 关闭writer,释放内存
    writer.close();
    //此处记得关闭输出Servlet流
    IoUtil.close(out);Copy to clipboardErrorCopied
  8. 写出xlsx
    ExcelWriter writer = ExcelUtil.getWriter(true);
    writer.write(rows, true);
    response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
    response.setHeader("Content-Disposition","attachment;filename=test.xlsx");
    writer.flush(out, true);
    writer.close();
    IoUtil.close(out);Copy to clipboardErrorCopied
    注意 ExcelUtil.getWriter()默认创建xls格式的Excel,因此写出到客户端也需要自定义文件名为XXX.xls,否则会出现文件损坏的提示。 若想生成xlsx格式,请使用ExcelUtil.getWriter(true)创建。
  9. 下载提示文件损坏问题解决
    有用户反馈按照代码生成的Excel下载后提示文件损坏,无法打开,经过排查,可能是几个问题:
    ● (1)writer和out流没有正确关闭,请在代码末尾的finally块增加关闭。
    ● (2)扩展名不匹配。getWriter默认生成xls,Content-Disposition中也应该是xls,只有getWriter(true)时才可以使用xlsx
    ● (3)Maven项目中Excel保存于ClassPath中(src/main/resources下)宏替换导致被破坏,解决办法是添加filtering(参考:https://blog.csdn.net/qq_42270377/article/details/92771349)
    ● (4)Excel打开提示文件损坏,WPS可以打开。这是Excel的安全性控制导致的,解决办法见:https://blog.csdn.net/zm9898/article/details/99677626
    自定义Excel
  10. 设置单元格背景色
    ExcelWriter writer = ...;
    // 定义单元格背景色
    StyleSet style = writer.getStyleSet();
    // 第二个参数表示是否也设置头部单元格背景
    style.setBackgroundColor(IndexedColors.RED, false);Copy to clipboardErrorCopied
  11. 自定义字体
    ExcelWriter writer = ...;
    //设置内容字体
    Font font = writer.createFont();
    font.setBold(true);
    font.setColor(Font.COLOR_RED);
    font.setItalic(true);
    //第二个参数表示是否忽略头部样式
    writer.getStyleSet().setFont(font, true);Copy to clipboardErrorCopied
  12. 写出多个sheet
    //初始化时定义表名
    ExcelWriter writer = new ExcelWriter("d:/aaa.xls", "表1");
    //切换sheet,此时从第0行开始写
    writer.setSheet("表2");
    ...
    writer.setSheet("表3");
    ...Copy to clipboardErrorCopied
  13. 更详细的定义样式
    在Excel中,由于样式对象个数有限制,因此Hutool根据样式种类分为4个样式对象,使相同类型的单元格可以共享样式对象。样式按照类别存在于StyleSet中,其中包括:
    ● 头部样式 headCellStyle
    ● 普通单元格样式 cellStyle
    ● 数字单元格样式 cellStyleForNumber
    ● 日期单元格样式 cellStyleForDate
    其中cellStyleForNumber cellStyleForDate用于控制数字和日期的显示方式。
    因此我们可以使用以下方式获取CellStyle对象自定义指定种类的样式:
    StyleSet style = writer.getStyleSet();
    CellStyle cellStyle = style.getHeadCellStyle();
    ..

Excel大数据生成-BigExcelWriter
介绍
对于大量数据输出,采用ExcelWriter容易引起内存溢出,因此有了BigExcelWriter,使用方法与ExcelWriter完全一致。
使用
List<?> row1 = CollUtil.newArrayList("aa", "bb", "cc", "dd", DateUtil.date(), 3.22676575765);
List<?> row2 = CollUtil.newArrayList("aa1", "bb1", "cc1", "dd1", DateUtil.date(), 250.7676);
List<?> row3 = CollUtil.newArrayList("aa2", "bb2", "cc2", "dd2", DateUtil.date(), 0.111);
List<?> row4 = CollUtil.newArrayList("aa3", "bb3", "cc3", "dd3", DateUtil.date(), 35);
List<?> row5 = CollUtil.newArrayList("aa4", "bb4", "cc4", "dd4", DateUtil.date(), 28.00);
List> rows = CollUtil.newArrayList(row1, row2, row3, row4, row5);
BigExcelWriter writer= ExcelUtil.getBigWriter("e:/xxx.xlsx");
// 一次性写出内容,使用默认样式
writer.write(rows);
// 关闭writer,释放内存
writer.close();

目录
相关文章
|
2月前
|
Java 大数据 Apache
Excel工具-HUTOOL-输出Excel
Hutool基于Apache POI封装了Excel读写功能,提供ExcelWriter和BigExcelWriter类,支持写出List、Map、Bean等数据类型到Excel,可自定义样式、多sheet操作,并解决大数据量导出时的内存溢出问题,适用于文件导出、客户端下载等场景。
|
XML SQL Java
ClickHouse【SpringBoot集成】clickhouse+mybatis-plus配置及使用问题说明(含建表语句、demo源码、测试说明)
ClickHouse【SpringBoot集成】clickhouse+mybatis-plus配置及使用问题说明(含建表语句、demo源码、测试说明)
2280 0
|
2月前
|
Apache
Excel工具-HUTOOL-读取Excel
基于Hutool和Apache POI,封装Excel读取工具,支持xls/xlsx格式。可读取为List、Map或Bean,提供Sax模式(Excel03SaxReader/Excel07SaxReader)高效处理大文件,避免内存溢出,适用于海量数据流式读取。
|
8月前
|
Prometheus 监控 Cloud Native
|
关系型数据库 MySQL 数据库
什么是数据库触发器?
【8月更文挑战第3天】
1925 10
什么是数据库触发器?
|
数据可视化 Python
我是如何把python获取到的数据写入Excel的?
我是如何把python获取到的数据写入Excel的?
312 2
|
XML Java 关系型数据库
SpringBoot整合ClickHouse
SpringBoot整合ClickHouse
1691 0
|
NoSQL 前端开发 Java
使用 Spring Boot + Neo4j 实现知识图谱功能开发
在数据驱动的时代,知识图谱作为一种强大的信息组织方式,正逐渐在各个领域展现出其独特的价值。本文将围绕使用Spring Boot结合Neo4j图数据库来实现知识图谱功能开发的技术细节进行分享,帮助读者理解并掌握这一技术栈在实际项目中的应用。
1201 4
idea启动java服务报错OutOfMemoryError: GC overhead limit exceeded解决方法
idea启动java服务报错OutOfMemoryError: GC overhead limit exceeded解决方法
6491 3
|
数据可视化 Java 程序员
IDEA插件-Maven Helper
Maven Helper是一个用于Apache Maven项目的IntelliJ IDEA插件,它提供了一些有用的功能来帮助开发人员更好地管理和调试Maven项目。
2287 0
IDEA插件-Maven Helper