博文地址: https://sourl.cn/SsD3AM
最近读者小 H 给小黑哥发来私信:html
小黑哥,最近我在负责公司报表平台开发,须要导出报表到 excel 中。每次使用 POI 开发,都要写长长的一坨代码,好几回由于没加入判空判断,致使生成失败。想跟你请教下有没有更加高效一点读写 excel 方法?
使用过 poi 的开发同窗可能都有此体会,每次都要写一坨代码,最后的代码以下面同样:java
这样的代码是否是又臭又长?当字段数量多的时候,一不当心还容易写错。小黑哥还记得当初使用 poi 导出一个二十多字段的 excel,不断复制粘贴,行号一不当心就写错了,那叫个一个心酸。git
今天小黑哥就来推荐一个阿里开源的项目『EasyExcel』,带你们完全告别上面又长又臭的代码,完全解决这个问题。github
EasyExcel 是一个阿里出品的开源项目 ,看名字就能看出这个项目是为了让你更加简单的操做 Excel。另外 EasyExcel 还解决了poi 内存溢出问题,修复了一些并发状况下一些 bug。并发
github 地址:https://github.com/alibaba/ea...ide
截止小黑哥写文章时,已有 13.6k star 数据,可见这个项目仍是深受你们欢迎。字体
废话很少说,咱们直接进入源码实战环节。url
首先咱们须要引入 EasyExcel pom 依赖:idea
<dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.1.6</version> </dependency>
这里建议你们使用 2.0 以上的正式版本,不要再使用 1.0 的老版本,二者使用 API 差异很大。另外 beta 版本可能会存在某些 bug,你们谨慎使用。spa
一行代码生成 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<String>
表明一列的数据,集合内每一个数据将会顺序写入这列每一行。若是每一列的相同行数的内容相同,将会自动合并单元格。经过这个规则,咱们建立复杂的表头。
最终建立表头以下:
写入表体数据
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<Object>>
,可是与表头规则不同。
每一个 List<Object>
表明一行的数据,数据将会按照顺序写入每一列中。
集合中数据 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; }
理论上当前 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.git...
欢迎关注个人公众号:程序通事,得到平常干货推送。若是您对个人专题内容感兴趣,也能够关注个人博客: studyidea.cn