java?freemarker實(shí)現(xiàn)動(dòng)態(tài)生成excel文件
最近做了一個(gè)動(dòng)態(tài)生成excel的功能,這里記錄下部分功能,主要用到的是freemarker框架,spring就有帶,我起的demo載入了一下freemarker的jar包
一、創(chuàng)建模板
首先可以創(chuàng)建一個(gè)excel,編輯自己想要的模板,這里舉個(gè)簡單的例子
編寫好后可以保存一下,然后再保存為.xml格式的文件,就能得到模板雛形
大概是長這樣
然后根據(jù)ftl文件的語法,我們可以對(duì)模板進(jìn)行改造,加入自己需要的字段
這里列舉一些常見的方式
1、普通字段填充
<Cell ss:StyleID="s17"><Data ss:Type="String">姓名</Data></Cell> <Cell ss:StyleID="s17"><Data ss:Type="String">${(name)!}</Data></Cell>
2、日期填充,java傳入的參數(shù)類型為Date
<Cell ss:Index="2" ss:StyleID="s17"><Data ss:Type="String">出生年月</Data></Cell> <Cell ss:StyleID="s17"> <#if birth??><Data ss:Type="String">${birth?string("yyyy-MM-dd")}</Data></#if> </Cell>
3、switch case選擇用法
<Cell ss:StyleID="s17"><Data ss:Type="String">國籍</Data></Cell> <Cell ss:StyleID="s17"> <#if certType??> <#switch certType> <#case "A"> <Data ss:Type="String">■身份證 □外籍護(hù)照 □港澳居民來往內(nèi)地通行證</Data> <#break> <#case "B"> <Data ss:Type="String">□身份證 ■外籍護(hù)照 □港澳居民來往內(nèi)地通行證</Data> <#break> <#case "C"> <Data ss:Type="String">□身份證 □外籍護(hù)照 ■港澳居民來往內(nèi)地通行證</Data> <#break> <#default> </#switch> <#else> <Data ss:Type="String">□身份證 □外籍護(hù)照 □港澳居民來往內(nèi)地通行證</Data> </#if> </Cell>
4、數(shù)組對(duì)象展示
(這邊我做的這個(gè)主要是因?yàn)橛袆?dòng)態(tài)展示的需求,如果沒有家屬信息,就不展示家屬單元格)
<#list spouseInfos as row> <Row ss:AutoFitHeight="0"> <Cell ss:MergeDown="2" ss:StyleID="s18"><Data ss:Type="String">家屬信息</Data></Cell> <Cell ss:StyleID="s17"><Data ss:Type="String">姓名</Data></Cell> <Cell ss:StyleID="s17"><Data ss:Type="String">${(row.name)!}</Data></Cell> </Row> <Row> <Cell ss:Index="2" ss:StyleID="s17"><Data ss:Type="String">關(guān)系</Data></Cell> <Cell ss:StyleID="s17"><Data ss:Type="String">${(row.relation)!}</Data></Cell> </Row> <Row> <Cell ss:Index="2" ss:StyleID="s17"><Data ss:Type="String">聯(lián)系電話</Data></Cell> <Cell ss:StyleID="s17"><Data ss:Type="String">${(row.tel)!}</Data></Cell> </Row> </#list>
這里需要注意如果使用了數(shù)組動(dòng)態(tài)展示需要計(jì)算行數(shù)
可以把xml文件里的ExpandedRowCount參數(shù)進(jìn)行修改,加入totalRowCount參數(shù)標(biāo)記行數(shù)
在java程序中需要?jiǎng)討B(tài)計(jì)算這個(gè)行數(shù)
<Table ss:ExpandedColumnCount="3" ss:ExpandedRowCount="${(totalRowCount)!}" x:FullColumns="1" x:FullRows="1" ss:DefaultColumnWidth="54" ss:DefaultRowHeight="13.5">
模板制作好以后保存再修改文件格式名稱為.ftl即可
主體部分為
<Table ss:ExpandedColumnCount="3" ss:ExpandedRowCount="${(totalRowCount)!}" x:FullColumns="1" x:FullRows="1" ss:DefaultColumnWidth="54" ss:DefaultRowHeight="13.5"> <Column ss:Index="3" ss:AutoFitWidth="0" ss:Width="310.5"/> <Row> <Cell ss:MergeDown="2" ss:StyleID="s18"><Data ss:Type="String">基本信息</Data></Cell> <Cell ss:StyleID="s17"><Data ss:Type="String">姓名</Data></Cell> <Cell ss:StyleID="s17"><Data ss:Type="String">${(name)!}</Data></Cell> </Row> <Row> <Cell ss:Index="2" ss:StyleID="s17"><Data ss:Type="String">性別</Data></Cell> <Cell ss:StyleID="s17"><Data ss:Type="String">${(sex)!}</Data></Cell> </Row> <Row> <Cell ss:Index="2" ss:StyleID="s17"><Data ss:Type="String">出生年月</Data></Cell> <Cell ss:StyleID="s17"> <#if birth??><Data ss:Type="String">${birth?string("yyyy-MM-dd")}</Data></#if> </Cell> </Row> <Row> <Cell ss:MergeDown="2" ss:StyleID="s18"><Data ss:Type="String">其他信息</Data></Cell> <Cell ss:StyleID="s17"><Data ss:Type="String">國籍</Data></Cell> <Cell ss:StyleID="s17"> <#if certType??> <#switch certType> <#case "A"> <Data ss:Type="String">■身份證 □外籍護(hù)照 □港澳居民來往內(nèi)地通行證</Data> <#break> <#case "B"> <Data ss:Type="String">□身份證 ■外籍護(hù)照 □港澳居民來往內(nèi)地通行證</Data> <#break> <#case "C"> <Data ss:Type="String">□身份證 □外籍護(hù)照 ■港澳居民來往內(nèi)地通行證</Data> <#break> <#default> </#switch> <#else> <Data ss:Type="String">□身份證 □外籍護(hù)照 □港澳居民來往內(nèi)地通行證</Data> </#if> </Cell> </Row> <Row> <Cell ss:Index="2" ss:StyleID="s17"><Data ss:Type="String">居住地址</Data></Cell> <Cell ss:StyleID="s17"><Data ss:Type="String">${(address)!}</Data></Cell> </Row> <Row> <Cell ss:Index="2" ss:StyleID="s17"><Data ss:Type="String">聯(lián)系電話</Data></Cell> <Cell ss:StyleID="s17"><Data ss:Type="String">${(tel)!}</Data></Cell> </Row> <#list spouseInfos as row> <Row ss:AutoFitHeight="0"> <Cell ss:MergeDown="2" ss:StyleID="s18"><Data ss:Type="String">家屬信息</Data></Cell> <Cell ss:StyleID="s17"><Data ss:Type="String">姓名</Data></Cell> <Cell ss:StyleID="s17"><Data ss:Type="String">${(row.name)!}</Data></Cell> </Row> <Row> <Cell ss:Index="2" ss:StyleID="s17"><Data ss:Type="String">關(guān)系</Data></Cell> <Cell ss:StyleID="s17"><Data ss:Type="String">${(row.relation)!}</Data></Cell> </Row> <Row> <Cell ss:Index="2" ss:StyleID="s17"><Data ss:Type="String">聯(lián)系電話</Data></Cell> <Cell ss:StyleID="s17"><Data ss:Type="String">${(row.tel)!}</Data></Cell> </Row> </#list> </Table>
二、生成文件
生成文件的主要java代碼如下
import freemarker.template.Configuration; import freemarker.template.Template; import java.io.*; import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; public class ExcelUtil { /** * 根據(jù)模板生成文件 * @param dataMap 寫入數(shù)據(jù) * @param templateFilePath 模板文件路徑 * @param outFileName 輸出文件路徑 */ public static void doGenerateFile(Map<String, Object> dataMap, String templateFilePath, String outFileName) { Writer out = null; FileOutputStream fileStream = null; //需要壓縮的文件,大于1個(gè)才會(huì)壓縮 try {//生成合同文件 Configuration configuration = new Configuration(); configuration.setDefaultEncoding("UTF-8"); Template t = configuration.getTemplate(templateFilePath); // 獲取模板文件 // 導(dǎo)出文件 File outFile = new File(outFileName); //獲取父目錄 File fileParent = outFile.getParentFile(); //判斷是否存在 if (!fileParent.exists()) { //創(chuàng)建父目錄文件 fileParent.mkdirs(); } OutputStreamWriter oWriter = null; fileStream = new FileOutputStream(outFile); oWriter = new OutputStreamWriter(fileStream, StandardCharsets.UTF_8); out = new BufferedWriter(oWriter); // 將填充數(shù)據(jù)填入模板文件并輸出到目標(biāo)文件 t.process(dataMap, out); } catch (Exception e1) { if (fileStream != null && out != null) { close(fileStream, out); } System.out.println("生成文件出錯(cuò)," + e1.getMessage()); } finally { if (fileStream != null && out != null) { close(fileStream, out); } } } private static void close(FileOutputStream fileStream, Writer out) { try { fileStream.flush(); fileStream.close(); out.flush(); out.close(); } catch (Exception e) { System.out.println("關(guān)閉流異常," + e.getMessage()); } } public static Date str2Date(String dateString) { try { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Date date = sdf.parse(dateString); return date; } catch (Exception e) { e.printStackTrace(); } return null; } }
寫個(gè)簡單的類測試一下
1、如果不需要展示List對(duì)象的數(shù)據(jù),可以存一個(gè)空數(shù)組到Map,本文為例,家屬信息為列表對(duì)象
import java.math.BigDecimal; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class TestMain { public static void main(String[] args) { //相對(duì)路徑 模板文件、輸出文件 String templateFile = "file/temp.ftl"; String outFileName = "file/test.xls"; Map<String, Object> dataMap = test01(); // Map<String, Object> dataMap = test02(); try { ExcelUtil.doGenerateFile(dataMap, templateFile, outFileName); } catch (Exception e) { System.out.println("處理異常," + e.getMessage()); } } private static Map<String, Object> test01() { Map<String, Object> dataMap = new HashMap<>(); BigDecimal baseRow = new BigDecimal(6); dataMap.put("name", "張三"); dataMap.put("sex", "男"); dataMap.put("birth", ExcelUtil.str2Date("1990-01-10")); dataMap.put("certType", "A"); dataMap.put("address", "地址詳情"); dataMap.put("tel", "110110"); //放入一個(gè)空數(shù)組的參數(shù)避免合成的時(shí)候報(bào)錯(cuò) List<Map<String, Object>> list = new ArrayList<>(); dataMap.put("spouseInfos", list); dataMap.put("totalRowCount", baseRow); return dataMap; } private static Map<String, Object> test02() { Map<String, Object> dataMap = new HashMap<>(); BigDecimal baseRow = new BigDecimal(6); dataMap.put("name", "張三"); dataMap.put("sex", "男"); dataMap.put("birth", ExcelUtil.str2Date("1990-01-10")); dataMap.put("certType", "A"); dataMap.put("address", "地址詳情"); dataMap.put("tel", "110110"); List<Map<String, Object>> list = new ArrayList<>(); Map<String, Object> s1 = new HashMap<>(); s1.put("name", "李四"); s1.put("relation", "夫妻"); s1.put("tel", "112112"); list.add(s1); dataMap.put("spouseInfos", list); //計(jì)算展示行數(shù) BigDecimal subtract = baseRow.add(new BigDecimal(3)); dataMap.put("totalRowCount", subtract); return dataMap; } }
使用test01數(shù)據(jù)效果如圖
使用test02數(shù)據(jù)效果如圖
到此這篇關(guān)于java freemarker實(shí)現(xiàn)動(dòng)態(tài)生成excel文件的文章就介紹到這了,更多相關(guān)java freemarker生成excel內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于Java實(shí)現(xiàn)HttpServer模擬前端接口調(diào)用
這篇文章主要介紹了關(guān)于Java實(shí)現(xiàn)Http?Server模擬前端接口調(diào)用,Http?協(xié)議是建立在?TCP?協(xié)議之上的協(xié)議,所以能用?TCP?來自己模擬一個(gè)簡單的?Http?Server?當(dāng)然是可以的,需要的朋友可以參考下2023-04-04淺析我對(duì) String、StringBuilder、StringBuffer 的理解
StringBuilder、StringBuffer 和 String 一樣,都是用于存儲(chǔ)字符串的。這篇文章談?wù)勑【帉?duì)String、StringBuilder、StringBuffer 的理解,感興趣的朋友跟隨小編一起看看吧2020-05-05java用split分割字符串的一個(gè)有趣現(xiàn)象
最近在項(xiàng)目中使用了java中的split分割字符串,發(fā)現(xiàn)了一個(gè)bug,充分了展示了自己對(duì)java底層的認(rèn)知有很多的不足和欠缺。下面將這次的經(jīng)過總結(jié)出來分享給大家,有需要的朋友們可以參考借鑒,下面來一起看看吧。2016-12-12java實(shí)現(xiàn)網(wǎng)站微信掃碼支付
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)網(wǎng)站微信掃碼支付,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07SpringBoot集成分頁插件PageHelper的配置和使用過程
這篇文章主要介紹了SpringBoot集成分頁插件PageHelper的配置和使用過程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04Java Applet查找素?cái)?shù)小程序代碼實(shí)例
這篇文章主要介紹了Java Applet查找素?cái)?shù)小程序代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02詳解Java?redis中緩存穿透?緩存擊穿?雪崩三種現(xiàn)象以及解決方法
緩存穿透是指緩存和數(shù)據(jù)庫中都沒有的數(shù)據(jù),而用戶不斷發(fā)起請求,如發(fā)起為id為“-1”的數(shù)據(jù)或id為特別大不存在的數(shù)據(jù)。這時(shí)的用戶很可能是攻擊者,攻擊會(huì)導(dǎo)致數(shù)據(jù)庫壓力過大2022-01-01