在業務開發中咱們常常會遇到Excel的導入導出,而 Apache POI 是Java開發者經常使用的API。
【https://poi.apache.org/components/spreadsheet/index.html】html
Universal solution for reading and writing simply Excel based on functional programming and POI EventModel
GridExcel是基於Java8函數式編程和POI EventModel實現的用於Excel簡單讀寫的通用解決方案。java
什麼是EventModel?在POI FAQ(常見問題解答)【https://poi.apache.org/help/faq.html#faq-N100C2】官方給出解釋:git
The SS eventmodel package is an API for reading Excel files without loading the whole spreadsheet into memory. It does require more knowledge on the part of the user, but reduces memory consumption by more than tenfold. It is based on the AWT event model in combination with SAX. If you need read-only access, this is the best way to do it.
SS eventmodel包是一個用於讀取Excel文件而不將整個電子表格加載到內存中的API。 它確實須要用戶掌握更多知識,可是將內存消耗減小了十倍以上。 它基於AWT(Abstract Window Toolkit)event model與SAX的結合。 若是您須要只讀訪問權限,這是最好的方式。程序員
說到函數編程,就不得不提Lambda表達式,若是對Java8中的Lambda不瞭解或理解不深入,能夠看下甲骨文官網給出的這篇文章,【https://www.oracle.com/technetwork/articles/java/architect-lambdas-part1-2080972.html】,我的認爲這是Java8 Lambda從入門到進階最好的文章之一。github
其中函數編程的目的就是實現代碼塊傳遞
,即,將方法做爲參數在方法間傳遞。爲此,隨着Java語言的發展,不斷出現一些解決方案:apache
內部類
和匿名內部類
來實現,可是大多數狀況下,它們只是被用做事件處理。碼塊做爲對象
(其實是數據)不只有用並且是必要的,可是Java中函數編程仍是很笨拙,它須要成長。注意: 五、六、7參考《深刻理解Java虛擬機》第2版,8.3.3 動態類型語言支持。編程
在POI的使用過程當中,對大多數API User來講常常面臨兩個問題,這也是GridExcel致力解決的問題。oracle
將Excel處理邏輯抽取出來,封裝成工具類。ide
與大多數Java API同樣,POI把更多的精力放在高級功能的處理上,好比Formula(公式)、Conditional Formatting(條件格式)、Zoom(縮放)等。對於僅僅作數據導入導出功能的API User,不多使用這些高級特性,這容許API用戶對POI的使用進行簡單的封裝。函數式編程
不管是讀是寫,咱們都須要解決Excel中的Columns(列)與Java數據對象Fields(字段)的映射關係,將這種映射關係做爲參數(Map對象HashMap或LinkedHashMap),傳遞給工具類。
對於Columns不難理解,它能夠是有序的數字或字母,也能夠是其它字符串用來做爲首行,表示該列數據的含義。
對於Fields,它的處理須要兼容複雜狀況,以下:
value == true?完成:失敗;
首先想到,也是大多數封裝者都在使用的方式是就是Reflection API,從上文 函數編程 章節咱們瞭解到,反射重量級,會下降代碼的性能,同時對複雜狀況的處理支持性不夠好。
這種方式能夠更好的支持複雜狀況,可是反射依然會下降性能,同時註解對數據對象會形成代碼侵入,並且對該工具類封裝者的其餘使用者無疑會增長學習成本。
這種方式也能夠很好的支持複雜狀況,可是使用匿名內部類的語法顯然患有「垂直問題」(這意味着代碼須要太多的線條來表達基本概念),太過冗雜。至於性能,應該也不如直接傳遞函數來的快吧。
這種方式是基於第5條方法調用的字節碼指令invokeDynamic實現的,直接傳遞函數代碼塊,很好的支持複雜狀況,性能較高,代碼編寫更簡單結構更加簡潔,並且對數據對象代碼零侵入。
內存溢出
或頻繁的Full GC
,該如何解決?POI的使用對咱們來講很常見,對下面兩個概念應該並不陌生:
可是對於eventmodel和streaming.SXSSFWorkbook就不多接觸了,它們是POI提供的專門用來解決內存佔用問題的low level API(低級API),使用它們能夠讀寫數據量很是大的Excel,同時能夠避免內存溢出
或頻繁的Full GC
。【https://poi.apache.org/compon...】
streaming.SXSSFWorkbook,用來寫Excel(是對XSSFWorkbook的封裝,僅支持.xlsx),經過滑動窗口來實現,只在內存中保留滑動窗口容許存在的行數,超出的行Rows被寫出到臨時文件,當調用write(OutputStream stream)
方法寫出內容時,再直接從臨時內存寫出到目標OutputStream。SXSSFWorkbook的使用會產生一些侷限性。
基於Java函數編程(Lambda),支持流式API,使用環境Java1.8或更高,學習成本:Lambda
實際上POI官網已經給了用戶使用示例,而上述工具只是作了本身的封裝實現,讓使用更方便。
<dependency> <groupId>com.github.liuhuagui</groupId> <artifactId>gridexcel</artifactId> <version>2.2</version> </dependency>
GridExcel.java提供了多種靜態方法,能夠直接使用,具體式例可參考測試代碼(提供了測試數據和測試文件):
/** * 業務邏輯處理方式三選一: * 1.啓用windowListener,並將業務邏輯放在該函數中。 * 2.不啓用windowListener,使用get()方法取回所有數據集合,作後續處理。 * 3.readFunction函數,直接放在函數中處理 或 使用final or effective final的局部變量存放這寫數據,作後續處理。 * 注意:使用EventModel時readFunction函數的輸入爲每行的cell值集合List<String>。 * @throws Exception */ @Test public void readXlsxByEventModel() throws Exception { InputStream resourceAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("2007.xlsx"); GridExcel.readByEventModel(resourceAsStream,TradeOrder.class,ExcelType.XLSX) .window(2,ts -> System.out.println(JSON.toJSONString(ts)))//推薦在這裏執行本身的業務邏輯 .process(cs ->{ TradeOrder tradeOrder = new TradeOrder(); tradeOrder.setTradeOrderId(Long.valueOf(cs.get(0))); Consultant consultant = new Consultant(); consultant.setConsultantName(cs.get(3)); tradeOrder.setConsultant(consultant); tradeOrder.setPaymentRatio(cs.get(16)); return tradeOrder; },1); } /** * 使用Streaming UserModel寫出數據到Excel * @throws Exception */ @Test public void writeExcelByStreaming() throws Exception { GridExcel.writeByStreaming(TradeOrder.class) .head(writeFunctionMap())//對象字段到Excel列的映射 .createSheet() .process(MockData.data())//模擬數據。在這裏設置業務數據集合。 .write(FileUtils.openOutputStream(new File("/excel/test.xlsx"))); }
Use user model to read excel file. userModel ——
Use event model to read excel file. eventModel ——
Use user model to write excel file. userModel ——
Use API-compatible streaming extension of XSSF to write very large excel file. streaming userModel——
缺點:
在使用工具過程當中出現問題,有功能添加或改動需求的能夠向做者提Issue:https://github.com/liuhuagui/...