poi实现对树形结构数据导出excel并合并表格

article/2025/8/21 21:52:05

poi实现对树形结构数据导出excel并合并表格

  • 1.主要逻辑!
  • 2.完整代码

最近好像得罪了poi,遇到的都是导出word、Excel、pdf的问题。下面我记录一下poi对树形结构的处理,前面先梳理整体思路,文章末尾会贴上完整代码。
首先我们看一下模板和效果图吧:

在这里插入图片描述

在这里插入图片描述
怎么样,效果还行吧,有没有达到你心目中的标准?如果你也遇到了这样的问题,那么请静下心来花费几分钟时间,我会详细的梳理出自己的思路,希望能够帮助到你。

1.主要逻辑!

1.首先,我们来看一下树形结构的数据、正如效果图一样,我这里处理的是一个三层结构。

---- 祖先节点(包含祖先节点id,祖先节点name,children,total(当前对象的第三级子节点的数量))
  ---父亲节点(包含祖先节点id,祖先节点name,本身的id,本身的name,children)
     ----子节点(包含上面两个祖先的数据和自己本身的数据,无children)
数据是提前处理好了的,在代码里的体现就是一个集合List ,StatisticsByPartVo是一个java bean对象,是个树形结构。
2.因为涉及到表格的合并,我再提一下关键的代码

sheet0.addMergedRegion(new CellRangeAddress(Parma1,Parma2,Parma3,Parma4));

四个参数分别表示
Parma1:要合并的开始行
Parma2:要合并的结束行
Parma3:要合并的开始列
Parma4:要合并的结束列
举个例子,因为坐标都是从(0,0)开始的,我要合并三行四列,参数就是(2,2,3,3)

现在开始整理一下整体思路:循环整个list集合,用HSSFRow 来创建行,用HSSFCell来创建一行的一个元素,在循环的过程中,将需要合并的数据的坐标,单独用一个List<Map<String,String>>stepList 保存起来,Map里面的数据就是坐标的四个Parma,循环完数据之后,再单独循环坐标集合,统一调用上面的一行代码搞定合并,(记得合并是最后来做的事情)
怕一段文字太多影响你们阅读,我上面说的是总体思路,下面我再简单说一下针对我这个demo和数据的逻辑。
1.循环整个list,得到当前对象StatisticsByPartVo,取到StatisticsByPartVo的total,根据total的值和当前rowNum的值,来为第一级添加坐标,我代码里添加了两次,因为序号也是跟第一级一起合并的。
2.循环当前对象StatisticsByPartVo的children,也是一个集合,得到当前对象secondChild,在循环secondChild的children,分别创建行列,在secondChild的children循环完毕后,为第二级添加坐标,代码的231行,其中注意rowNum和curNum等计数器的变化和位置,如果这个有错也会导致表格格式不对。
3.循环完之后,循环计步集合,合并表格,整体完毕

        for(Map<String,Integer>map:stepList){sheet0.addMergedRegion(new CellRangeAddress(map.get("startIndexRow"), map.get("endIndexRow"), map.get("startIndexCol"), map.get("endIndexCol")));}

以上就是我的整体思路,如果你也被这个问题困扰,不如跟着我的思路走一下,整体代码和逻辑都不复杂,如果我的文章能够帮助你解决掉问题,别吝啬你的小指头给作者点个赞哦。

下面贴上完整逻辑代码,关键地方已经打上注释,欢迎下方留言,有不对的地方欢迎指出。转载请附上原文链接。

2.完整代码

package cdcb.govpublic.base.entity;import cdcb.util.PropertiesUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** @author wq* @date 2020/4/2.*/
public class StatisticsByPartView {public StatisticsByPartView() {}public static void buildExcelDocument(Map<String, Object> mode, HttpServletRequest request, HttpServletResponse response,String year) throws Exception {String path = PropertiesUtils.getValueByKey("excelPath", request.getServletContext().getRealPath("/"));String excelModelPath = path + "static/template/listByPart.xls";File excel = new File(excelModelPath);FileInputStream is = new FileInputStream(excel);Workbook workbook = new HSSFWorkbook(is);is.close();String excelName = year+"年政府网各栏目数据报送情况汇总表";//这个方法就是主要创建逻辑方法setWorkBookValue(workbook, mode,excelName);String userAgent = request.getHeader("User-Agent");userAgent = userAgent == null ? "" : userAgent.toLowerCase();if (!userAgent.contains("msie") && !userAgent.contains("trident")) {excelName = new String(excelName.getBytes(), "iso-8859-1");} else {excelName = URLEncoder.encode(excelName, "UTF-8");}response.setContentType("application/octet-stream");response.setHeader("Content-disposition", "attachment;filename=\"" + excelName + ".xls\"");OutputStream ouputStream = response.getOutputStream();workbook.write(ouputStream);ouputStream.flush();ouputStream.close();}private static void setWorkBookValue(Workbook wbs, Map<String, Object> model,String excelName) {List<StatisticsByPartVo> list = (List)model.get("list");HSSFCellStyle style = (HSSFCellStyle)wbs.createCellStyle();style.setVerticalAlignment((short)1);style.setAlignment((short)2);style.setWrapText(false);style.setBorderBottom((short)1);style.setBorderRight((short)1);style.setBorderTop((short)1);style.setBorderLeft((short)1);//这里设置style2的目的是给下面的循环做判断,如果数据为零则加粗标红HSSFCellStyle style2 = (HSSFCellStyle) wbs.createCellStyle();style2.setVerticalAlignment((short) 1);style2.setAlignment((short) 2);style2.setWrapText(false);style2.setBorderBottom((short) 1);style2.setBorderRight((short) 1);style2.setBorderTop((short) 1);style2.setBorderLeft((short) 1);Font ztFont = wbs.createFont();ztFont.setColor(Font.COLOR_RED);ztFont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);style2.setFont(ztFont);//创建工作簿HSSFSheet sheet0 = (HSSFSheet)wbs.getSheetAt(0);//记录步数的集合List<Map<String,Integer>>stepList = new ArrayList<>();//下面几行是为了替换模板第一行标题的文字HSSFRow headRow = sheet0.getRow(0);HSSFCell headCell = headRow.getCell(0);headCell.setCellValue(excelName);sheet0.createFreezePane(0,3,0,3);//因为模板的起始行是第三行,所以这里定义为3int rowNum = 3;for(int i = 0; i < list.size(); ++i) {Map<String,Integer>map2 = new HashMap<>();Map<String,Integer>map3 = new HashMap<>();StatisticsByPartVo vo = list.get(i);//为当前对象的第一级和序号列添加步数if(vo.getTotal()>1){map2.put("startIndexRow",rowNum);map2.put("endIndexRow",vo.getTotal()+rowNum-1);map2.put("startIndexCol",0);map2.put("endIndexCol",0);map3.put("startIndexRow",rowNum);map3.put("endIndexRow",vo.getTotal()+rowNum-1);map3.put("startIndexCol",1);map3.put("endIndexCol",1);stepList.add(map2);stepList.add(map3);}//循环第二级int curNum = rowNum;for(int k=0;k<vo.getChildren().size();k++){StatisticsByPartVo secondChild = vo.getChildren().get(k);Map<String,Integer>map4 = new HashMap<>();//创建第二级和第三级for (int j = 0; j < secondChild.getChildren().size(); j++) {StatisticsByPartVo third = secondChild.getChildren().get(j);HSSFRow rowi = sheet0.createRow(curNum +j);HSSFCell col0 = rowi.createCell(0);col0.setCellStyle(style);HSSFCell col1 = rowi.createCell(1);col1.setCellStyle(style);//创建第一级的数据,下面判断原因:因为要合并,合并内容的数据只需要创建一次就好,其他的为空if(j==0){col1.setCellValue(vo.getFirstName());col0.setCellValue((double)(i + 1));}else{col1.setCellValue("");col0.setCellValue("");}//创建第二级的数据HSSFCell col2 = rowi.createCell(2);col2.setCellStyle(style);if(j == 0){col2.setCellValue(third.getSecondName());}else{col2.setCellValue("");}HSSFCell col3 = rowi.createCell(3);col3.setCellValue(third.getThirdName());col3.setCellStyle(style);//下面都是创建第三级的数据了HSSFCell col4 = rowi.createCell(4);col4.setCellValue(third.getMonth1());if(third.getMonth1() == 0){col4.setCellStyle(style2);}else{col4.setCellStyle(style);}HSSFCell col5 = rowi.createCell(5);col5.setCellValue(third.getMonth2());if(third.getMonth2() == 0){col5.setCellStyle(style2);}else{col5.setCellStyle(style);}HSSFCell col6 = rowi.createCell(6);col6.setCellValue(third.getMonth3());if(third.getMonth3() == 0){col6.setCellStyle(style2);}else{col6.setCellStyle(style);}HSSFCell col7 = rowi.createCell(7);col7.setCellValue(third.getMonth4());if(third.getMonth4() == 0){col7.setCellStyle(style2);}else{col7.setCellStyle(style);}HSSFCell col8 = rowi.createCell(8);col8.setCellValue(third.getMonth5());if(third.getMonth5() == 0){col8.setCellStyle(style2);}else{col8.setCellStyle(style);}HSSFCell col9 = rowi.createCell(9);col9.setCellValue(third.getMonth6());if(third.getMonth6() == 0){col9.setCellStyle(style2);}else{col9.setCellStyle(style);}HSSFCell col10 = rowi.createCell(10);col10.setCellValue(third.getMonth7());if(third.getMonth7() == 0){col10.setCellStyle(style2);}else{col10.setCellStyle(style);}HSSFCell col11 = rowi.createCell(11);col11.setCellValue(third.getMonth8());if(third.getMonth8() == 0){col11.setCellStyle(style2);}else{col11.setCellStyle(style);}HSSFCell col12 = rowi.createCell(12);col12.setCellValue(third.getMonth9());if(third.getMonth9() == 0){col12.setCellStyle(style2);}else{col12.setCellStyle(style);}HSSFCell col13 = rowi.createCell(13);col13.setCellValue(third.getMonth10());if(third.getMonth10() == 0){col13.setCellStyle(style2);}else{col13.setCellStyle(style);}HSSFCell col14 = rowi.createCell(14);col14.setCellValue(third.getMonth11());if(third.getMonth11() == 0){col14.setCellStyle(style2);}else{col14.setCellStyle(style);}HSSFCell col15 = rowi.createCell(15);col15.setCellValue(third.getMonth12());if(third.getMonth12() == 0){col15.setCellStyle(style2);}else{col15.setCellStyle(style);}HSSFCell col16 = rowi.createCell(16);col16.setCellValue(third.getTotal());if(third.getTotal() == 0){col16.setCellStyle(style2);}else{col16.setCellStyle(style);}}//记录第二级合并的步数if(secondChild.getChildren().size()>1){map4.put("startIndexRow",curNum);map4.put("endIndexRow",secondChild.getChildren().size()+curNum-1);map4.put("startIndexCol",2);map4.put("endIndexCol",2);stepList.add(map4);}curNum+=secondChild.getChildren().size();}rowNum += vo.getTotal();}//循环合并表格for(Map<String,Integer>map:stepList){sheet0.addMergedRegion(new CellRangeAddress(map.get("startIndexRow"), map.get("endIndexRow"), map.get("startIndexCol"), map.get("endIndexCol")));}}
}

http://chatgpt.dhexx.cn/article/piA12jjF.shtml

相关文章

【JAVA】读取excel导入数据库,形成树状结构

最近需要导入一个excel表格&#xff0c;存到数据库并以树状结构读取出来 下面两张图片是需要导入的excel Transactional(rollbackFor Exception.class)public String import(MultipartFile file, Integer projectId) throws Exception {//poi解析excelInputStream inputStrea…

html 树 excel,用Excel实现简易树状关系

引子 - Excel训练营 - 写在前面 树状图对大家来说并不陌生。 树状图&#xff0c;亦称树枝状图&#xff0c;其文绉绉的定义如下&#xff1a; 树形图是数据树的图形表示形式&#xff0c;以父子层次结构来组织对象。是枚举法的一种表达方式。 而excel能够在一定程度上实现比较简单…

JAVA对树状结构数据导出Excel自动合并同级内容代码

针对树形结构数据进行Excel导出并进行合并处理 针对树形结构数据的Excel导出的1 需求1 对象结构2 对数据进行树形结构数据组合并且进行计算工具类3 对数据库的数据进行处理(全文最重要的数据处理方法思路逻辑)4 递归查询 父节点信息5 对数据写入Excel,6 自动合并代码参考我的上…

1、简单的Excel地址导入与树状结构生成

2019独角兽企业重金招聘Python工程师标准>>> 一、地区表结构 DROP TABLE IF EXISTS pro_area; /*!40101 SET saved_cs_client character_set_client */; /*!40101 SET character_set_client utf8 */; CREATE TABLE pro_area (area_id bigint(30) NOT NULL AUT…

树状结构导出到excel表格

/**获取导出实例 */async getAllInstances(SlotId) {//SlotId 数据库词槽idlet result:any [] //导出的数据模块const allData await this.getSimpleInstance(SlotId)//allData根据数据库词槽ID查询到的树状结构数据let count 1//fn 是递归的函数let fn (data, objc,count)…

Excel树状数据绘制导出

//存放数据的二维集合&#xff0c;twoDimensional 中每个List是树状结构的一个分支的所有数据List<List<JSONObject>> twoDimensional new ArrayList<>();//创建对象XSSFWorkbook xwb new XSSFWorkbook();//创建工作表Sheet sheet xwb.createSheet("…

将excel树形结构的数据导入数据库

因为工作需要&#xff0c;用户需要将产品分类通过excel表格导入到数据库中&#xff0c;而产品分类又有一、二、三、四、五级分类。最终通过各种尝试终于实现了数据导入。因此记录下来。 一、excel模板数据结构和数据库表结构介绍 1、 待导入excel模板数据&#xff1a; 2、数据…

关于excel多层级(树形)数据结构,提取成树形结构数据并导出到数据库

在开发中遇到一个问题&#xff0c;就是有一张excel表中的数据时多层级的&#xff0c;不是普通一行一行的&#xff0c;而是&#xff0c;一行对应多行&#xff0c;多行之中的每一行在对应多行数据。形成树形结构&#xff1a; 如上图所示&#xff1a;我遇到的excel表的结构&#x…

使用excel插件treeplan构建决策树

Treeplan是一种构建决策树的很轻巧的excel插件&#xff0c;可以做出比较规范的决策树&#xff0c;并可以自动计算结果。下面以excel2003为例&#xff08;07也可正常使用&#xff09;介绍其使用方法。 一&#xff0e;加载treeplan插件 工具&#xff08;菜单&#xff09;——加载…

EXCEL(VBA)画树程序

看了好多Python写的画树&#xff0c;想看看在Excel里画个树行不行&#xff0c;于是乎花了点时间用VBA写了个&#xff0c;效果还不错&#xff0c;截个图给大家看看。 绿色固定配色版效果&#xff1a; 随机颜色版效果&#xff1a; 附上主代码 Sub test() 画树主程序 作者&#…

Java 树形结构数据生成导出excel文件

效果 用法 String jsonStr "{\"name\":\"aaa\",\"children\":[{\"name\":\"bbb\",\"children\":[{\"name\":\"eee\"},{\"name\":\"fff\",\"children\"…

python 根据树型结构生成指定格式的excel数据

数据 tree {a: {a1: [(a1a, 1)],a2: [(a2a, 1),(a2b, 2),]},b: {b1: [(b1b, 1)],b2: [(b2b, 1)]} }excel 数据格式 代码实现 import xlrd from xlutils.copy import copyold_excel xlrd.open_workbook(1.xls) new_excel copy(old_excel) ws new_excel.get_sheet(0)def wr…

人工智能-高等数学之导数篇

高等数学之导数篇 线性代数的学习基本就先告一个段落了&#xff0c;接着学最重要的微积分&#xff0c;高等数学里的重中之重&#xff0c;也是近代科学的发展利器&#xff0c;微积分主要包括包括极限、微分学、积分学及其应用&#xff0c;而微分学包括求导数的运算&#xff0c;…

机器学习之数学基础 一 .导数

简单的说,导数是曲线的斜率,是曲线变化快慢的反应. 2阶导数是斜率变化快慢的反应,反应曲线的凸凹性 例如:加速度的方向总是指向轨迹曲线凹的一侧. 导数(Derivative)是微积分学中重要的基础概念.一个函数在某一点的导数描述了这个函数在这一点附近的变化率.导数的本质是通过极…

【数值优化之范数与导数】

本文参考书籍《最优化计算方法》 这一部分会介绍一些最优化需要用到的基本数学概念。 目录 1 范数 1.1 向量范数 1.2 矩阵范数 1.3 矩阵内积 2 导数 2.1 梯度与海瑟矩阵 2.2 矩阵变量函数的导数 1 范数 1.1 向量范数 范数相当于是从向量空间到实数域的映射&#xff…

微积分——什么是导数

目录 1. “导数(derivative)”名称的由来 1.1 “derivative”的词源 1.2 “derivative”的数学意义来源 1.3 “derivative”中文翻译为“导数” 2. “导数(derivative)”的数学意义 1. “导数(derivative)”名称的由来 1.1 “derivative”的词源 作为名词&#xff0c;始于…

一阶导数

本文引用与百度百科。 简介 导数&#xff08;英语&#xff1a;Derivative&#xff09;是微积分学中重要的基础概念。一个函数在某一点的导数描述了这个函数在这一点附近的变化率。导数的本质是通过极限的概念对函数进行局部的线性逼近。当函数 f 的自变量在一点 x0 上产生一个…

AI笔记: 数学基础之方向导数的计算和梯度

方向导数 定理 若函数f(x,y,z)在点P(x,y,z)处可微&#xff0c;沿任意方向l的方向导数 ∂ f ∂ l ∂ f ∂ x c o s α ∂ f ∂ y c o s β ∂ f ∂ z c o s γ \frac{\partial f}{\partial l} \frac{\partial f}{\partial x} cos \alpha \frac{\partial f}{\partial y} c…

图像处理之_导数微分

1. 一阶导数应用&#xff1a;图像的梯度 1) 用途: 在图像处理中, 常用梯度求取图像的边缘, 这是一个很基础的应用. 下图为在OpenCV中使用cvSobel()函数的具体效果. 四张图分别为: 原图, 在x方向上的梯度, y方向上的梯度, xy方向上的梯度. 2) 二元函数 这里我们只讨论二元…

如何理解微分、差分、导数

先说差分和微分 自变量x的差分就是微分 即&#xff1a; Δxdx 因变量y的差分是函数y的变化量 即 Δyy(xΔx)-y(x) 因变量y的微分是指函数图像在某一点处的切线在横坐标取得增量Δx以后&#xff0c;纵坐标取得的增量dy。 dyf(x)dx 总结&#xff1a; 微分是差分的线…