博文地址: 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