計算機與人相比,有什麼優點?這個問題從計算機誕生之初就不斷被回答:在重複性工做上,計算機有人類沒法企及的計算速度和存儲空間。所以,把重複性工做交給計算機,也就是常說的「可複用性」,是軟件設計中的一個最基本的思想。java
這裏記錄的這個小設計,就是把重複工做自動化處理的一個例子。git
背景github
在咱們的系統中,常常有用戶上傳一個Excel文件、系統進行處理的需求。數組
Excel的處理框架,有Jxl和POI。咱們的系統使用了POI框架,並封裝了若干個Util工具類。可是,因爲工具類的封裝不到位,業務代碼中仍然會有大量的解析Excel文件(而且還存留了不少只接受.xls文件、沒法處理.xlsx文件的代碼)、遍歷sheet/row/cell、處理單元格和Java對象類型轉換的重複代碼。 多線程
所以,我設計實現了這個小小的工具。框架
思路異步
Excel導入的基本流程以下圖所示。這個導入工具封裝了校驗、Excel轉pojo這兩個步驟,數據處理則做爲擴展點留給了業務代碼。ide
除基本功能外,這個框架還須要考慮性能問題。所以,方案中要爲Excel轉pojo和數據處理這兩個操做預留異步的擴展點,以期提升處理效率。而且據我之前的測試,一個大小爲1MB的Excel文件,放入JVM中以後要佔用約2MB的內存空間。因此這個框架還應儘可能節省(或者儘快釋放)內存空間。函數
類圖工具
文件導入框架的入口是FileImporrtor接口。主方法入參是一個標記接口,其中要求提供字節數組,做爲待導入的文件數據。導入時若是還須要其它數據,能夠在實現接口時自行擴展、提供。
這裏將文件轉化爲字節數組,主要有兩點考慮。一方面,這樣作能夠兼容不一樣格式、不一樣封裝的文件。例如,不管是MultipartFile仍是File、不管是txt仍是doc文件,均可以在轉成字節數組後歸入框架中來進行處理。另外一方面,不管是File仍是InputStream,都會佔用句柄、鏈接等資源。管理這些資源並非這個框架的職能——事實上,技術框架都沒法肯定業務資源應當什麼時候關閉。所以,接口只接受字節數組形式的入參。
框架中實現了一個Excel的導入類FileImportor4Excel。這個類使用POI框架做爲底層工具。其中處理其實很簡單,就是使用POI解析出excel文件後,遍歷其中的sheet/row/cell,將其中數據轉換爲Java封裝類。
解析Excel的流程中,將數據轉換爲Java封裝類是比較困難的一個點。由於Excel中的數據類型只有那麼幾種,定義爲Cell中的幾個int常量。可是Java類型卻有千千萬。如何把它們正確的轉換爲Java類型?框架中引入了CellValueTransfer和ExcelImportHelper這兩個類。CellValueTransfer是一個接口,定義了將POI的Cell轉換爲Java類的方法,並提供了若干個基礎實現類。而ExcelImportHelper則是一個輔助類,用於爲當前的Cell和Java類找到合適的CellValueTransfer,並執行轉換操做。
後來增長了FileImportor4ExcelParallel,引入了多線程來處理。其中使用的線程池是ForkJoinPool,由於Excel導入恰能夠「分而治之」。不過引入多線程後,整個Excel中的數據就沒法在同一個事務中進行處理了。
此外還增長了一個帶回調函數的類FileImportor4ExcelCallback。由於原邏輯中,須要將Excel所有轉換爲List而後再作處理。加入Callback以後,則能夠每轉換一條數據就處理一條數據,而且能夠在處理完成後迅速丟棄(設置爲null)該數據,以儘快釋放內存。
代碼
https://github.com/winters1224/blogs/tree/master/code/src/main/java/net/loyintean/blog/fileimport
不過這裏只有早期的部分代碼,不包括後來的優化整理和功能擴展。