我去,还在这样读写 excel 这也太低效了吧!

使用过 poi 的开发同学可能都有此体会,每次都要写一坨代码,最后的代码如下面一样:

这样的代码是不是又臭又长?当字段数量多的时候,一不小心还容易写错。还记得当初使用 poi 导出一个二十多字段的 excel,不断复制粘贴,行号一不小心就写错了,那叫个一个心酸。

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

EasyExcel

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

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

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

com.alibaba

easyexcel

2.1.6

这里建议大家使用 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> head() {

List> list = new ArrayList>();

// 第一列表头

List head0 = new ArrayList();

head0.add("第一列");

head0.add("第一列第二行");

// 第二列表头

List head1 = new ArrayList();

head1.add("第一列");

head1.add("第二列第二行");

// 第三列

List head2 = new ArrayList();

head2.add("第一列");

head2.add("第三列第二行");

list.add(head0);

list.add(head1);

list.add(head2);

return list;

}

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

最终创建表头如下:

写入表体数据

private static List dataList() {

List> list = new ArrayList>();

for (int i = 0; i < 10; i++) {

List data = new ArrayList();

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<Object>>,但是与表头规则不一样。

每个 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 {

@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 上相关文档例子非常丰富,大家可以自行参考。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容