POI 导出 树形结构

 参考文章:(327条消息) Excel树状数据绘制导出_excel导出树形结构_Deja-vu xxl的博客-CSDN博客icon-default.png?t=N6B9https://blog.csdn.net/weixin_45873182/article/details/120132409?spm=1001.2014.3001.5502


    @Override
    public void exportPlus(String yearMonth, HttpServletRequest request ,HttpServletResponse response) {
        try {
            String fileName = "周进度填报.xlsx";
            ServletOutputStream out = response.getOutputStream();
            HSSFWorkbook workbook = new HSSFWorkbook();
            response.setHeader("content-type", "text/plain");
            response.setHeader("content-type", "application/x-msdownload;");
            response.setContentType("text/plain; charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename="  +  URLEncoder.encode(fileName, "UTF-8"));

            String projectId = tokenService.getProjectId(request);
            List<SysDept> deptIdsByProjectId = sysDeptMapper.getDeptIdsByPeojectId(Long.valueOf(projectId));
            List<SysDept> collect = deptIdsByProjectId.stream().filter(s -> s.getEmail() == null).collect(Collectors.toList());

            if(collect.size()>0){
                for (int i = 0; i <collect.size(); i++) {
                    SysDept sysDept = collect.get(i);
                    String email = sysDept.getEmail();
                    if (email == null){
                        exportPlusByProject(sysDept.getDeptId(),yearMonth,workbook, i, sysDept.getDeptName(), out);
                    }
                }
            }
            
            //原理就是将所有的数据一起写入,然后再关闭输入流。
            out = response.getOutputStream();
            workbook.write(out);
            out.flush();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();

        }
    }



    public void exportPlusByProject(Long zhgdDeptId,String yearMonth,HSSFWorkbook workbook, int sheetNum,String sheetTitle,
                                                     String[] headers,List<List<JSONObject>> data,ServletOutputStream out) {
        try {
           

            //存放数据的二维集合,twoDimensional 中每个List是树状结构的一个分支的所有数据
            List<List<JSONObject>> twoDimensional = new ArrayList<>();

            //******************************查询正文数据******************************
            ZhgdWeeklyProgressReport zhgdWeeklyProgressReport = new ZhgdWeeklyProgressReport();
            zhgdWeeklyProgressReport.setZhgdDeptId(zhgdDeptId);
            zhgdWeeklyProgressReport.setCurrentDates(yearMonth);
            ZhgdWeeklyProgressReport zhgdWeeklyProgressReport1 = weeklyProgressReportService.getlastMonthData(zhgdWeeklyProgressReport);
            String fillingTime1 = zhgdWeeklyProgressReport1.getFillingTime();

            LambdaQueryWrapper<ZhgdWeeklyProgressReport> ZhgdWeeklyProgressReportWrapper = new LambdaQueryWrapper<>();
            ZhgdWeeklyProgressReportWrapper.eq(ZhgdWeeklyProgressReport::getZhgdDeptId,zhgdDeptId)
                    .eq(ZhgdWeeklyProgressReport::getCurrentDates,yearMonth)
                    .eq(ZhgdWeeklyProgressReport::getFillingTime,fillingTime1)
                    .eq(ZhgdWeeklyProgressReport::getIsExists,2)
                    .orderByAsc(ZhgdWeeklyProgressReport::)



            //------------------------------静态数据-----------------------------------

            HashMap<String, Object> stringObjectHashMap0 = new HashMap<>();
            stringObjectHashMap0.put("dictLabel","施工驻地,工地实验室");
            stringObjectHashMap0.put("key1","39");
            stringObjectHashMap0.put("key2","0.65%");
            stringObjectHashMap0.put("key3","767731.2");
            stringObjectHashMap0.put("key4","0.23%");

            HashMap<String, Object> stringObjectHashMap1 = new HashMap<>();
            stringObjectHashMap1.put("dictLabel","施工驻地,工地实验室");

            HashMap<String, Object> stringObjectHashMap2 = new HashMap<>();
            stringObjectHashMap2.put("dictLabel","临时工程与设施");

            ArrayList<JSONObject> list0 = new ArrayList<>();
            list0.add(new JSONObject(stringObjectHashMap0));
            list0.add(new JSONObject(stringObjectHashMap1));
            list0.add(new JSONObject(stringObjectHashMap2));

            //---------------------------第二组list----------------------------------
            HashMap<String, Object> stringObjectHashMap10 = new HashMap<>();
            stringObjectHashMap10.put("dictLabel","拌合站(处)");
            stringObjectHashMap10.put("key1","75");
            stringObjectHashMap10.put("key2","1.24%");
            stringObjectHashMap10.put("key3","444767731.2");
            stringObjectHashMap10.put("key4","1.33%");

            HashMap<String, Object> stringObjectHashMap11 = new HashMap<>();
            stringObjectHashMap11.put("dictLabel","拌合站(处)");

            HashMap<String, Object> stringObjectHashMap12 = new HashMap<>();
            stringObjectHashMap12.put("dictLabel","临时工程与设施");

            ArrayList<JSONObject> list1 = new ArrayList<>();
            list1.add(new JSONObject(stringObjectHashMap10));
            list1.add(new JSONObject(stringObjectHashMap11));
            list1.add(new JSONObject(stringObjectHashMap12));

            twoDimensional.add(list0);
            twoDimensional.add(list1);

            //------------------------------结束------------------------------------

            //------------------------------表头-----------------------------------
            //keys 是表头的字段
            List<String> keys = new ArrayList<>();

            //tier 是动态项目清单的总层级
            Integer tier = 3;
            //创建对象
            //创建工作表
            Sheet sheet = workbook.createSheet();
            workbook.setSheetName(sheetNum, sheetTitle);
            sheet.setDefaultColumnWidth(25);
            short s1  = 2 * 256 ;
            sheet.setDefaultRowHeight(s1);

            CellStyle styleTltles = workbook.createCellStyle();
            styleTltles.setFillForegroundColor(IndexedColors.GREEN.getIndex());

            styleTltles.setAlignment(HorizontalAlignment.CENTER);
            styleTltles.setVerticalAlignment(VerticalAlignment.CENTER);
            //下边框
            styleTltles.setBorderBottom(BorderStyle.THIN);
            //左边框
            styleTltles.setBorderLeft(BorderStyle.THIN);
            //上边框
            styleTltles.setBorderTop(BorderStyle.THIN);
            //右边框
            styleTltles.setBorderRight(BorderStyle.THIN);
            //自动换行
            styleTltles.setWrapText(true);

            //间隔行加背景
            setRowBackground(workbook);

            //columnMap 是一个对象,转换成Json
            //*****************************下面数据请求数据库***********************
            LambdaQueryWrapper<ZhgdWeeklyProgressReport> weeklyProgressReportLambdaQueryWrapper = new LambdaQueryWrapper<>();
            weeklyProgressReportLambdaQueryWrapper.eq(ZhgdWeeklyProgressReport::getCurrentDates,yearMonth)
                                                  .eq(ZhgdWeeklyProgressReport::getZhgdDeptId,zhgdDeptId)
                                                  .groupBy(ZhgdWeeklyProgressReport::getFillingTime)
                                                  .groupBy(ZhgdWeeklyProgressReport::getCreateDatetime)
                                                  .orderByAsc(ZhgdWeeklyProgressReport::getCreateDatetime)
                                                  .select(ZhgdWeeklyProgressReport::getFillingTime);

            List<ZhgdWeeklyProgressReport> weeklyProgressReportList = weeklyProgressReportService.list(weeklyProgressReportLambdaQueryWrapper);

            HashMap<String, Object> columnMap = new HashMap<>(5);
            columnMap.put("单价(元)","单价(元)");
            keys.add("单价(元)");
            columnMap.put("总量","总量");
            keys.add("总量");
            if (weeklyProgressReportList.size()>0){
                weeklyProgressReportList.stream().forEach(entity->{
                    String fillingTime = entity.getFillingTime();
                    String s = fillingTime + "日完成工程量";
                    columnMap.put(s,s);
                    keys.add(s);
                });
            }
            
            columnMap.put("完成工程量合计","完成工程量合计");
            keys.add("完成工程量合计");
            if (weeklyProgressReportList.size()>0){
                weeklyProgressReportList.stream().forEach(entity->{
                    String fillingTime = entity.getFillingTime();
                    String s = fillingTime + "日完成产值(万元)";
                    columnMap.put(s,s);
                    keys.add(s);
                });
            }
            columnMap.put("完成产值(万元)合计","完成产值(万元)合计");
            keys.add("完成产值(万元)合计");
            columnMap.put("截止上月累计完成工程量","截止上月累计完成工程量");
            keys.add("截止上月累计完成工程量");
            columnMap.put("截止上月累计完成产值","截止上月累计完成产值");
            keys.add("截止上月累计完成产值");
            columnMap.put("截止本月累计完成工程量","截止本月累计完成工程量");
            keys.add("截止本月累计完成工程量");
            columnMap.put("累计完成总量占比","累计完成总量占比");
            keys.add("累计完成总量占比");
            columnMap.put("截止本月累计完成产值(万元)","截止本月累计完成产值(万元)");
            keys.add("截止本月累计完成产值(万元)");

            //动态创建首行表头
            JSONObject topBean = new JSONObject();
            Row firstRow = sheet.createRow(0);
            JSONObject cm = new JSONObject(columnMap);
            for (int i = 0; i < tier+keys.size(); i++) {
                Cell cell = firstRow.createCell(i);
                if (i<tier){
                    String s="一";
                    switch (i){
                        case 1 : s="二";break;
                        case 2 : s="三";break;
                    }
                    cell.setCellValue(s+"级分类");
                }else {
                    cell.setCellValue(cm.getString(keys.get(i - tier)));
                }
            }

            //动态绘制数据,tier是层级数,根据业务最多三级
            for (int i = 0; i < twoDimensional.size(); i++) {
                Row row = sheet.createRow(i+1);
                List<JSONObject> list = twoDimensional.get(i);

                for (int j = 0; j < keys.size()+tier; j++) {
                    Cell cell = row.createCell(j);
                    if (j<tier){
                        //绘制层级标签
                        if (j==0){
                            JSONObject jsonObject = list.get(tier - 1);
                            cell.setCellValue(jsonObject.getString("dictLabel"));
                            continue;
                        }
                        if (j==1){
                            Map map = list.get(tier - 2);
                            cell.setCellValue((String)map.get("dictLabel"));
                            continue;
                        }
                        if (j==2){
                            Map map = list.get(tier - 3);
                            cell.setCellValue((String)map.get("dictLabel"));
                            continue;
                        }
                    }else {
                        //绘制层级的数据
                        JSONObject bean = new JSONObject(list.get(0));
                        cell.setCellValue(bean.getString(keys.get(j - tier)));
                    }
                }
            }

            //添加总合计行,并合并单元格
            Row totalRow = sheet.createRow(twoDimensional.size()+1);
            for (int j = 0; j < keys.size()+tier; j++) {
                Cell cell = totalRow.createCell(j);
                if (j<tier){
                    cell.setCellValue("合计");
                }else {
                    cell.setCellValue(topBean.getString(keys.get(j - tier)));
                }
            }
            if (tier != 1){
                sheet.addMergedRegion(new CellRangeAddress(twoDimensional.size()+1,twoDimensional.size()+1,0,tier-1));
            }

            //合并相同的单元格
            int lastRowNum = sheet.getLastRowNum();
            int index = 0;
            //根据业务只有标签这几列需要合并
            for (int i = 0; i < tier-1; i++) {
                //比较相邻cell的值是否相同,并记录
                for (int j = 0; j < lastRowNum; j++) {
                    Row row = sheet.getRow(j);
                    Cell cell = row.getCell(i);
                    Cell cell2 = row.getCell(i+1);
                    String stringCellValue = cell.getStringCellValue();
                    String stringCellValueNextRow = cell2.getStringCellValue();
                    if ("合计".equals(stringCellValue)){
                        sheet.addMergedRegion(new CellRangeAddress(j,j,i,i+1));
                        continue;
                    }

                    Row nextRow = sheet.getRow(j+1);
                    Cell nextcell = nextRow.getCell(i);
                    String nextStringCellValue = nextcell.getStringCellValue();
                    if (stringCellValue.equals(nextStringCellValue)){
                        if (j+1 == lastRowNum){
                            if (index != 0){
                                sheet.addMergedRegion(new CellRangeAddress(j-index,j+1,i,i));
                                index = 0;
                            }
                        }else {
                            index++;
                        }
                    }else {
                        if (index != 0){
                            sheet.addMergedRegion(new CellRangeAddress(j-index,j,i,i));
                            index = 0;
                        }
                    }
                    //横向合并
                    // row-- 相邻的如果相同合并
                    if (stringCellValueNextRow.equals(stringCellValue) && j != 0 ){
                        sheet.addMergedRegionUnsafe(new CellRangeAddress(j,j,i,i+1));
                    }

                }
            }

        }catch (Exception e){
            e.printStackTrace();
        }
    }

导出样式

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/49194.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

spring5源码篇(12)——spring-mvc请求流程

spring-framework 版本&#xff1a;v5.3.19 文章目录 一、请求流程1、处理器映射器1.1、 RequestMappingHandlerMapping1.2、获取对应的映射方法1.3、添加拦截器 2、获取合适的处理器适配器3、通过处理器适配器执行处理器方法3.1、拦截器的前置后置3.2、处理器的执行3.2.1 参数…

重生之我要学C++第四天

这篇文章的主要内容是类的默认成员函数。如果对大家有用的话&#xff0c;希望大家三连支持&#xff0c;博主会继续努力&#xff01; 目录 一.类的默认成员函数 二.构造函数 三.析构函数 四.拷贝构造函数 五.运算符重载 一.类的默认成员函数 如果一个类中什么成员都没有&…

目标检测-击穿黑夜的PE-YOLO

前言 当前的目标检测模型在许多基准数据集上取得了良好的结果&#xff0c;但在暗光条件下检测目标仍然是一个巨大的挑战。为了解决这个问题&#xff0c;作者提出了金字塔增强网络&#xff08;PENet&#xff09;并将其与YOLOv3结合&#xff0c;构建了一个名为PE-YOLO的暗光目标检…

Linux中的ldd命令使用方法总结

ldd&#xff08;List Dynamic Dependencies&#xff09;命令是Linux系统中的一个工具 它用于打印出一个可执行文件所依赖的共享库文件&#xff08;动态链接库&#xff09; 当你运行ldd命令&#xff0c;并跟上一个可执行文件作为参数&#xff0c;它会列出该可执行文件所需要的…

【Spring】Spring 总览

一、简单介绍一下 Spring Spring是一个全面的、企业应用开发的一站式解决方案&#xff0c;贯穿表现层、业务层、持久层&#xff0c;可以轻松和其他框架整合&#xff0c;具有轻量级、控制反转、面向切面、容器等特征。 轻量级 &#xff1a; 空间开销和时间开销都很轻量 控制反…

栈和队列第二弹,完结篇

&#x1f49b;1.队列的基本底层实现 public class MyQueue {int array[];int usedsize0;public MyQueue(){this.arraynew int [5];} &#x1f499;2.判断是否满&#xff0c;满了需要扩容 Arrays.copyOf(数组&#xff0c;数组的长度&#xff09;&#xff1b;我常常会忘记哈…

Java版本企业工程项目管理系统平台源码(三控:进度组织、质量安全、预算资金成本、二平台:招采、设计管理)

工程项目管理软件&#xff08;工程项目管理系统&#xff09;对建设工程项目管理组织建设、项目策划决策、规划设计、施工建设到竣工交付、总结评估、运维运营&#xff0c;全过程、全方位的对项目进行综合管理 工程项目各模块及其功能点清单 一、系统管理 1、数据字典&#…

Safari 查看 http 请求

文章目录 1、开启 Safari 开发菜单2、显示 JavaScript 控制台 1、开启 Safari 开发菜单 Safari 设置中&#xff0c;打开开发菜单选项 *** 选择完成后&#xff0c;Safari 的目录栏就会出现一个 开发 功能。 2、显示 JavaScript 控制台 开启页面后&#xff0c;在开发中选中 显…

掌握Python的X篇_10+11_if分支语句、else语句、elif语句

文章目录 1. if关键字及语法2. 语句块的概念3. else语句4. elif语句 1. if关键字及语法 基本语法如下&#xff1a; if 条件表达式:条件为True时&#xff0c;要执行的语句举例&#xff1a; number int(input("Input an number")) if number > 5 :print("这…

F12 浏览器调试模式页面刷新 network 日志刷新消失的解决办法

每次请求刷新后都把之前的请求记录刷新掉了&#xff0c;把preserve log勾选上后&#xff0c;所有的请求都会保留&#xff0c;再也不怕抓不到记录了。

SpringBoot项目部署在Windows与Centos上

文章目录 Windows部署一、github上下载文件winsw二、文件目录三、编辑xml文件四、安装服务五、启动服务六、把jar包放到项目外面七、添加限制内存 Linux部署一、准备二、服务三、操作 Windows部署 windows部署服务借鉴于此篇博文 一、github上下载文件winsw 点击链接下载下图…

windows切换php版本以及composer

前提 安装php8.2 安装Php7.4 下载 nts是非线程安全的&#xff0c;这里选择线程安全的&#xff0c;选择64位 解压缩 修改系统环境变量 修改为php-7的 cmd中输入php -v查看 找到composer存放路径C:\ProgramData\ComposerSetup\bin 将三个文件复制到php目录下 重启电脑…

【云原生】Docker容器命令监控+Prometheus监控平台

目录 1.常用命令监控 docker ps docker top docker stats 2.weave scope 1.下载 2.安装 3.访问查询即可 3.Prometheus监控平台 1.部署数据收集器cadvisor 2.部署Prometheus 3.部署可视化平台Gragana 4.进入后台控制台 1.常用命令监控 docker ps [rootlocalhost ~…

GitHub Copilot:让开发编程变得像说话一样简单

引用&#xff1a; 人类天生就梦想、创造、创新。但今天&#xff0c;我们花太多时间被繁重的工作所消耗&#xff0c;花在消耗我们时间、创造力和精力的任务上。为了重新连接我们工作的灵魂&#xff0c;我们不仅需要一种更好的方式来做同样的事情&#xff0c;更需要一种全新的工…

Linux下CMake开发

CMake编译和运行C文件 编写CMakeLists.txt # 声明要求的 cmake 最低版本 cmake_minimum_required( VERSION 3.1 )# 声明一个 cmake 工程 project( pro )# 设置编译模式 set( CMAKE_BUILD_TYPE "Release" )#添加OPENCV库 #指定OpenCV版本&#xff0c;代码如下 #find…

笔记20230727

1. http2.0&#xff0c;概念就不说了&#xff0c;查看是否使用&#xff1a;network调试&#xff0c;查看请求的header-view source&#xff0c;可以查看http版本&#xff1b;后端&#xff0c;如nginx&#xff0c;配置&#xff0c;http2表示开启。后端开启、浏览器支持&#xff…

PHP8的注释-PHP8知识详解

欢迎你来到PHP服务网&#xff0c;学习《PHP8知识详解》系列教程&#xff0c;本文学习的是《PHP8的注释》。 什么是注释&#xff1f; 注释是在程序代码中添加的文本&#xff0c;用于解释和说明代码的功能、逻辑或其他相关信息。注释通常不会被编译器或解释器处理&#xff0c;而…

《TCP IP网络编程》第十一章

第 11 章 进程间通信 11.1 进程间通信的基本概念 通过管道实现进程间通信&#xff1a; 进程间通信&#xff0c;意味着两个不同的进程中可以交换数据。下图是基于管道&#xff08;PIPE&#xff09;的进程间通信的模型&#xff1a; 可以看出&#xff0c;为了完成进程间通信&…

Redis 笔记,基本数据类型、持久化、主从、集群等等问题

标题 &#x1f600;&#x1f600;&#x1f600;创作不易&#xff0c;各位看官点赞收藏. 文章目录 标题Redis 基础笔记1、安装及环境搭建2、Redis 数据类型2.1、String2.2、List2.3、Hash2.4、Set2.5、Zset2.6、BitMap2.7、HyperLogLog2.8、Geospatial2.9、Stream 3、Redis 持久…

C++之普通函数指针/类成员函数指针/lambda回调函数总结(一百六十八)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…