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();

目录
相关文章
|
Java API Maven
敏感数据的保护伞——SpringBoot Jasypt加密库的使用
我们经常会在yml配置文件中存放一些敏感数据,比如数据库的用户名、密码,第三方应用的秘钥等等。这些信息直接以明文形式展示在文件中,无疑是存在较大的安全隐患的,所以今天这篇文章,我会借助jasypt实现yml文件中敏感信息的加密处理。
6411 1
敏感数据的保护伞——SpringBoot Jasypt加密库的使用
|
存储 Java 测试技术
JAVA-MAVEN初学者教程(配置、pom.xml、依赖管理等)
JAVA-MAVEN初学者教程(配置、pom.xml、依赖管理等)
4141 0
|
11月前
|
Java 大数据 Apache
Excel工具-HUTOOL-输出Excel
Hutool基于Apache POI封装了Excel读写功能,提供ExcelWriter和BigExcelWriter类,支持写出List、Map、Bean等数据类型到Excel,可自定义样式、多sheet操作,并解决大数据量导出时的内存溢出问题,适用于文件导出、客户端下载等场景。
|
7月前
|
Ubuntu Linux 开发者
Ubuntu 22.04 安装 RTX 5090 显卡驱动教程(小白也能学会的 Linux 驱动安装指南)
本教程参考:http://jyumw.cn手把手教你为Ubuntu 22.04安装RTX 5090显卡驱动,涵盖环境清理、PPA源添加、自动/手动安装及验证全流程,小白也能轻松完成Linux显卡配置,开启高性能计算。
|
9月前
|
数据采集 人工智能 自然语言处理
OpenClaw部署接入MiniMax等模型太费Token(rmb)了!OpenClaw自进化指南:让AI助理“自己养活自己”
2026年,OpenClaw(原Clawdbot)已从基础AI助手进化为可“自我成长”的数字员工——它不仅能执行预设任务,还能通过自动安装技能、扩展服务、切换模型,实现“自己养活自己”。但很多用户在使用中面临两大痛点:一是部署流程复杂,二是长期使用成本高(如MiniMax模型单日消耗可达9元)。
4050 1
|
前端开发 Java 开发者
这款免费 IDEA 插件让你开发 Spring 程序更简单
Feign-Helper 是一款支持 Spring 框架的 IDEA 免费插件,提供 URL 快速搜索、Spring Web Controller 路径一键复制及 Feign 与 Controller 接口互相导航等功能,极大提升了开发效率。
4187 1
|
安全 Java 测试技术
如何在 Spring Boot 中禁用 Actuator 端点安全?
如何在 Spring Boot 中禁用 Actuator 端点安全?
3890 1
|
存储 Java 测试技术
阿里巴巴java开发手册
这篇文章是关于阿里巴巴Java开发手册的整理,内容包括编程规约、异常日志、单元测试、安全规约、MySQL数据库使用以及工程结构等方面的详细规范和建议,旨在帮助开发者编写更加规范、高效和安全的代码。