注:本文代碼創建於前面寫的代碼。不過不看也沒關係。java
前面的文章把JXLS 2.4.0 的基本使用寫了一遍,如今講講一些更進一步的使用方法。我只寫一些我用到過的方法,更多的高級使用方法請參考官網。數據庫
http://jxls.sourceforge.net/網絡
1、Map的應用dom
從一開始,官方dome使用的model中的引用對象一直都是一個javaBean對象。後來我發現其實能夠直接往model中放一個map,而後也是直接用「點」的方式在excel中取出數據。函數
下面用第四篇文章——多sheet的源碼作演示,咱們先修改main方法,加入一個HashMapMap:工具
public static void main(String[] args) throws Exception { // 模板位置,輸出流 String templatePath = "E:/template5_2.xls"; OutputStream os = new FileOutputStream("E:/out5_2.xls"); List<Student> list = generateData(); // 模擬數據庫獲取數據 //List<Page> page = DataByPage.byPage(list); // 把獲取的數據進行分頁轉換 List<Page> page = individual(list); // 一頁一我的 // 定義一個Map Map<String, String> tableInfo = new HashMap<String, String>(); tableInfo.put("className", "六年三班2"); tableInfo.put("teacherComment", "已覈實2"); tableInfo.put("directorComment", "已覈實2"); Map<String, Object> model = new HashMap<String, Object>(); model.put("pages", page); model.put("sheetNames", getSheetName(page)); model.put("tableInfo", tableInfo); //model.put("className", "六年三班"); //model.put("teacherComment", "已覈實"); //model.put("directorComment", "已覈實"); JxlsUtils.exportExcel(templatePath, os, model); os.close(); // 刪除多出來的sheet DelSheet.deleteSheet("E:/out5_2.xls", "template"); System.out.println("完成"); }
把原來的model中put的多註釋掉,而後把定義的Map tableInfo 放入model中。lua
咱們看看模板中怎麼取:spa
直接取新加入的map的鍵名,再「點上」tableInfo的鍵名。.net
就這樣輕鬆的取出來了。Map也是能夠直接放進model中的,有時候Map用起來更加靈活,這就要自行選擇了。excel
2、使用工具
工具的使用先看JxlsUtils類。
public class JxlsUtils{ public static void exportExcel(InputStream is, OutputStream os, Map<String, Object> model) throws IOException{ Context context = PoiTransformer.createInitialContext(); if (model != null) { for (String key : model.keySet()) { context.putVar(key, model.get(key)); } } JxlsHelper jxlsHelper = JxlsHelper.getInstance(); Transformer transformer = jxlsHelper.createTransformer(is, os); //得到配置 JexlExpressionEvaluator evaluator = (JexlExpressionEvaluator)transformer.getTransformationConfig().getExpressionEvaluator(); //設置靜默模式,不報警告 evaluator.getJexlEngine().setSilent(true); //函數強制,自定義功能 Map<String, Object> funcs = new HashMap<String, Object>(); funcs.put("utils", new JxlsUtils()); //添加自定義功能 evaluator.getJexlEngine().setFunctions(funcs); //必需要這個,否者表格函數統計會錯亂 jxlsHelper.setUseFastFormulaProcessor(false).processTemplate(context, transformer); } public static void exportExcel(File xls, File out, Map<String, Object> model) throws FileNotFoundException, IOException { exportExcel(new FileInputStream(xls), new FileOutputStream(out), model); } public static void exportExcel(String templatePath, OutputStream os, Map<String, Object> model) throws Exception { File template = getTemplate(templatePath); if(template != null){ exportExcel(new FileInputStream(template), os, model); } else { throw new Exception("Excel 模板未找到。"); } } //獲取jxls模版文件 public static File getTemplate(String path){ File template = new File(path); if(template.exists()){ return template; } return null; } // 日期格式化 public String dateFmt(Date date, String fmt) { if (date == null) { return ""; } try { SimpleDateFormat dateFmt = new SimpleDateFormat(fmt); return dateFmt.format(date); } catch (Exception e) { e.printStackTrace(); } return ""; } // if判斷 public Object ifelse(boolean b, Object o1, Object o2) { return b ? o1 : o2; } }
咱們看到有一行:funcs.put("utils", new JxlsUtils()); //添加自定義功能
//函數強制,自定義功能 Map<String, Object> funcs = new HashMap<String, Object>(); funcs.put("utils", new JxlsUtils()); //添加自定義功能 evaluator.getJexlEngine().setFunctions(funcs);
這行代碼的意思就是設置一個工具類JxlsUtils(),在excel中的引用爲utils 。當你在excel中使用 utils 時就會調用JxlsUtils() 類(能夠是其餘的類)的對應方法。
咱們來看下模板怎麼寫:
在模板中,你能夠這樣調用工具類:
${utils:ifelse(page.currentPage == page.tolalPage,"最後一頁","")}
JXLS會自動找到utils這個鍵對應的值 new JxlsUtils() ,而後在JxlsUtils類中找對應的ifelse方法,而後根據方法接收的參數自動把你在excel寫的參數傳進去,再把方法的返回值顯示在excel中。
還記得我前面保存進Page中的當前頁碼和總頁碼這兩個屬性嗎?如今就是使用使用他們了。用他們能夠判斷如今的sheet是否是最後一頁,最後一頁能夠顯示一些別的數據。通常說ifelse這個已經夠用了,可是若是你有更加複雜的操做,你也能夠自行定製本身須要的工具類。
3、JXLS 是支持模板多個sheet輸出數據的
這句話很奇怪,可是我一會兒沒想出別的表達。這個多sheet不是前面咱們講的分sheet,是說你模板有自己就已經有不少個sheet了,每一個sheet顯示的表都不同,不用擔憂,你存放進model中的數據是能夠跨sheet的。只要你想取出就能取出,這個我就不演示了。
4、頁面邊距bug
這個bug通常人是真沒有發現的,可是對我來講就是差點要了老命....咱們公司項目導出的excel報表比較大,一張A3紙都只是勉勉強強夠打印。因此日常邊距要設定得很小,這個邊距的bug就是你在模板中設定的頁面邊距並不會拷貝進你導出的文件的。
你可能試驗了一下說,沒有啊,個人沒問題啊。我說的不會拷貝僅是在分頁分sheet導出時候出現的問題。我舉個例子,你在模板中設定了頁面邊距,而後導出,JXLS會先把你的模板複製進導出的文件中,而後創建一個新的sheet,而後在根據模板的設定把內容拷貝進新sheet中,而後再創建新sheet不斷循環。
問題就出如今把模板拷進新sheet的過程當中,若是你改變了模板的頁面邊距,再進行一個分sheet導出,不要用POi刪除導出文件第一頁空的模板sheet,你查看第一頁的頁邊距你發現是已經修改過的頁邊距,而你查看後面其餘sheet的頁邊距就會是excel默認的頁邊距了。
不明白沒關係,你只要知道我已經解決了就好(新版本2.4.2我不知道做者有沒有修復)。
問題就出如今這個PoiUtil的文件上,咱們打開看看,看到copySheetProperties(Sheet src, Sheet dest)這個方法,這個方法就是拷貝sheet屬性的。
public static void copySheetProperties(Sheet src, Sheet dest){ dest.setAutobreaks(src.getAutobreaks()); dest.setDisplayGridlines(src.isDisplayGridlines()); dest.setVerticallyCenter(src.getVerticallyCenter()); dest.setFitToPage(src.getFitToPage()); dest.setForceFormulaRecalculation(src.getForceFormulaRecalculation()); dest.setRowSumsRight(src.getRowSumsRight()); dest.setRowSumsBelow( src.getRowSumsBelow() ); //增長頁邊距保存 dest.setMargin(Sheet.TopMargin, src.getMargin(Sheet.TopMargin)); dest.setMargin(Sheet.LeftMargin, src.getMargin(Sheet.LeftMargin)); dest.setMargin(Sheet.RightMargin, src.getMargin(Sheet.RightMargin)); dest.setMargin(Sheet.BottomMargin, src.getMargin(Sheet.BottomMargin)); copyPrintSetup(src, dest); }
這個方法內少寫了對sheet頁邊距的拷貝,加上就行。加上後怎麼放回包裏?你能夠自行打包....你也能夠在你的項目目錄上創建一個與PoiUtil類如出一轍的路徑,而後在裏面放上修改後的類。Java在找包時候會優先找你寫的路徑,這樣就覆蓋掉了包路徑了。
在src的根目錄上,和com同級。
好了,這一篇文章就寫到這裏,寫這篇文章時候我是懶的,我懶得再去作案例驗證了,特別是最後的那個頁邊距的bug,我在當初我在網絡上根本找不到和我同樣的問題。我也是花了些功夫才找到這個緣由的。原本我應該作下案例把這個bug講清楚些,可是我寫到這裏我已經有些懶了.....說白了這個bug就是隻有在分sheet導出時候纔會出現的問題,能本身復現的就本身研究下,不能的,知道怎麼解決了就好了。
下載PoiUtil類: 點這裏下載