bootstraptable导出excel独立使用_使用 EasyPOI 优雅导出Excel模板数据(含图片)
EasyPOI功能如同名字Easy,主打的功能就是容易,讓一個沒接觸過POI的人員可以方便的寫出Excel導出,Excel模板導出,Excel導入,Word模板導出。通過簡單的注解和模板語言(熟悉的表達式語法),完成以前復雜的寫法。
本文主要通過簡單的分析讓讀者知道Excel模板該如何編寫,EasyPOI要如何使用才能導出滿足自己需要的Excel數據,從而簡化編碼。同時本文還會對一些不常見的功能如圖片導出功能進行說明,讓讀者少踩坑。
版本及依賴說明
EasyPOI4.0.0及以后的版本依賴于Apache POI的4.0.0及以后版本。所以在maven的配置中,兩者的版本號一定要匹配。
需要注意的是,Apache POI的4.0.0相對之前的版本有很大的變更,如果之前代碼中Excel操作部分依賴于舊的版本,那么不建議使用4.0.0及之后的版本。當然,如果之前代碼不涉及或很少涉及WorkBook的創建細節,使用新版也沒有問題。
筆者需要改寫的項目基于JEECG 3.7版本,依賴的是3.9版本的Apache POI,而JEECG維護的jeasypoi版本最高只有2.2.0,而該版本并不支持模板導出圖片功能。說到這里又要吐槽以下JEECG團隊,既然自己不打算維護jeasypoi,那項目中直接使用官方的EasyPOI不就好了,2.2.0版本的jeasypoi給開發者挖了多少坑啊!
為了和舊版本兼容,又想使用EasyPOI帶來的圖片導出功能,所以筆者最終采用的EasyPOI版本是3.3.0,對應的Apache POI依賴是3.15。
Maven配置如下所示:
<properties><poi.version>3.15</poi.version><easypoi.version>3.3.0</easypoi.version> </properties><dependencies><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>${poi.version}</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>${poi.version}</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml-schemas</artifactId><version>${poi.version}</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-scratchpad</artifactId><version>${poi.version}</version></dependency><dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-web</artifactId><version>${easypoi.version}</version></dependency> </dependencies>Excel模板的設計
我們使用EasyPOI的模板導出功能就是不想通過編碼的方式來設計Excel報表的樣式,所以工作的第一步就是設計Excel模板,分清楚哪些部分是固定的,哪些是需要循環填充的。EasyPOI有自己的表達式語言,每種表達式的詳細介紹請參考后文的參考鏈接。
一個簡單的Excel報表模板
一些簡單的模板就不在這里詳細解釋了,只放一下效果圖和模板配置內容。等讀者明白了復雜的模板如何制作并如何填值的時候,簡單的很快就能明白了。
先看看報表效果圖:
再看看實際的模板:
看了上述兩張圖,是不是已經感受到模板導出功能的強大了呢?
一個復雜的Excel報表模板
下面要介紹的這個模板比較復雜,不像是常見的那種一行是一條記錄的情況,所以將詳細介紹該模板的配置,順帶對EasyPOI的部分表達式進行簡單介紹。
還是先看效果圖:
再看看模板:
這兩張圖一對比,是不是有種知識改變命運的感覺?
復雜模板設計剖析
從貨品信息的模板圖及效果圖中我們發現,整個模板實際上分為上下兩部分。其中上部分為不變的抬頭信息,下部分為循環插入的貨品明細信息。所以我們關注的重點是下半部分的語法。
下半部分的第一列圖中沒有顯示完整,實際上是{{!fe: list t.id。
注意,這里 沒有 }}符號!根據EasyPOI的官方文檔,{{}}代表的是表達式,根據表達式取里邊的值。仔細看圖可以發現,表達式的閉合符號{{}}出現在圖中的右下角。也就是說,從第一列{{開始至右下角}}結束,這中間的所有內容都是表達式的一部分。
因為整個模板信息都是表達式的一部分,所以即使是普通字符串也需要專門標明。下面對表達式中的子表達式進行逐個說明。
!fe: 遍歷數據不創建row。
官方文檔中的這句話大家理解起來可能有點費解,什么叫不創建row?實際上,不創建row是相對于創建row而言的,創建row的表達式是fe:。
就像是數據庫中每條記錄對應著一個實體對象,創建row表示每行就是一個實體對象Entity,這個實體對象的屬性用{{}}表達式包裹起來。
不創建row表示整個表達式中只有一個實體對象Object,只不過這個Object比較特別,它是由list中N個Entity拼接起來的。每一個Entity不僅僅是指模型本身,也包含了Excel的樣式,比如占用了幾個單元格,單元格的坐標、排布順序等。
list 自定義的名稱,表示表達式中的數據集合,由代碼以list為鍵,從Map<String, Object>中獲取值的集合。
list這個名字容易理解,就是一個占位符,可以隨便取。EasyPOI解析到list就知道Map<String, Object>中存在著該鍵的值的集合,后邊解析到數據就從該集合中取即可。
t 預定義值,表示集合中的任意對象。
從模板中我們大致能感覺到,list中每個對象叫做t,t.name就代表t的name屬性,所以t這個名字就可以隨便叫,反正它和list一樣,作用是占位符。
但實際上這是一個大坑!如果你把t換成了其他值比如g,模板中其他地方寫g.name g.code等等,最終是解析不到的!官方文檔對這一點并沒有強調,而是作者實際踩了坑之后才發現的!
]] 換行符 多行遍歷導出。
對于這個符號的官方解釋也是莫名其妙,什么叫換行符,多行遍歷導出?實際上它的意思就是,當解析到表達式中含有這個符號,該行后邊的內容就不解析了,管你后邊有沒有其他內容或者樣式。
該符號一定要寫在每行的最后一列,不然會出現每行列數不一樣的情況,EasyPOI內部做賦值的時候就會報空指針異常了。
‘’ 單引號表示常量值 ‘’ 比如’1’ 那么輸出的就是 1
官方文檔中這里的介紹也有坑。''是表示常量值,但實際上Excel中只是這么些是不對的,因為Excel的單元格中遇到'后會認為后面都是字符串,所以得在單元格中寫''庫別:',這樣顯示出來的才是'庫別:',而不是字符串庫別:'。
經過上述分析,圖中的模板實際上就類似以下內容:
{{!fe: list t.id ‘庫別:’ t.bin 換行 ‘商品名稱:’ t.name 換行 ‘商品編號:’ t.code t.barcode 換行 ‘生產日期:’ t.proDate 換行 ‘進貨日期:’ t.recvDate}}如果list中有多條記錄,上述字符串就再循環拼接一些內容,最終都在一個{{}}表達式中。
至此,模板的設計已剖析完畢,讀者可根據自己的需求結合官方文檔自行設計模板。下面將對模板賦值進行介紹。
準備模板數據
從上節的描述中可知,只需要準備一個Map<String, Object>的對象即可,其中鍵為list,值為一個List數組,數組中元素類型為Map<String, Object>。代碼如下:
Map<String, Object> total = new HashMap<>(); List<Map<String, Object>> mapList = new ArrayList<>(); for (int i = 1; i <= 5; i++) {Map<String, Object> map = new HashMap<>();map.put("id", i + "");map.put("bin", "001 1000千克");map.put("name", "商品" + i);map.put("code", "goods" + i);map.put("proDate", "2019-05-30");map.put("recvDate", "2019-07-07");// 插入圖片ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();BufferedImage bufferImg = ImageIO.read(BarcodeUtil.generateToStream("001"));ImageIO.write(bufferImg, "jpg", byteArrayOut);ImageEntity imageEntity = new ImageEntity(byteArrayOut.toByteArray(), 200, 1000);map.put("barcode", imageEntity);mapList.add(map); } total.put("list", mapList);圖片數據導出
上述代碼中需要特殊關注的是圖片導出部分。EasyPOI導出圖片有兩種方式,一種是通過圖片的Url,還有一種是獲取圖片的byte[],畢竟圖片的本質就是byte[]。因為筆者的項目中圖片不是存放在數據庫之中,而是需要根據查詢結果動態生成條碼,所以通過byte[]導出圖片。
ImageEntity是EasyPOI內置的一個JavaBean,用于設定圖片的寬度和高度、導出方式、RowSpan和ColumnSpan等。調試EasyPOI的源碼可知,當設置了RowSpan或者ColumnSpan之后,圖片的高度設置就失效了,圖片大小會自動填充圖片所在的單元格。
圖片導出的坑點在于導出圖片的大小。假設我們將四個單元格合成為一個,希望導出的圖片能填充合并之后的單元格,但是對不起,EasyPOI暫時做不到,它只會填充合并之前左上角的單元格,具體原因如下源碼所示:
//BaseExportService.java ClientAnchor anchor; if (type.equals(ExcelType.HSSF)) {anchor = new HSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1),cell.getRow().getRowNum() + 1); } else {anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1),cell.getRow().getRowNum() + 1); }可以看到,在創建圖片插入位置的時候已經指定了圖片的跨度為1行1列,即左上角的單元格。如果之前又設置了RowSpan或者ColumnSpan,那么圖片高度的設置也會失效,最終導致導出的圖片非常小。
個人認為ImageEntity提供的RowSpan或者ColumnSpan的set方法并沒有什么用,因為我們動態創建的合并單元格并不能被賦值。所以,導出圖片的最好方式就是直接指定它的高度,因為寬度會自動填充單元格,模板中單元格的寬度要合適。
//ExcelExportOfTemplateUtil.java if (img.getRowspan()>1 || img.getColspan() > 1){img.setHeight(0);PoiMergeCellUtil.addMergedRegion(cell.getSheet(),cell.getRowIndex(),cell.getRowIndex() + img.getRowspan() - 1, cell.getColumnIndex(), cell.getColumnIndex() + img.getColspan() -1); }將數據導出至模板
以上準備工作全部完成后就可以將模板和數據進行組裝了,或者說是渲染,代碼如下所示:
public static void exportByTemplate(String templateName, Map<String, Object> data, OutputStream fileOut) {TemplateExportParams params = new TemplateExportParams("export/template/" + templateName, true);try {Workbook workbook = ExcelExportUtil.exportExcel(params, data);workbook.write(fileOut);} catch (Exception e) {LogUtil.error("", e);} }總結
網上針對EasyPOI的介紹多限于最基本的行插入功能,但實際上Excel模板的需求可能各式各樣。本文只是拋磚引玉,對EasyPOI中的部分概念做了詳細介紹,希望幫助大家少踩坑。
如果想詳細了解EasyPOI的各種功能,參考鏈接中的文檔說明及測試項目源碼就是最好的學習資料。希望大家都能得心應手地使用EasyPOI,大大提升開發效率!
參考鏈接
EasyPOI官方文檔
- https://opensource.afterturn.cn/doc/easypoi.html
EasyPOI測試項目
- https://gitee.com/lemur/easypoi-test
一些坑
近日有網友求助我解決EasyPOI的復雜模板配置問題,通過解決該網友的問題發現了EasyPOI中的幾個坑點,補充說明幾個問題。
在復雜模板設計剖析一節中已經描述了EasyPOI支持的復雜的模板該如何配置。該模板的配置是絕對正確的,但是有3個點沒有說清楚,大家在照葫蘆畫瓢時容易出錯:
來源:使用EasyPOI導出Excel模板數據(含圖片)_星懸_月的博客-CSDN博客
總結
以上是生活随笔為你收集整理的bootstraptable导出excel独立使用_使用 EasyPOI 优雅导出Excel模板数据(含图片)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: xutils找id空指针_xUtils更
- 下一篇: windows media player