我去,还在这样读写 excel 这也太低效了吧,好办法来了
??點擊上方?好好學java?,選擇?星標?公眾號
重磅資訊、干貨,第一時間送達 今日推薦:牛人 20000 字的 Spring Cloud 總結(jié),太硬核了~作者:樓下小黑哥 鏈接:https://www.cnblogs.com/goodAndyxublog/p/12683641.html前言
博文地址:https://sourl.cn/SsD3AM
最近讀者小 H 給小黑哥發(fā)來私信:
小黑哥,最近我在負責公司報表平臺開發(fā),需要導出報表到 excel 中。每次使用 POI 開發(fā),都要寫長長的一坨代碼,好幾次因為沒加入判空判斷,導致生成失敗。想跟你請教下有沒有更加高效一點讀寫 excel 方法?
使用過 poi 的開發(fā)同學可能都有此體會,每次都要寫一坨代碼,最后的代碼如下面一樣:
這樣的代碼是不是又臭又長?當字段數(shù)量多的時候,一不小心還容易寫錯。小黑哥還記得當初使用 poi 導出一個二十多字段的 excel,不斷復制粘貼,行號一不小心就寫錯了,那叫個一個心酸。
今天小黑哥就來推薦一個阿里開源的項目『EasyExcel』,帶大家徹底告別上面又長又臭的代碼,徹底解決這個問題。
EasyExcel
EasyExcel 是一個阿里出品的開源項目 ,看名字就能看出這個項目是為了讓你更加簡單的操作 Excel。另外 EasyExcel 還解決了poi 內(nèi)存溢出問題,修復了一些并發(fā)情況下一些 bug。
github 地址:https://github.com/alibaba/easyexcel
截止小黑哥寫文章時,已有 13.6k star 數(shù)據(jù),可見這個項目還是深受大家歡迎。
廢話不多說,我們直接進入源碼實戰(zhàn)環(huán)節(jié)。
首先我們需要引入 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());// 寫入數(shù)據(jù)生成 excel 代碼特別簡單,這里使用鏈式語句,一行代碼直接搞定生成代碼。代碼中再也不用我們指定行號,列號了。
上面代碼中使用自適應列寬的策略。
下面我們來看下表頭與標題如何生成。
創(chuàng)建表頭
/*** 創(chuàng)建表頭,可以創(chuàng)建復雜的表頭** @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> 代表一列的數(shù)據(jù),集合內(nèi)每個數(shù)據(jù)將會順序?qū)懭脒@列每一行。如果每一列的相同行數(shù)的內(nèi)容相同,將會自動合并單元格。通過這個規(guī)則,我們創(chuàng)建復雜的表頭。
最終創(chuàng)建表頭如下:
寫入表體數(shù)據(jù)
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; }表體數(shù)據(jù)然后也是使用 List<List<Object>>,但是與表頭規(guī)則不一樣。
每個 List<Object> 代表一行的數(shù)據(jù),數(shù)據(jù)將會按照順序?qū)懭朊恳涣兄小?/p>
集合中數(shù)據(jù) EasyExcel 將會按照默認的格式化轉(zhuǎn)換輸出,比如 date 類型數(shù)據(jù)就將會按照 yyyy-MM-dd HH:mm:ss 格式化。
如果需要轉(zhuǎn)化成其他格式,建議直接將數(shù)據(jù)格式化成字符串加入 List,不要通過 EasyExcel 轉(zhuǎn)換。
最終效果如下:
看完這個是不是想立刻體驗一下?等等,上面使用方式還是有點繁瑣,使用 EasyExcel 還可以更快。我們可以使用注解方式,無需手動設置表頭與表體。
注解方式
注解方式生成 Excel 代碼如下:
String fileName = "temp/annotateWrite" + System.currentTimeMillis() + ".xlsx"; // 這里 需要指定寫用哪個class去寫,然后寫到第一個sheet,名字為模板 然后文件流會自動關(guān)閉 // 如果這里想使用03 則 傳入excelType參數(shù)即可 EasyExcel.write(fileName, DemoData.class).sheet("注解方式").registerWriteHandler(createTableStyle())// Excel 表格樣式.doWrite(data());這里代碼與上面大體一致,只不過這里需要在 write 方法傳入 DemoData 數(shù)據(jù)類型。EasyExcel 會根據(jù) DemoData 類型自動生成表頭。
下面我們來看下 DemoData這個類到底內(nèi)部到底是啥樣?
@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("數(shù)字標題")private Double doubleData;@ExcelProperty(value = "枚舉類",converter = DemoEnumConvert.class)private DemoEnum demoEnum;/*** 忽略這個字段*/@ExcelIgnoreprivate String ignore; }DemoData 就是一個普通的 POJO 類,上面使用 ExayExcel 相關(guān)注解,ExayExcel 將會通過反射讀取字段類型以及相關(guān)注解,然后直接生成 Excel 。
ExayExcel 提供相關(guān)注解類,直接定義 Excel 的數(shù)據(jù)模型:
@ExcelProperty 指定當前字段對應excel中的那一列,內(nèi)部 value 屬性指定表頭列的名稱
@ExcelIgnore 默認所有字段都會和excel去匹配,加了這個注解會忽略該字段
@ContentRowHeight 指定表體行高
@HeadRowHeight 指定表頭行高
@ColumnWidth 指定列的寬度
另外 ExayExcel 還提供幾個注解,自定義日期以及數(shù)字的格式化轉(zhuǎn)化。
@DateTimeFormat
@NumberFormat
另外我們可以自定義格式化轉(zhuǎn)換方案,需要實現(xiàn) Converter 類相關(guān)方法即可。
public class DemoEnumConvert implements Converter<DemoEnum> {@Overridepublic Class supportJavaTypeKey() {return DemoEnum.class;}@Overridepublic CellDataTypeEnum supportExcelTypeKey() {return CellDataTypeEnum.STRING;}/*** excel 轉(zhuǎn)化為 java 類型,excel 讀時將會被調(diào)用* @param cellData* @param contentProperty* @param globalConfiguration* @return* @throws Exception*/@Overridepublic DemoEnum convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {return null;}/*** java 類型轉(zhuǎn) excel 類型,excel 寫時將會被調(diào)用* @param value* @param contentProperty* @param globalConfiguration* @return* @throws Exception*/@Overridepublic CellData convertToExcelData(DemoEnum value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {return new CellData(value.getDesc());} }最后我們還需要在 @ExcelProperty 注解上使用 converter 指定自定義格式轉(zhuǎn)換方案。
使用方式如下:
@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);// 內(nèi)容的策略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);// 這個策略是 頭是頭的樣式 內(nèi)容是內(nèi)容的樣式 其他的策略可以自己實現(xiàn)HorizontalCellStyleStrategy horizontalCellStyleStrategy =new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);return horizontalCellStyleStrategy; }使用注意點
poi 沖突問題
理論上當前 easyexcel兼容支持 poi 的3.17,4.0.1,4.1.0所有較新版本,但是如果項目之前使用較老版本的 poi,由于 poi 內(nèi)部代碼調(diào)整,某些類已被刪除,這樣直接運行時很大可能會拋出以下異常:
NoSuchMethodException
ClassNotFoundException
NoClassDefFoundError
所以使用過程中一定要注意統(tǒng)一項目中的 poi 的版本。
非注解方式自定義行高列寬
非注解方式自定義行高以及列寬比較麻煩,暫時沒有找到直接設置的入口。查了一遍 github 相關(guān) issue,開發(fā)人員回復需要實現(xiàn) WriteHandler 接口,自定義表格樣式。
總結(jié)
本文主要給各位小伙伴們安利 EasyExcel 強大的功能,介紹 EasyExcel 兩種生成 excel 方式,以及演示相關(guān)的示例代碼。EasyExcel 除了寫之外,當然還支持快讀讀取 Excel 的功能,這里就不再詳細介紹。Github 上相關(guān)文檔例子非常豐富,大家可以自行參考。
Github 文檔地址:https://alibaba-easyexcel.github.io/index.html
Reference
https://github.com/alibaba/easyexcel
https://alibaba-easyexcel.github.io/index.html
https://cloud.tencent.com/developer/article/1431888
總結(jié)
以上是生活随笔為你收集整理的我去,还在这样读写 excel 这也太低效了吧,好办法来了的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 看一遍就理解,图解单链表反转
- 下一篇: 只需 5 分钟看完这篇 HTTPS,去阿