近期,由於需要對項目中的數據進行治理,設計到大量Excel文件的讀取。爲了簡化工作,開發了template-excel組件。本項目已在gitee上開源,源碼地址:https://gitee.com/beiding/template-excel。demo地址:https://gitee.com/beiding/template-excel-demo
安裝及使用:
1 添加maven依賴:
<dependency>
<groupId>com.gitee.beiding</groupId>
<artifactId>template-excel</artifactId>
<version>1.2.0-RELEASE</version>
</dependency>
2 渲染操作:
2.1 編寫渲染模板:
渲染表達式請翻閱下文
2.2 讀取渲染模板並對數據實體進行渲染
//將需要渲染的數據放入Data容器中 data = Data.create(); data.put("students", students); //模板Excel的輸入流 templateInputStream = new FileInputStream("模板.xlsx"); //渲染結果的輸出流 resultOutputStream = new FileOutputStream("結果.xlsx"); Renderer.render(data, templateInputStream, resultOutputStream);
渲染後生成的Excel:
3 提取操作:
3.1 編寫提取模板:
//你也可以在Excel文件中編寫提取模板,然後使用流的方式讀取 XSSFSheet templateSeet = FastSheet.create("Sheet1") .newRow() .cell("A","序號").cell("B", "姓名").cell("C", "科目編號").cell("D", "科目") .newRow() .cell("A","${/[0-9]*/}").cell("B", "${students[i].name/張偉[0-9]+/}").cell("C", "${students[i].indexs[j]}").cell("D", "選修科目:${students[i].subjects[j]}") .toXSSFSheet();
提取表達式編寫語法請翻閱下文
3.2 提取數據Excel中的數據
ExtractResult result = Extractor.extract( templateSeet //提取模板 , dataInputStream//數據excel輸入流 , TypeMapperBuilder.createAndMapping("students[i]", Student.class).toMap(), ColNumberMatchingMode.EQUALS);//實體映射 //從提取的結果中獲取數據實體 List<Student> list = result.get("students", List.class); for (Student student : list) { System.out.println(student); }
渲染表達式說明 1.${xxx}是渲染表達式,在渲染表達式之外的文本將會原樣輸出. 2.如果使用"[index]"作爲某個實體的後綴,則表示這個實體是可遍歷的,渲染引擎會將其遍歷展開 例如:表達式"${students[i].name}"中的students實體會被遍歷展開,並且將展開的每個實體的name屬性填入該單元格 3.在同一行中對使用了同名自增變量的多個渲染表達式,其遍歷過程是同步的 例如:表達式"${students[i].name}"和表達式"${students[i].indexs[j]}"都使用了i作爲students的自增變量,因此在這兩個單元格展開時使用的是同一個Student實體 4.渲染表達式支持多維數組或多層級數組的展開 例如:array[i][j]或者students[i].indexs[j] 多維數組或多層級數組展開時,引擎將採用字典順序確定自增變量的層級關係 例如:表達式"${students[i].indexs[j]}"中存在i和j兩個自增變量,那麼在展開時自增變量將採用以下等效的層級關係 for(i=0;i<iMax;i++){ for(j=0;j<jMax;j++){ ... } } *確定自增變量的層級關係有時也是一件重要的事情,因爲這會影響單元格合併情況 5.當同一行中渲染表達式渲染的結果存在一對多關係時,引擎會自動將一的那一方進行單元格合併 例如:表達式"${students[i].name}"和表達式"${students[i].indexs[j]}" Student實體中name和indexs之間是存在一對多的關係的,因此name會自動單元格合併 6.可以採用函數對數據進行操作後再進行遍歷輸出: 例如:表達式"${reversal(students[i].subjects)[j]}"中,reversal就是一個反轉函數,該表達式能夠叫Student實體中的subjects列表反轉後再進行遍歷輸出(無需擔心性能問題,因爲reversal函數是帶有緩存的. 你也可以使用com.beiding.template-excel.Js.defineFunction函數自定義函數,使用該方法定義的函數都會自帶緩存,請不要在方法定義中手動調用_cacheGet和_cachePut,可能會造成無限遞歸問題) 指令函數說明 1. 由於無法在數據展開的過程中確定數據行的索引,因此對於依賴數據行索引生成的數據就無法使用渲染表達式生成,指令函數提供一種方式在數據填充進單元格時生成所需的數據 2. 格式爲"$xxx(xx)",例如"$index(from)" 3. 你可以使用com.beiding.template-excel.Js.defineCommand定義一個指令函數. 例如: Js.defineCommand("function $test(){return "測試"}") 指令定義中,你可以引用"_index",這是一個以模板行爲單位的索引引用,從0開始自增模板行展開的行數 例如:一個模板行展開了20行,index會從0開始自增到19 你也可以引用_globalIndex,這是從0開始的當前Sheet頁的全局行號引用 _col是當前列的列號,從0開始 *注意:指令函數不要寫在渲染表達式中 提取表達式說明 1. ${xxx/regex/}是提取表達式的標準格式,xxx是接收提取結果的實體字段,regex是匹配正則 例如:${student.name/張偉[0-9]+/}表示將滿足"張偉[0-9]+"正則的數據提取爲student實體的name字段 2. ${xxx}是全匹配提取表達式的簡寫模式,該表達式將任意內容提取到xxx 3. ${/regex/}非獲取匹配表達式,該表達式只會檢驗數據是否匹配regex正則,但不會保存匹配到的內容 4. 當對數據實體使用"[index]"作爲後綴時,表明這是一個列表,引擎會將連續多行匹配的結果填充爲一個列表,並自動處理一對多關係 例如:${students[i].name/張偉[0-9]+/}會將students創建爲List<Student> *注意:提取表達式不支持多維數組,並且引擎會自動忽略自增變量的名稱,引擎在解析時會將自增變量抹除 例如:${students[i].indexs[j]}會被處理爲${students[].indexs[]} 但是爲了更好的表意性推薦將索引變化情況相同的實體使用相同名稱的自增變量 *注意:提取模板是不匹配樣式的