注:本文代码创建于前面写的代码。不过不看也没关系。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类: 点这里下载