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

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等。

相关推荐
heartbeat..9 小时前
使用 Apache POI 实现 Excel 文件读写(导入 导出)操作的工具类
java·apache·excel·文件
星空椰12 小时前
Java Excel转PDF
pdf·excel
ohoy14 小时前
easypoi 带图片导入 公司表
excel
appleคิดถึง1 天前
tp6数据导出excel文件时对大数据量处理
php·excel·tp6
heartbeat..1 天前
注解 + 反射:Web 项目 Excel 一键导出工具 EnhancedExportExcelUtil 详解
java·excel·poi
yivifu1 天前
Excel表格取多行数据中的唯一值及多条件数据查询问题
excel
天一生水water2 天前
顶级多项目管理 Excel 模板
excel·敏捷流程
取啥都被占用2 天前
VBA的excel逐行替换到word模板及打印还原
excel·vba
坚定信念,勇往无前2 天前
vue3图片,pdf,word,excel,ppt多格式文件预览组件Vue Doc Viewers Plus
pdf·word·excel
weixin_462446232 天前
【原创实践】python 获取节假日列表 并保存为excel
数据库·python·excel