注:本文代码建立于前面写的代码。不过不看也不要紧。

  前面的文章把JXLS 2.4.0 的基本使用写了一遍,现在讲讲一些更进一步的使用方法。我只写一些我用到过的方法,更多的高级使用方法请参考官网。

  http://jxls.sourceforge.net/

一、Map的应用

  从一开始,官方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中。

  我们看看模板中怎么取:

  直接取新加入的map的键名,再“点上”tableInfo的键名。

  就这样轻松的取出来了。Map也是可以直接放进model中的,有时候Map用起来更加灵活,这就要自行选择了。

二、使用工具

  工具的使用先看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这个已经够用了,但是如果你有更加复杂的操作,你也可以自行定制自己需要的工具类。

三、JXLS 是支持模板多个sheet输出数据的

  这句话很奇怪,但是我一下子没想出别的表达。这个多sheet不是前面我们讲的分sheet,是说你模板有本身就已经有很多个sheet了,每个sheet显示的表都不一样,不用担心,你存放进model中的数据是可以跨sheet的。只要你想取出就能取出,这个我就不演示了。

四、页面边距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类: 点这里下载

JXLS 2.4.0系列教程(五)——更进一步的应用和页面边距bug修复的更多相关文章

  1. JXLS 2.4.0系列教程(二)——循环导出一个链表的数据

    请务必先看上一篇文章,本文在上一篇文章的代码基础上修改而成. JXLS 2.4.0系列教程(一)--最简单的模板导出 上一篇文章我们介绍了JXLS和模板导出最简单的应用,现在我们要更进一步,介绍在模板 ...

  2. 黄聪:Microsoft Enterprise Library 5.0 系列教程(五) Data Access Application Block

    原文:黄聪:Microsoft Enterprise Library 5.0 系列教程(五) Data Access Application Block 企业库数据库访问模块通过抽象工厂模式,允许用户 ...

  3. JXLS 2.4.0系列教程(一)——最简单的模板导出

    Java中实现excel根据模板导出数据的方法有很多,一般简单的可以通过操作POI进行.还可以使用一些工具很轻松的实现模板导出.这些工具现在还在维护,而且做得比较好的国内的有easyPOI,国外的就是 ...

  4. JXLS 2.4.0系列教程(六)番外篇——导出图片(完结)

    突然想起来有同学说过能不能导出图片,本来我是想说不懂的,后来我上官网查了查,还挺容易.我就简短的写一写怎么导出图片. 官方提供了导出图片标签: jx:image(lastCell="D10& ...

  5. JXLS 2.4.0系列教程(四)——多sheet是怎么做到的

    注:本文代码在第一篇文章基础上修改而成,请务必先阅读第一篇文章. http://www.cnblogs.com/foxlee1024/p/7616987.html 本文也不会过多的讲解模板中遍历表达式 ...

  6. JXLS 2.4.0系列教程(四)——拾遗 如何做页面小计

    注:阅读本文前,请先阅读第四篇文章. http://www.cnblogs.com/foxlee1024/p/7619845.html 前面写了第四篇教程,发现有些东西忘了讲了,这里补回来. 忘了讲两 ...

  7. JXLS 2.4.0系列教程(三)——嵌套循环是怎么做到的

    注:本文代码在第一篇文章基础上修改而成,请务必先阅读第一篇文章. http://www.cnblogs.com/foxlee1024/p/7616987.html 本文也不会过多的讲解模板中遍历表达式 ...

  8. Enterprise Library 5.0 系列教程

    1. Microsoft Enterprise Library 5.0 系列教程(一) Caching Application Block (初级) 2. Microsoft Enterprise L ...

  9. Android Studio系列教程五--Gradle命令详解与导入第三方包

    Android Studio系列教程五--Gradle命令详解与导入第三方包 2015 年 01 月 05 日 DevTools 本文为个人原创,欢迎转载,但请务必在明显位置注明出处!http://s ...

随机推荐

  1. Missing number in array

    Given an array of size n-1 and given that there are numbers from 1 to n with one missing, the missin ...

  2. 理解new构造函数和apply以及call

    今天在看设计模式的时候,遇到一些挺低级的东西,搞不懂,顾查阅资料整理记录一番. 先了解一下new构造函数的过程: function func(){ console.log('do'); } var f ...

  3. 为什么硬链接不能链接目录、文件inode 和目录 dentry 的区别联系

    我们对任何一个目录用ls -l 命令都可以看到其连接数至少是2,这也说明了系统中是存在硬连接的,而且命令ln -d 也可以让超级用户对目录作硬连接,这些都说明了系统限制对目录进行硬连接只是一个硬性规定 ...

  4. jquery获取焦点和失去焦点事件代码

    input失去焦点和获得焦点 鼠标在搜索框中点击的时候里面的文字就消失了. 我们在做网站的时候经常会用到搜索框的获得焦点和失去焦点的事件,因为懒,每次都去写非常的烦,于是就一劳永逸,遇到类似情况就来调 ...

  5. php+中文分词scws+sphinx+mysql打造千万级数据全文搜索

    转载自:http://blog.csdn.net/nuli888/article/details/51892776 Sphinx是由俄罗斯人Andrew Aksyonoff开发的一个全文检索引擎.意图 ...

  6. Elasticsearch5.4常见问题总结

    最近项目中用到了Elasticsearch5.4(ES)是比较新的一个版本,使用的过程中出现了很多的问题,很是头疼,但是问题最终还是解决掉了. 问题一:ESClient获取慢,并且不能获取Client ...

  7. Keras:基于Theano和TensorFlow的深度学习库

    catalogue . 引言 . 一些基本概念 . Sequential模型 . 泛型模型 . 常用层 . 卷积层 . 池化层 . 递归层Recurrent . 嵌入层 Embedding 1. 引言 ...

  8. golang 数组反转

    我做hackerearth上题目记录,具体的题目描述是这样的: Given the size and the elements of array A, print all the elements i ...

  9. Python正则表达式返回首次匹配到的字符及查询的健壮性

    re.findall(pattern,string)会搜索所有匹配的字符,返回的是一个列表,获取首个匹配需要re.findall(pattern,string)[0]访问, 但是如果findall没匹 ...

  10. 【转2】Appium 1.6.3 在Xcode 8 (真机)测试环境搭建 经验总结

    Appium 1.6.3 在Xcode 8 (真机)测试环境搭建经验总结 关于 Appium 1.6.3 在Xcode 8, 1真机上环境搭建问题更多,写此文章,供大家参考,让大家少走弯路. 在开始i ...