以前接触过一个很古老的导出Excel,实现的逻辑是先声明一个导出的Excel模板,模板里报表的表头名称和顺序是固定的,这样执行导出时,系统是先读取手动创建的Excel模板文件,然后就往里面set查询结果值,最近因需要,写了一个可以根据表头信息自动导出Excel报表文件的方法,思路是把表头信息和表格数据进行分开2次写入,接下来分开讲解下思路,并贴上部分代码供大家参考。
首先,因为这种导出函数是可复用的,根据也无需要会导出不同的excel文件,里面数据不同,所以我们不能先声明Excel模板,只能通过POI里的Workbook类动态新建空白的excel模板,至于workbook具体的实现类,就要看你想导出03 还是07版excel了。
表格表头导出
单行表头
单行表头导出直接把获取的表头信息按照顺序输出就可以了,这里就不做特殊说明了。
多行表头
重点来了,多行表头动态导出难点是表头的行合并和列合并,这个能通过递归分析出来,分析出表头的行合并和列合并信息后就可以根据这些信息推导出每个表头信息在excel表格中所在的坐标以及单元格合并样式,剩下的就是根据这些信息进行写入workbook了。
下面是我的代码实现,只截取了部分仅供参考:
1.声明excel表格节点类 和 表头标题类
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
/**
* 导出表头节点信息
* @author wr
*/
@Setter
@Getter
@ToString
public class HeaderNodeVo implements Serializable {
private static final long serialVersionUID = 6243427059921159767L;
/**
* 行号
*/
private Integer rowStart;
/**
* 行号
*/
private Integer rowEnd;
/**
* 列号
*/
private Integer colStart;
/**
* 列号
*/
private Integer colEnd;
/**
* 层级
*/
private Integer level;
/**
* 标题名称
*/
private String name;
/**
* 对应的字段别名
*/
private String prop;
/**
* 节点ID
*/
private String id;
/**
* 节点父ID
*/
private String parentId;
/**
* 子节点数量
*/
private Integer sonNum;
}
public class TargetTitleVo {
/**
* 指标ID列表
*/
private List<String> targetIds;
/**
* 标题ID
*/
private String titleId;
/**
* 标题
*/
private String value;
/**
* 对应数据集的字段名称
* 最后一级标题以外为空
*/
private String prop;
/**
* 排序
*/
private Integer sort;
/**
* 子标题
*/
private List<TargetTitleVo> children;
/**
* 上级titleId
*/
private String parentId;
/**
* 该标题下叶子总数
*/
private int nodeCount;
}
2.获取表头字段名信息(这里要根据你们本地工程动态调整)
List<TargetTitleVo> titleVos = reportDataDao.getTitles();
3.初始化标题信息并组装HeaderNodeVo 类基本信息
/**
* 初始化标题信息
* @param titleVos 标题vo集合
* @param list 表头层级集合
* @param level 表头开始层级号
* @param nodes 表头节点集合
*/
private void initTitleInfo(List<TargetTitleVo> titleVos, List<Integer> list, Integer level, List<HeaderNodeVo> nodes){
if(!CollectionUtils.isEmpty(titleVos)){
//no
for(TargetTitleVo vo : titleVos){
list.add(level);
//初始化节点
HeaderNodeVo node = this.initNode(vo, level);
nodes.add(node);
if(hasChild(vo)){
//含有子项
initTitleInfo(vo.getChildren(),list,level+1,nodes);
}
}
}
}
/**
* 判断标题是否有子项
* @param vo 维度标题vo
* @return boolean
*/
private boolean hasChild(TargetTitleVo vo){
boolean result = false;
if(vo!=null){
List<TargetTitleVo> children = vo.getChildren();
if(children!=null &&children.size() >0){
result = true;
}
}
return result;
}
/**
* 初始化节点
* @param vo 指标vo
* @param level 表头层数
* @return 表头节点
*/
private HeaderNodeVo initNode(TargetTitleVo vo, Integer level){
HeaderNodeVo result = new HeaderNodeVo();
//节点id
result.setId(vo.getTitleId());
//节点名称
result.setName(vo.getValue()</