EasyExcel-一款好用的excel生成工具

news2025/4/18 23:50:48

EasyExcel是一款处理excel的工具类,主要特点如下(官方):

特点

  • 高性能读写:FastExcel 专注于性能优化,能够高效处理大规模的 Excel 数据。相比一些传统的 Excel 处理库,它能显著降低内存占用。
  • 简单易用:该库提供了简洁直观的 API,使得开发者可以轻松集成到项目中,无论是简单的 Excel 操作还是复杂的数据处理都能快速上手。
  • 流式操作:FastExcel 支持流式读取,将一次性加载大量数据的问题降到最低。这种设计方式在处理数十万甚至上百万行的数据时尤为重要。

我自己实践之后的感受如下:

  • 性能比较好,底层使用SXSSF,在大数据的情况下,会先往硬盘中插入,加快速度。(SXSSF 通过将数据写入磁盘而不是全部保留在内存中,来减少内存的使用。这种 “流式” 写入方式特别适合处理那些可能导致传统内存处理方式崩溃的大型 CSV 文件。SXSSF 可以在写入数据的同时,将数据保存在一个临时的文件中,这样即使处理非常大的数据集,内存的使用也会保持在可控范围内。)
  • 支持注解,可以在每个字段属性上添加注解,可以设置表格的表头/颜色/字体/合并单元格等属性。
  • 支持策略,针对复杂的表格,支持注入策略,针对表格进行各种加工。
  • 支持excel转pdf(仅支持xlsx,版本为1.0.0)

实践

引入依赖


<dependency>
    <groupId>cn.idev.excel</groupId>
    <artifactId>fastexcel</artifactId>
    <version>1.1.0</version>
</dependency>
1.表头支持注解方式生成

比如,下方的示例:创建一个绿色背景,加边框的表头
在这里插入图片描述
代码的话可以直接这样写:
新增一个订单类:

@Data
// 表头背景设置
@HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 17)
public class Order {
   @ExcelProperty("订单号")
   private String orderId;
   @ExcelProperty("渠道")
   private String searchChannel;
   @ExcelProperty("创建时间")
   private String createTime;
   @ExcelProperty("乘客姓名")
   private String name;
   @ExcelProperty("证件号")
   private String idCard;
}

创建表格


/**
 * 合并单元格
 * <p>
 * 1. 创建excel对应的实体对象 参照{@link DemoData} {@link DemoMergeData}
 * <p>
 * 2. 创建一个merge策略 并注册
 * <p>
 * 3. 直接写即可
 *
 * @since 2.2.0-beta1
 */
@Test
public void mergeOrderWrite() {
    //使用策略合并单元格
    try (FileOutputStream excel = new FileOutputStream("mergeOrderWrite.xlsx");
         BufferedOutputStream bos = new BufferedOutputStream(excel)) {
        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        EasyExcel.write(bos, Order.class).sheet("模板").doWrite(buildData());
        System.out.println("导出完成");
    } catch (IOException e) {
        System.out.println("导出失败:" + e.getMessage());
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

//初始化数据
private List<Order> buildData() {
    List<Order> list = new ArrayList<>();
    for (int i = 0; i < 100; i++) {
        for (int j = 0; j < 2; j++) {
            Order user = new Order();
            user.setOrderId("orderId_" + i);
            user.setSearchChannel("searchChannel_" + i);
            user.setCreateTime(DateTimeUtil.nowString());
            user.setName("name_" + j);
            user.setIdCard("idCard_" + j);
            list.add(user);
        }
    }

    Order user1 = new Order();
    user1.setOrderId("orderId_99");
    user1.setSearchChannel("searchChannel_99");
    user1.setCreateTime(DateTimeUtil.nowString());
    user1.setName("name_a");
    user1.setIdCard("idCard_a");
    list.add(user1);
    return list;
}

上面代码执行之后,即可以生成效果图中的表格数据

2.通过添加策略,来支持复杂的表格处理

比如我们要处理一个表格,里面的数据涉及到动态合并单元格。需要将相邻的相同订单号合并到一起
在这里插入图片描述
支持添加策略实现:
思路:遍历每个row,如果两个orderid一样,则合并

@Slf4j
public class LoopOrderMergeStrategy implements RowWriteHandler {
    /**
     * 订单号
     */
    private String orderId;

    /**
     * 当前订单号起始坐标
     */
    private Integer indexStart;

    /**
     * 合并策略,订单号和创建时间合并
     *
     * @author zhouxy
     * @date 2025/4/3 17:27
     */
    public void afterRowDispose(RowWriteHandlerContext context) {
        log.info("进来,,,{},{}", context.getRow().getRowNum(), context.getRelativeRowIndex());
        //遍历每个row,如果两个orderid一样,则合并
        //这里是获取每一行数据
        Cell cell = context.getRow().getCell(0);
        String currentOrderId = cell.getStringCellValue();
        if (Strings.isEmpty(this.orderId)) {
            this.orderId = currentOrderId;
            indexStart = context.getRowIndex();
        } else if (Objects.equals(this.orderId, currentOrderId)) {
            //合并单元格
            //订单号
            CellRangeAddress orderCellRangeAddress = new CellRangeAddress(indexStart,
                    context.getRowIndex(),
                    cell.getColumnIndex(),
                    cell.getColumnIndex());
            context.getWriteSheetHolder().getSheet().addMergedRegionUnsafe(orderCellRangeAddress);
            //渠道
            Cell searchChannelCell = context.getRow().getCell(1);
            CellRangeAddress searchChannelCellRangeAddress = new CellRangeAddress(indexStart,
                    context.getRowIndex(),
                    searchChannelCell.getColumnIndex(),
                    searchChannelCell.getColumnIndex());
            context.getWriteSheetHolder().getSheet().addMergedRegionUnsafe(searchChannelCellRangeAddress);
            //创建时间
            Cell createtimeCell = context.getRow().getCell(2);
            CellRangeAddress createTimeCellRangeAddress = new CellRangeAddress(indexStart,
                    context.getRowIndex(),
                    createtimeCell.getColumnIndex(),
                    createtimeCell.getColumnIndex());
            context.getWriteSheetHolder().getSheet().addMergedRegionUnsafe(createTimeCellRangeAddress);
        } else if (!Objects.equals(this.orderId, currentOrderId)) {
            this.orderId = currentOrderId;
            indexStart = context.getRowIndex();
        }
    }

}

生成表格的时候,将该策略设置进去


/**
 * 合并单元格
 * <p>
 * 1. 创建excel对应的实体对象 参照{@link DemoData} {@link DemoMergeData}
 * <p>
 * 2. 创建一个merge策略 并注册
 * <p>
 * 3. 直接写即可
 *
 * @since 2.2.0-beta1
 */
@Test
public void mergeOrderWrite() {
    //使用策略合并单元格
    try (FileOutputStream excel = new FileOutputStream("mergeOrderWrite.xlsx");
         BufferedOutputStream bos = new BufferedOutputStream(excel)) {
        LoopOrderMergeStrategy loopMergeStrategy = new LoopOrderMergeStrategy();
        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        EasyExcel.write(bos, Order.class).registerWriteHandler(loopMergeStrategy).sheet("模板").doWrite(buildData());
        System.out.println("导出完成");
    } catch (IOException e) {
        System.out.println("导出失败:" + e.getMessage());
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
3.支持excel转pdf,但是只有1.0.0版本有,新版本去掉了。
   @Test
   public void excelToPdf() {
       FastExcel.convertToPdf(new File("excel1.xlsx"),new File("pdfFile"),null,null);
   }
4.性能

相同数据生成用时比较:ExsyExcel > SXSSF > HSSF. 但是HSSF最大行数为65565行,再大就超出范围报错
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
HSSF可写入行数
在这里插入图片描述
easyexcel和SXSSF可写入行数
在这里插入图片描述

综合比较用时的话,,EasyExcel和SX SSF的用时差不多,HSSF的用时相当于前两者的三分之一。但是HSSF数据量支持较小,但是综合下来的话,从用时,代码简洁度来说,建议使用EasyExcel

其他功能可以看官方的github,里面有很多示例。比如支持转图片,根据模板写入excel等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2332616.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WEB攻防-Java安全JNDIRMILDAP五大不安全组件RCE执行不出网不回显

目录 1. RCE执行-5大类函数调用 1.1 Runtime方式 1.2 Groovy执行命令 1.3 脚本引擎代码注入 1.4 ProcessImpl 1.5 ProcessBuilder 2. JNDI注入(RCE)-RMI&LDAP&高版本 2.1 RMI服务中的JNDI注入场景 2.2 LDAP服务中的JNDI注入场景 攻击路径示例&#…

DrissionPage移动端自动化:从H5到原生App的跨界测试

一、移动端自动化测试的挑战与机遇 移动端测试面临多维度挑战&#xff1a; 设备碎片化&#xff1a;Android/iOS版本、屏幕分辨率差异 混合应用架构&#xff1a;H5页面与原生组件的深度耦合 交互复杂性&#xff1a;多点触控、手势操作、传感器模拟 性能监控&#xff1a;内存…

从 Excel 到你的表格应用:条件格式功能的嵌入实践指南

一、引言 在日常工作中&#xff0c;面对海量数据时&#xff0c;如何快速识别关键信息、发现数据趋势或异常值&#xff0c;是每个数据分析师面临的挑战。Excel的条件格式功能通过自动化的视觉标记&#xff0c;帮助用户轻松应对这一难题。 本文将详细介绍条件格式的应用场景&am…

STM32单片机入门学习——第22节: [7-2] AD单通道AD多通道

写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难&#xff0c;但我还是想去做&#xff01; 本文写于&#xff1a;2025.04.07 STM32开发板学习——第22节: [7-2] AD单通道&AD多通道 前言开发板说明引用解…

【Survival Analysis】【机器学习】【1】

前言&#xff1a; 今年在做的一个博士课题项目&#xff0c;主要是利用病人的数据&#xff0c;训练出一个AI模型&#xff0c;做因果分析&#xff0c; 以及个性化治疗。自己一直是做通讯AI方向的&#xff0c;这个系列主要参考卡梅隆大学的教程&#xff0c;以及临床医生的角度 了…

JavaScript---原型和原型链

目录 一、引用类型皆为对象 二、原型和原型链是什么 三、__proto__与prototype 总结 四、原型链顶层 五、constructor 六、函数对象的原型链 一、引用类型皆为对象 原型和原型链都是来源于对象而服务于对象&#xff1a; JavaScript中一切引用类型都是对象&#xff0c;…

离散数学问题集--问题5.9

问题 5.9 综合了计算机组成原理、数字逻辑和离散数学中的关键概念&#xff0c;旨在帮助学生理解二进制算术运算的硬件实现、逻辑门与算术运算的关系&#xff0c;以及如何使用数学方法来验证数字系统的正确性。它强调了从规范到实现再到验证的完整过程。 思想 函数抽象&#xf…

Java—HTML:CSS选择器

今天我要介绍的知识点内容是Java HTML中的CSS选择器&#xff1b; CSS选择器用于定位HTML元素并为其添加样式。它允许我们控制网页的颜色、字体、布局和其他视觉元素。通过分离内容与样式。 下面我将介绍CSS中选择器的使用&#xff0c;并作举例说明&#xff1b; 选择器基本语…

SSM阶段性总结

0 Pojo类 前端给后端&#xff1a;DTO 后端给前端&#xff1a;VO 数据库&#xff1a;PO/VO 业务处理逻辑&#xff1a;BO 统称pojo 1 代理模式 实现静态代理&#xff1a; 1定义接口2实现类3写一个静态代理类4这样在调用时就可以使用这个静态代理类来实现某些功能 实现动态代…

Qt 5.14.2入门(一)写个Hello Qt!程序

目录 参考链接&#xff1a;一、新建项目二、直接运行三、修改代码增加窗口内容1、Qt 显示一个 QLabel 标签控件窗口2、添加按键 参考链接&#xff1a; Qt5教程&#xff08;一&#xff09;&#xff1a;Hello World 程序 Qt 编程指南 一、新建项目 1、新建一个项目&#xff08…

Jmeter分布式测试启动

代理客户端配置 打开jmeter.properties文件&#xff0c;取消注释并设置端口&#xff08;如server_port1099&#xff09;&#xff0c; 并添加server.rmi.ssl.disabletrue禁用SSL加密。 &#xff08;Linux系统&#xff09;修改jmeter-server文件中的RMI_HOST_DEF为代理机实际IP。…

redis itheima

缓存问题 核心是如何避免大量请求到达数据库 缓存穿透 既不存在于 redis&#xff0c;也不存在于 mysql 的key&#xff0c;被重复请求 public Result queryById(Long id) {String key CACHE_SHOP_KEYid;// 1. redis & mysqlString shopJson stringRedisTemplate.opsFo…

100天精通Python(爬虫篇)——第122天:基于selenium接管已启动的浏览器(反反爬策略)

文章目录 1、问题描述2、问题推测3、解决方法3.1 selenium自动启动浏览器3.2 selenium接管已启动的浏览器3.3 区别总结 4、代码实战4.1 手动方法&#xff08;手动打开浏览器输入账号密码&#xff09;4.2 自动方法&#xff08;.bat文件启动的浏览器&#xff09; 1、问题描述 使用…

MPP 架构解析:原理、核心优势与对比指南

一、引言&#xff1a;大数据时代的数据处理挑战 全球数据量正以指数级增长。据 Statista 统计&#xff0c;2010 年全球数据量仅 2ZB&#xff0c;2025 年预计达 175ZB。企业面临的核心挑战已从“如何存储数据”转向“如何快速分析数据”。传统架构在处理海量数据时暴露明显瓶颈…

Python设计模式-工厂模式

一、模式定义与核心思想 工厂模式&#xff08;Factory Pattern&#xff09;属于创建型设计模式&#xff0c;其核心思想是通过一个"工厂类"来创建对象&#xff0c;而不是直接调用类的构造函数。这种模式将对象的实例化过程封装起来&#xff0c;使系统在实例化对象时能…

彻底解决VS2008编译错误:fatal error C1083 无法打开包括文件“stdint.h“

彻底解决VS2008编译错误&#xff1a;fatal error C1083 无法打开包括文件"stdint.h" 一、错误现象与本质原因 当在Visual Studio 2008中编译包含C99标准整数类型&#xff08;如int8_t、uint32_t&#xff09;的代码时&#xff0c;常出现以下编译错误&#xff1a; f…

react从零开始的基础课

全文约5万字。 1.hello,.. // App.jsx import { useState } from react import reactLogo from ./assets/react.svg import viteLogo from /vite.svg import ./App.cssfunction App() {const [count, setCount] useState(0)return (<><Greeting name"world&qu…

算法题型讲解

一.双指针 主要分为俩种类型&#xff1a; 1.左右指针&#xff1a;双指针指向开头&#xff0c;以一定标准移动或交换&#xff0c;对区域进行划分&#xff0c;或找到特殊点的位置 &#xff08;如&#xff1a;快慢指针判断有无环&#xff0c;移动零&#xff09; 2.对撞指针&am…

Redis和数据库一致性问题

操作模拟 1、先更新数据库还是先更新缓存&#xff1f; 1.1先更新缓存&#xff0c;再更新数据库 按并发的角度来说&#xff0c;有两个线程A、B&#xff0c;操作同一个数据&#xff0c;线程A先更新缓存为1&#xff0c;在线程A更新数据库之前&#xff0c;这时候线程B进来&#…

第R8周:RNN实现阿尔茨海默病诊断(pytorch)

>- **&#x1f368; 本文为[&#x1f517;365天深度学习训练营]中的学习记录博客** >- **&#x1f356; 原作者&#xff1a;[K同学啊]** 本人往期文章可查阅&#xff1a; 深度学习总结 一、准备工作 &#x1f3e1; 我的环境&#xff1a; 语言环境&#xff1a;Python3.1…