使用Jxls1.0导出Excel文件
Jxls2admin 发布于:2017-08-08 16:57:23
阅读:loading
很早很早就想写这么一篇文章了,但是觉得太简单了,就一直没写,直到昨天一个紧急的功能调整用到了此功能中的某项,由于时间太长记不大清楚了,随补上。在实现一些小型数据报表的时候,jxls是一个非常方便的实现方案,如果你还不了解,那正好就跟着我来熟悉一下吧。有人说我直接就用POI就可以实现,实际上jxls就是在poi的基础之上做的封装,它采用Excel模板的方式实现,配合el表达式来处理逻辑,也就是说我们的报表实现是基于事先创建一个最终效果的模板文件,在模板的基础上按照el规范去填充数据,最终显示效果。
基本模板实现,Excel的报表易于维护
如果想修改某个单元格的显示样式,比如文本颜色、背景颜色、文本各种显示位置、边框、字体大小、千分位显示、百分百显示等等,都可以只需要修改模板,而不需要调整后台代码,也就省去了升级部署的一些问题。
API调用简单,表达式规范学习成本较低
生成报表时的API比较简单,传递数据集、模板文件、输出目录等参数即可,采用el表达式规范处理数据逻辑,可以不用在后台处理数据,比如本例中要实现的数据列表使用<jx:forEach items="${dataList}" var="item" varStatus="in" >和<jx:if test="${in.index % 2 == 0}">标签实现,分别为循环、判断标签,与jstl中的c标签用法完全一致。同样可以数据循环嵌套,依赖由后台的数据结构。
部分Excel自带的功能可用
以本例来说,虚拟了用户的一些数据,其中有个工资字段,将所有工资大于10000的数据格子文本显示红色、背景显示黄色,我们就不用后台那么复杂的去实现,只需要使用Excel自带的条件格式实现即可,功能丰富强大。
Excel自带计算公式使用
在使用公式时有两种情况使用到得最多,1、单元格值为某个属性乘以某个数字(某个属性乘以某个属性);2、单元格值为引用了一些格子的公式 ,如: 格子A + 格子B + 格子C,其中各个格子也都可以自带其它的公式,支持数据循环的公式模式。统计汇总的公式引用等,打开生成的报表文件,其中的单元格是包含有公式的。
适合小型数据量的报表
由于是采用后台数据填充的模式,所以对于大数据量时的处理就会略显鸡肋。
适合数据报表,对于图形化报表模板略显鸡肋
1、对于下拉列表的样式循环,采用模板时发现下拉框并未跟着数据循环,参考如下图:
2、单元格合并未找到如何处理;
3、某些时候发现一些单元格的公式未自动执行;
4、如果某些格子想使用excel自带的金额、数字格子类的公式或样式时,后台返回的属性又为文本,此时可使用让该文本*1的方式进行类型转换;
使用jxls的API填充完数据后,可以返回POI的Workbook对象,所有的处理如:单元格的下拉列表、合并单元格等需要二次使用。
表头样式(加粗、居中、表格宽高)、隔行换色、汇总、基于数字的单元格公式计算、基于单元格引用的公式计算、条件格式等。参考模板图片为:
/**
*
*/
package cn.chendd.example.vo;
/**
* 用户信息
* @author chendd
*/
public class User {
private Integer id;// id
private String name;// 姓名
private Double salary;// 工资(元),大于10000的标绿色,大于20000的标红色
private Double rate;// 税率
public User() {
super();
}
public User(Integer id, String name, Double salary,Double rate) {
super();
this.id = id;
this.name = name;
this.salary = salary;
this.rate = rate;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
public Double getRate() {
return rate;
}
public void setRate(Double rate) {
this.rate = rate;
}
}
package cn.chendd.example;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.sf.jxls.transformer.XLSTransformer;
import cn.chendd.example.vo.User;
public class Test {
public static void main(String[] args) throws Exception {
String srcFilePath = Test.class.getResource("user.xlsx").getPath();
String destFilePath = "d:\\tt\\员工.xlsx";
List<User> dataList = getDataList();
Map<String, Object> dataAll = new HashMap<String, Object>();
dataAll.put("dataList", dataList);
XLSTransformer transformer = new XLSTransformer();
transformer.transformXLS(srcFilePath, dataAll, destFilePath);
System.out.println("Test.main()");
}
private static List<User> getDataList() {
List<User> dataList = new ArrayList<User>();
dataList.add(new User(101, "曹*", 8000D, 0.20D, 0D));
dataList.add(new User(102, "曹昂", 12000D, 0.25D, 0D));
dataList.add(new User(103, "曹丕", 23000D, 0.40D, 0D));
dataList.add(new User(104, "曹植", 36000D, 0.50D, 0D));
dataList.add(new User(105, "曹冲", 7500D, 0.20D, 0D));
dataList.add(new User(106, "曹仁", 8000D, 0.20D, 0D));
dataList.add(new User(107, "曹彰", 8000D, 0.20D, 0D));
dataList.add(new User(108, "曹髦", 8000D, 0.20D, 0D));
dataList.add(new User(109, "曹休", 8000D, 0.20D, 0D));
dataList.add(new User(110, "小鬼", 8000D, 0.20D, 0D));
return dataList;
}
}
commons-beanutils-1.8.2.jar
commons-collections-3.2.1.jar
commons-digester-2.0.jar
commons-jexl-2.0.1.jar
commons-logging-1.1.1.jar
dom4j-1.6.1.jar
jxls-core-1.0.6.jar
poi-3.9.jar
poi-ooxml-3.9.jar
poi-ooxml-schemas-3.9.jar
xml-apis-1.0.b2.jar
xmlbeans-2.3.0.jar
之前在找jxls的时候有新版2.0了,稍微看了一下是基于备注来实现的,感觉好复杂,也没怎么深入。
@20180308 补充
突然想起来了就在补充一下,
1、使用jxls做多sheet导出时与单个sheet一样,把标签写在其它sheet里面即可。
2、在循环嵌套时,与jstl的循环嵌套类似,有varStatus属性;
3、jxls的标签较少,可以在打开jxls-core-1.0.xxx.jar中的net.sf.jxls.tag.JxTaglib类中查看,总共只是有4个标签类,也可以在jxls-core-1.0-rc-2-sources.jar中的同级目录的jx-core.xml中印证;
4、有一些表格循环行高的问题等,如果在xlsx中出现了,不妨将xlsx转换为xls试试;
5、除了上文中提到的下拉框,还有一些图片导出、超链接导出、更改sheet名称、循环数据的单元格合并等等,如果实现不了,在jxls导出excel后,使用poi进行二次处理;
6、数字金额类型转换的问题,有时候在后台返回的字符串类型的数字,实际上你想要的是数字,而excel会在格子的左上角给显示一个绿色的小三角,此时的两种解决办法,
①在后台将数字字符串转换为数字类型;
②在${item.name}处添加数字的计算,比如我们知道一个数在乘以1或者加上0之后还是等于它本身,即${item.name*1},excel会将这只字符串转换成数字类型;
@20180611 补充
有个List类型在返回数据集中不存在报错的问题
假如模板中存在一个对List集合循环显示的表格,但是Java后台又由于某些逻辑而又没给模板中参数集合绑定对应的参数,即对Map参数中不存在的变量进行循环,此时是会报错的,解决办法常规的有两种:
1、从Java后台判定,如果集合为空则进行new ArrayList给个empty集合数据;
2、模板中添加一个if判断标签,即满足条件时才执行forEach循环语句,参见判断的写法为 {not empty dataList},一定是使用 not empty 去判断,不能直接s还有 == null 之类的判断,因为这样的判断会使用String类型的判断,而非集合类型的判断。
@20180829 补充
补充一下标签的相关:
1、循环标签,js:forEach,有varStatus属性,可获取下标实现第一次循环或最后一次循环的逻辑等;
2、判断标签,js:if,字符串判断<js:if test="item.prop == 'value'">;当判断集合是否为空时使用not empty的方式判断(同jstl);
点赞