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

相关推荐
小旺不正经7 小时前
txt、Csv、Excel、JSON、SQL文件读取(Python)
sql·json·excel
Ramseyuu13 小时前
Excel文件的导入导出
excel
蠟筆小新工程師13 小时前
Odoo 部署本地 把現時的excel計算表格部署上odoo 教程
数据库·excel
码猩1 天前
C# winform根据EXCEL匹配文件后将txt的图片分别下载到指定的文件夹里
开发语言·c#·excel
焚 城1 天前
AI结合VBA提升EXCEL办公效率尝试
ai·excel
兰德里的折磨5501 天前
基于若依和elementui实现文件上传(导入Excel表)
前端·elementui·excel
唐骁虎1 天前
Excel VBA 运行时错误1004’:方法‘Open’作用于对象‘Workbooks’时失败 的解决方法
excel
weixin_448771721 天前
使用xml模板导出excel
xml·java·excel
杂学者2 天前
python 办公自动化------ excel文件的操作,读取、写入
python·excel
SunkingYang2 天前
C++中如何使用Cshapes类的addpicture函数将图片插入excel
excel·cshapes·addpicture·插入图片到excel·get_shapes