EasyExcel读写Excel

2023-11-09

转载,侵删
原文链接:https://mp.weixin.qq.com/s/T_xBuoYgj1NuM7_yHe084Q

最近读者小 H 在知识星球中给阿粉发来私信:

阿粉,最近我在负责公司报表平台开发,需要导出报表到 Excel 中。每次使用 POI 开发,都要写长长的一坨代码,好几次因为没加入判空判断,导致生成失败。想跟你请教下有没有更加高效一点读写 Excel 方法?

ps:知识星球汇集一片大神,感兴趣的同学可以加入知识星球,有任何问题都会有大神及时解答。

使用过 poi 的开发同学可能都有此体会,每次都要写一坨代码,最后的代码如下面一样:
在这里插入图片描述
这样的代码是不是又臭又长?当字段数量多的时候,一不小心还容易写错。阿粉还记得当初使用 poi 导出一个二十多字段的 excel,不断复制粘贴,行号一不小心就写错了,那叫个一个心酸。

今天阿粉就来推荐一个阿里开源的项目『EasyExcel』,带大家彻底告别上面又长又臭的代码,彻底解决这个问题。在这里插入图片描述

EasyExcel

EasyExcel 是一个阿里出品的开源项目 ,看名字就能看出这个项目是为了让你更加简单的操作 Excel。另外 EasyExcel 还解决了poi 内存溢出问题,修复了一些并发情况下一些 bug。

github 地址:https://github.com/alibaba/easyexcel
在这里插入图片描述
截止阿粉写文章时,已有 13.6k star 数据,可见这个项目还是深受大家欢迎。

废话不多说,我们直接进入源码实战环节。

首先我们需要引入 EasyExcel pom 依赖:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>2.1.6</version>
</dependency>

这里建议大家使用 2.0 以上的正式版本,不要再使用 1.0 的老版本,两者使用 API 差别很大。另外 beta 版本可能会存在某些 bug,大家谨慎使用。

普通方式

一行代码生成 Excel
// 写法1
String fileName = "temp/" + "test" + System.currentTimeMillis() + ".xlsx";
EasyExcel.write(fileName)
        .head(head())// 设置表头
        .sheet("模板")// 设置 sheet 的名字
        // 自适应列宽
        .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
        .doWrite(dataList());// 写入数据

生成 excel 代码特别简单,这里使用链式语句,一行代码直接搞定生成代码。代码中再也不用我们指定行号,列号了。

上面代码中使用自适应列宽的策略。

下面我们来看下表头与标题如何生成。

创建表头
/**
 * 创建表头,可以创建复杂的表头
 *
 * @return
 */
private static List<List<String>> head() {
    List<List<String>> list = new ArrayList<List<String>>();
    // 第一列表头
    List<String> head0 = new ArrayList<String>();
    head0.add("第一列");
    head0.add("第一列第二行");
    // 第二列表头
    List<String> head1 = new ArrayList<String>();
    head1.add("第一列");
    head1.add("第二列第二行");
    // 第三列
    List<String> head2 = new ArrayList<String>();
    head2.add("第一列");
    head2.add("第三列第二行");
    list.add(head0);
    list.add(head1);
    list.add(head2);
    return list;
}

上面每个 List 代表一列的数据,集合内每个数据将会顺序写入这列每一行。如果每一列的相同行数的内容相同,将会自动合并单元格。通过这个规则,我们创建复杂的表头。

最终创建表头如下:
在这里插入图片描述

写入表体数据
private static List dataList() {
    List<List<Object>> list = new ArrayList<List<Object>>();
    for (int i = 0; i < 10; i++) {
        List<Object> data = new ArrayList<Object>();
        data.add("点赞+" + i);
        // date 将会安装 yyyy-MM-dd HH:mm:ss 格式化
        data.add(new Date());
        data.add(0.56);
        list.add(data);
    }
    return list;
}

表体数据然后也是使用 List<List>,但是与表头规则不一样。

每个 List 代表一行的数据,数据将会按照顺序写入每一列中。

集合中数据 EasyExcel 将会按照默认的格式化转换输出,比如 date 类型数据就将会按照 yyyy-MM-dd HH:mm:ss 格式化。

如果需要转化成其他格式,建议直接将数据格式化成字符串加入 List,不要通过 EasyExcel 转换。

最终效果如下:
在这里插入图片描述
看完这个是不是想立刻体验一下?等等,上面使用方式还是有点繁琐,使用 EasyExcel 还可以更快。我们可以使用注解方式,无需手动设置表头与表体。

在这里插入图片描述

注解方式

注解方式生成 Excel 代码如下:

String fileName = "temp/annotateWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
// 如果这里想使用03 则 传入excelType参数即可
EasyExcel
        .write(fileName, DemoData.class)
        .sheet("注解方式")
        .registerWriteHandler(createTableStyle())// Excel 表格样式
        .doWrite(data());

这里代码与上面大体一致,只不过这里需要在 write 方法传入 DemoData 数据类型。EasyExcel 会根据 DemoData 类型自动生成表头。

下面我们来看下 DemoData这个类到底内部到底是啥样?

@ContentRowHeight(30)// 表体行高
@HeadRowHeight(20)// 表头行高
@ColumnWidth(35)// 列宽
@Data
public class DemoData {
    /**
     * 单独设置该列宽度
     */
    @ColumnWidth(50)
    @ExcelProperty("字符串标题")
    private String string;
    /**
     * 年月日时分秒格式
     */
    @DateTimeFormat("yyyy年MM月dd日HH时mm分ss秒")
    @ExcelProperty(value = "日期标题")
    private Date date;
    /**
     * 格式化百分比
     */
    @NumberFormat("#.##%")
    @ExcelProperty("数字标题")
    private Double doubleData;
    @ExcelProperty(value = "枚举类",converter = DemoEnumConvert.class)
    private DemoEnum demoEnum;
    /**
     * 忽略这个字段
     */
    @ExcelIgnore
    private String ignore;
}

DemoData 就是一个普通的 POJO 类,上面使用 ExayExcel 相关注解,ExayExcel 将会通过反射读取字段类型以及相关注解,然后直接生成 Excel 。

ExayExcel 提供相关注解类,直接定义 Excel 的数据模型:

  • @ExcelProperty 指定当前字段对应excel中的那一列,内部 value 属性指定表头列的名称
  • @ExcelIgnore 默认所有字段都会和excel去匹配,加了这个注解会忽略该字段
  • @ContentRowHeight 指定表体行高
  • @HeadRowHeight 指定表头行高
  • @ColumnWidth 指定列的宽度

另外 ExayExcel 还提供几个注解,自定义日期以及数字的格式化转化。

  • @DateTimeFormat
  • @NumberFormat

另外我们可以自定义格式化转换方案,需要实现 Converter 类相关方法即可。

public class DemoEnumConvert implements Converter<DemoEnum> {
    @Override
    public Class supportJavaTypeKey() {
        return DemoEnum.class;
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    /**
     * excel 转化为 java 类型,excel 读时将会被调用
     * @param cellData
     * @param contentProperty
     * @param globalConfiguration
     * @return
     * @throws Exception
     */
    @Override
    public DemoEnum convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        return null;
    }

    /**
     * java 类型转 excel 类型,excel 写时将会被调用
     * @param value
     * @param contentProperty
     * @param globalConfiguration
     * @return
     * @throws Exception
     */
    @Override
    public CellData convertToExcelData(DemoEnum value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        return new CellData(value.getDesc());
    }
}

最后我们还需要在 @ExcelProperty 注解上使用 converter 指定自定义格式转换方案。

使用方式如下:

@ExcelProperty(value = "枚举类",converter = DemoEnumConvert.class)
private DemoEnum demoEnum;

最后我们运行一下,看下 Excel 实际效果如何:
在这里插入图片描述
怎么样,效果还是可以吧。
在这里插入图片描述
对了,默认的样式表格样式可不是这样,这个效果是因为我们在 registerWriteHandler 方法中设置自定义的样式,具体代码如下:

/***
 * 设置 excel 的样式
 * @return
 */
private static WriteHandler createTableStyle() {
    // 头的策略
    WriteCellStyle headWriteCellStyle = new WriteCellStyle();
    // 背景设置为红色
    headWriteCellStyle.setFillForegroundColor(IndexedColors.PINK.getIndex());
    // 设置字体
    WriteFont headWriteFont = new WriteFont();
    headWriteFont.setFontHeightInPoints((short) 20);
    headWriteCellStyle.setWriteFont(headWriteFont);
    // 内容的策略
    WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
    // 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定
    contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
    // 背景绿色
    contentWriteCellStyle.setFillForegroundColor(IndexedColors.LEMON_CHIFFON.getIndex());

    WriteFont contentWriteFont = new WriteFont();
    // 字体大小
    contentWriteFont.setFontHeightInPoints((short) 20);
    contentWriteCellStyle.setWriteFont(contentWriteFont);
    // 设置边框的样式
    contentWriteCellStyle.setBorderBottom(BorderStyle.DASHED);
    contentWriteCellStyle.setBorderLeft(BorderStyle.DASHED);
    contentWriteCellStyle.setBorderRight(BorderStyle.DASHED);
    contentWriteCellStyle.setBorderTop(BorderStyle.DASHED);

    // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
    HorizontalCellStyleStrategy horizontalCellStyleStrategy =
            new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
    return horizontalCellStyleStrategy;
}

使用注意点

poi 冲突问题

理论上当前 easyexcel兼容支持 poi 的3.17,4.0.1,4.1.0所有较新版本,但是如果项目之前使用较老版本的 poi,由于 poi 内部代码调整,某些类已被删除,这样直接运行时很大可能会抛出以下异常:

  • NoSuchMethodException

  • ClassNotFoundException

  • NoClassDefFoundError

所以使用过程中一定要注意统一项目中的 poi 的版本。

非注解方式自定义行高列宽

非注解方式自定义行高以及列宽比较麻烦,暂时没有找到直接设置的入口。查了一遍 github 相关 issue,开发人员回复需要实现 WriteHandler 接口,自定义表格样式。

总结

本文主要给各位小伙伴们安利 EasyExcel 强大的功能,介绍 EasyExcel 两种生成 excel 方式,以及演示相关的示例代码。EasyExcel 除了写之外,当然还支持快读读取 Excel 的功能,这里就不再详细介绍。Github 上相关文档例子非常丰富,大家可以自行参考。

Github 文档地址:https://alibaba-easyexcel.github.io/index.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

EasyExcel读写Excel 的相关文章

随机推荐

  • 使用vector迭代器实现二分查找

    vector二分查找 include stdafx h include
  • macOS 视频格式转换:ffmpeg + shell 脚本【最优方案】【免费 + 高效】

    效果完美 开始转换 成功输出 ffmpeg 下载 github 开源下载 下载地址 https ffmpeg org download html shell 脚本 你的用户名 替换成你得自己的对应路劲 比如你下载的 ffmpeg 躲在路劲
  • windows的磁盘操作之七——获取当前所有的物理磁盘号

    有了前几节的基础后 本节给出一个更复杂但却非常实用的例子 很多情况下 我们想知道当前系统下安装了多少块磁盘 他们的物理驱动器号都是多少 每一块磁盘上有多少个分区 分区号怎么分布 每个分区大小是多少 这就类似于我们打开windows 的磁盘管
  • c++的工程文件的编译顺序

    以前一直以为 vs在编译c 文件时候是从头文件开始编译的 而每个头文件对应的源文件只是头文件定义中的一些实现而已 源文件不参与编译 今天经过同学指点并实践之后才发现 其实不是这样的 从中受益颇多 c 编译的时候实际上只编译源文件 而不编译头
  • 416. 分割等和子集

    题目描述 给你一个 只包含正整数 的 非空 数组 nums 请你判断是否可以将这个数组分割成两个子集 使得两个子集的元素和相等 示例 1 输入 nums 1 5 11 5 输出 true 解释 数组可以分割成 1 5 5 和 11 示例 2
  • nginx实战总结-request_time和upstream_response_time详解

    一 前言 这个主要是日志模块的延伸 这两个参数 在实战中非常重要 因此提出来单独说 二 图解 从上图中得出以下结论 打印日志是在最后一个步骤 也就是说整套请求完毕后 进行打印 请求的整套时间线 1 客户端 request gt nginx
  • 最大流解决医生排班问题

    目录 问题描述 场景建模 Ford Fulkerson方法 Edmonds karp算法 Dinic算法 问题描述 一个医院有n名医生 现有k个公共假期需要安排医生值班 每一个公共假期由若干天 假日 组成 第j个假期包含的假日用 Dj表示
  • Python接口自动化测试之文件上传

    在接口测试中 经常会涉及到文件上传 文件上传一般包含的文件是图片 视频以及如csv excel 记事本等文件 它的请求头中Content Type对应的value值是multipart form data 这里依据实际的案例来说明文件上传的
  • Makefile 神奇:驾驭编译的力量

    一 make和Makefile 当谈到 make 和 Makefile 时 通常是指构建工具 make 和用于描述编译和构建过程的文本文件 Makefile make 是一个在类Unix系统中广泛使用的构建工具 它基于文件的时间戳比较 只编
  • 【Vue】生命周期回调函数

    生命周期 又名 生命周期回调函数 生命周期函数 生命周期钩子 程序员间沟通常称生命周期钩子 是什么 Vue在关键时刻帮我们调用的一些特殊名称的函数 生命周期函数的名字不可更改 但是函数的具体内容是程序员根据需求编写的 生命周期函数中的 th
  • java中的Socket编程

    基于Socket的java网络编程 网络上的两个程序通过一个双向的通讯连接实现数据的交换 这个双向链路的一端成为一个socket Socket通常用来实现客户方和服务方的连接 Socket是TCP IP协议的一个十分流行的编程界面 一个so
  • window环境下 —Apache 2.4下载、安装配置与卸载

    一 Apache的下载 1 下载地址 https www apachehaus com cgi bin download plx 2 安装Apache 解压后打开conf文件夹下httpd conf文件 修改Apache目录地址 Defin
  • python螺旋矩阵

    Python 螺旋矩阵 给你一个正整数 n 生成一个包含 1 到 n2 所有元素 且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix class Solution def generateMatrix self n int
  • system.ComponentModel.Win32Exception (0x80004005): 目录名无效。 解决方法

    system ComponentModel Win32Exception 0x80004005 目录名无效 解决方法 参考文章 1 system ComponentModel Win32Exception 0x80004005 目录名无效
  • Neural Filters用不了怎么办?推荐uminar AI for Mac人工智能照片编辑软件

    Luminar AI 1 3 0 for Mac是macOS第一款完全人工智能的照片编辑软件 摄影爱好者和专业摄影师 设计师必备的后期软件 Luminar AI 可以作为独立的照片编辑软件或作为PS LRC插件使用 功能强大媲美PS的神经滤
  • 【Windows】VScode终端添加GitBash,终端直接调用git

    1 打开VScode 文件 gt gt 首选项 gt gt 设置 搜索 shell windows 点击settings json编辑 把下面的语句复制进去 terminal integrated profiles windows Powe
  • 台达b3伺服参数设置方法_台达伺服驱动器参数设置一览表

    台达伺服驱动器参数设置一览表 2020 12 23 台达伺服驱动器的参数设置分为八大群组 从P0到P7 参数群组定义如下 群组 0 监控参数 例 P0 xx 群组 1 基本参数 例 P1 xx 群组 2 扩展参数 例 P2 xx 群组 3
  • oracle 表 xml,详细分析Oracle XML数据

    在向大家详细介绍Oracle XML数据之前 首先让大家了解下Oracle 11g 然后全面介绍Oracle XML数据 在Oracle 11g可以使用CLOB及二进制两种方式保存XML信息 灵活性很高 Oracle 11g还支持针对XML
  • ElementUI/ElementPlus+笔记

    如何修改特定文件下使用的Element组件样式 在哪修改样式 在修改element样式时 最好在scoped中修改避免全局污染 如果在scoped中修改样式不生效就在全局中修改 但是在要修改的样式外面套一层class 避免修改了所有页面 使
  • EasyExcel读写Excel

    转载 侵删 原文链接 https mp weixin qq com s T xBuoYgj1NuM7 yHe084Q 最近读者小 H 在知识星球中给阿粉发来私信 阿粉 最近我在负责公司报表平台开发 需要导出报表到 Excel 中 每次使用