EasyExcel导出Excel文件——合并单元格多层级数据导出

news2024/10/5 14:11:54

合并单元格多层数据导出

思维脑图

在这里插入图片描述

代码实现

/**
 * 导出所有信息
 *
 * @param request 请求体
 */
@Override
public void getWilliamExportList(WilliamReqVo request, HttpServletResponse response) throws Exception {
    List<SysDictData> dataByType = dictDataService.getDictDataByType("status");
    Map<String, String> calendarStatus = dataByType.stream().collect(Collectors.toMap(SysDictData::getDictValue, SysDictData::getDictLabel));
    List<WilliamAllExportVo> list = baseMapper.getWilliamExportData(request);
    if (CollectionUtils.isNotEmpty(list)) {
        list.forEach(s -> s.setStatus(calendarStatus.get(s.getStatus())));
    }
    // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
    response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    response.setCharacterEncoding("utf-8");
    // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
    String fileName = URLEncoder.encode("某某表" + DateUtil.format(new Date(), SysConstants.DATE_FORMAT), "UTF-8").replaceAll("\\+", "%20");
    response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
    ExcelWriterBuilder writerBuilder = EasyExcel.write(response.getOutputStream(), WilliamAllExportVo.class);
    //合并策略
    addMergeStrategy(list, writerBuilder);
    writerBuilder.sheet("信息表").doWrite(list);
}


/**
 * 合并策略
 *
 * @param list          数据集
 * @param writerBuilder excel写对象
 */
private static void addMergeStrategy(List<WilliamAllExportVo> list, ExcelWriterBuilder writerBuilder) {
    // 第一级,选定键值进行分层准备
    Map<String, List<WilliamAllExportVo>> collect = list.stream().collect(Collectors.groupingBy(s -> s.getProjectSn() + s.getMonth()));
    Map<String, List<WilliamAllExportVo>> collect2 = list.stream().collect(Collectors.groupingBy(s -> s.getProjectSn() + s.getMonth() + s.getTitle()));
    //第一层合并单元格处理
    for (int i = 1; i < list.size(); ) {
        WilliamAllExportVo exportVo = list.get(i);
        //计算集合长度,确定有多少行
        int size = collect.get(exportVo.getProjectSn() + exportVo.getMonth()).size();
        //按照分层合并范围的属性,设置j的数值
        for (int j = 0; j < 10; j++) {
            OnceAbsoluteMergeStrategy strategy = new OnceAbsoluteMergeStrategy(i, i + size - 1, j, j);
            writerBuilder.registerWriteHandler(strategy);
        }
        i = i + size;
    }
    //第二层合并单元格处理,
    for (int i = 1; i < list.size(); ) {
        WilliamAllExportVo exportVo = list.get(i);
        int size = collect2.get(exportVo.getProjectSn() + exportVo.getMonth() + exportVo.getTitle()).size();
        for (int j = 10; j < 14; j++) {
            OnceAbsoluteMergeStrategy strategy = new OnceAbsoluteMergeStrategy(i, i + size - 1, j, j);
            writerBuilder.registerWriteHandler(strategy);
        }
        i = i + size;
    }
}

逻辑分析

1. 数据准备与状态映射

首先,通过dictDataService.getDictDataByType(“status”)获取字典数据,这通常用于将数据库中的状态码(如数字或简短字符串)转换为更加友好的展示标签。之后,使用Java 8的Stream API将这些数据转换成一个Map,键为状态值,值为状态标签,便于后续替换列表中项目的状态字段。

List<SysDictData> dataByType = dictDataService.getDictDataByType("project_calendar_status");
Map<String, String> calendarStatus = dataByType.stream()
    .collect(Collectors.toMap(SysDictData::getDictValue, SysDictData::getDictLabel));

接着,调用baseMapper.getWilliamExportData(request)获取项目日历导出数据列表,然后遍历列表,使用前面构建的状态映射替换项目状态字段的代码值为描述文本。

2. 设置响应头及内容类型

让HTTP响应能够以Excel文件的形式下载。首先,设置了响应的内容类型为Excel的OpenXML格式,然后通过URLEncoder.encode方法对文件名进行编码,以防止中文乱码,并使用特定的Content-Disposition头部来指示浏览器以附件形式下载文件,并给出文件名。

response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode("某某表" + DateUtil.format(new Date(), SysConstants.DATE_FORMAT), "UTF-8")
   .replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

3. 使用EasyExcel导出数据

EasyExcel是一个用于简化Excel操作的Java库,它允许开发者以更简洁的方式读写Excel文件。在这里,通过EasyExcel.write(response.getOutputStream(), WilliamAllExportVo.class)初始化一个Excel写入器,然后调用addMergeStrategy方法注册合并单元格的策略,最后在指定的工作表中写入数据。

4. 单元格合并策略

addMergeStrategy方法实现了Excel表格中单元格的合并策略。这里的逻辑是首先按照编号(projectSn)和月份(month)进行第一级分组,然后在同一组内再按照标题(title)进行第二级分组,分别对不同列范围内的连续行进行合并。

对于第一级分组(第1至第9列),合并所有属于同一项目、同一月份的行。
对于第二级分组(第10至第13列),在第一级的基础上,进一步根据标题合并。
使用了OnceAbsoluteMergeStrategy类,该类为EasyExcel提供的单元格合并策略之一,参数分别为起始行号、结束行号、起始列号、结束列号,指定了合并的具体范围。

知识点总结

  • 数据映射:利用Map和Stream API进行数据转换,提高代码的可读性和效率。
  • HTTP响应处理:设置正确的响应头以实现文件下载,以及解决中文乱码问题。
  • EasyExcel库:简化Excel文件的生成和读取过程,提升开发效率。
  • 单元格合并:通过自定义策略实现Excel中数据的分组和单元格合并,提升报表的可读性。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

添砖Java之路(其五)——封装,String,StringBuilder类。

封装&#xff1a; 封装意义&#xff1a;更好的维护数据&#xff0c;让使用者无需关心如何使用&#xff0c;只需要知道怎么使用。 Java Bean&#xff1a; 然后我们要知道Java Bean(实体类)标准。 1.对于这个类的成员都需要设为私有&#xff0c;而且要对外提供相应Get,Set的接…

WWW服务器搭建(1)——HTTP协议原理篇

目录 一、WWW的相关概念 1.1 WWW的定义 1.2 超文本标记语言HTML 1.3 统一资源定位符URL 1.4 超文本传输协议HTTP 二、HTTP协议工作过程 2.1 DNS解析 2.2 TCP连接过程 2.3 HTTP 请求与响应 2.4 TCP连接断开 三、HTTP请求报文格式 3.1 请求行 3.2 请求头 3.3 空行 …

大语言模型的数据预处理

文章目录 质量过滤敏感内容过滤数据去重 当收集了丰富的文本数据之后&#xff0c;为了确保数据的质量和效用&#xff0c;还需要对数据进行预处理&#xff0c;从而消除低质量、冗余、无关甚可能有害的数据。一般来说&#xff0c;需要构建并使用系统化的数据处理框架&#xff08;…

第十五节:贪心算法(下)

一 、 贪心算法的解题套路实战一&#xff08;最多的会议宣讲场次&#xff09; 1.1 描述 一些项目要占用一个会议室宣讲&#xff0c;会议室不能同时容纳两个项目的宣讲。 给你每一个项目开始的时间和结束的时间 你来安排宣讲的日程&#xff0c;要求会议室进行的宣讲的场次最多。…

校园志愿者管理系统带万字文档

文章目录 校园志愿者管理系统一、项目演示二、项目介绍三、10000字论文参考四、部分功能页面五、部分代码展示六、底部获取项目源码和万字论文参考&#xff08;9.9&#xffe5;带走&#xff09; 校园志愿者管理系统 一、项目演示 校园志愿者管理系统 二、项目介绍 基于Spring…

快速对比 找出2个名单不同之处

import pandas as pd# 读取两个Excel文件 df1 pd.read_excel(1.xlsx) df2 pd.read_excel(2.xlsx)# 检查两个DataFrame的列是否相同 if list(df1.columns) ! list(df2.columns):print("两个Excel文件的列不一致。")print("文件1的列&#xff1a;", df1.co…

免费思维13招之九:时间型思维

免费思维13招之九:时间型思维 免费思维的另一大战略思维——时间型思维。 什么是时间型思维呢?就是在某一个规定的时间内对消费者进行免费,比如一个月中的某一天,或一周中的某一天或一天中的某一个时间段对消费者进行免费。 就在去年,有一个电影院老板弟子,他的电影院营…

基于SSM的“基于协同过滤的在线通用旅游平台网站”的设计与实现(源码+数据库+文档)

基于SSM的“基于协同过滤的在线通用旅游平台网站”的设计与实现&#xff08;源码数据库文档) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SSM 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统主界面 景点信息界面 后台界面 部分源码…

设计循环队列-C语言实现

题目描述 设计循环队列 设计你的循环队列实现。 循环队列是一种线性数据结构&#xff0c;其操作表现基于 FIFO&#xff08;先进先出&#xff09;原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。 循环队列的一个好处是我们可以利用这个队列之前用过的…

算法-卡尔曼滤波之为什么要使用卡尔曼滤波器

假设使用雷达来预测飞行器的位置&#xff1b; 预先的假设条件条件: 1.激光雷达的激光束每5s发射一次&#xff1b; 2.通过接受的激光束&#xff0c;雷达估计目标当前时刻的位置和速度&#xff1b; 3.同时雷达要预测下一时刻的位置和速度 根据速度&#xff0c;加速度和位移的…

Spring简介IOCDI

文章目录 Spring简介Spring课程介绍为什么要学学什么怎么学 初识SpringSpring家族Spring发展史 Spring体系结构Spring核心概念目前代码存在的问题核心概念 IOC和DI入门案例IOC入门案例入门案例分析实现步骤实现代码 DI入门案例DI入门案例分析实现步骤实现代码图解演示 Bean的基…

【超详细】跑通YOLOv8之深度学习环境配置3-YOLOv8安装

环境配置3下载安装内容如下&#xff1a; 1、配置清华等镜像源 2、创建环境 3、下载安装Pytorch 4、下载安装YOLOv8运行环境 版本&#xff1a;Python3.8&#xff08;要求>3.8&#xff09;&#xff0c;torch1.12.0cu113&#xff08;要求>1.8&#xff09; 1、配置清华等镜…

用Arm CCA解锁数据的力量

安全之安全(security)博客目录导读 目录 CCA将如何改变Arm架构呢? 在实践中部署CCA 释放数据和人工智能的全部力量和潜力 早期计算中最大的挑战之一是管理计算资源&#xff0c;以最大化计算效率同时提供给不同程序或用户分配资源的分离。这导致了我们今天大多数使用的时间…

Windows环境下代码文档生成工具Doxygen使用详细教程

背景 最近研究aom源码&#xff0c;发现编译需要依赖Doxygen工具&#xff0c;故此篇博客详细记录下Doxygen的安装和使用。 Doxygen Doxygen 是一个强大的源代码文档生成工具&#xff0c;它支持多种编程语言&#xff0c;能够直接从源代码中的注释提取文档&#xff0c;并生成多…

基于SpringBoot设计模式之创建型设计模式·抽象工厂模式

文章目录 介绍开始架构图&#xff08;以穿搭举例&#xff09;样例一&#xff08;html关于列表和表格的应用&#xff09;定义抽象工厂&#xff08;html&#xff09;定义抽象工厂需要制作抽象产物&#xff08;托盘&#xff09;定义具体工厂&#xff08;列表、表格&#xff09;定义…

Mamba:4 魔幻矩阵A

若在阅读过程中有些知识点存在盲区&#xff0c;可以回到如何优雅的谈论大模型重新阅读。另外斯坦福2024人工智能报告解读为通识性读物。若对于如果构建生成级别的AI架构则可以关注AI架构设计。技术宅麻烦死磕LLM背后的基础模型。 ​Mamba自从出道就一直被拿来和Transformer对比…

HIVE卡口流量需求分析

HIVE卡口流量需求分析 目录 HIVE卡口流量需求分析 1.创建表格 插入数据 2.需求 3.总结&#xff1a; 1.创建表格 插入数据 CREATE TABLE learn3.veh_pass( id STRING COMMENT "卡口编号", pass_time STRING COMMENT "进过时间", pass_num int COMMENT …

懒人网址导航源码v3.9

测试环境 宝塔Nginx -Tengine2.2.3的PHP5.6 MySQL5.6.44 为防止调试错误&#xff0c;建议使用测试环境运行的php与mysql版本 首先用phpMyAdmin导入数据库文件db/db.sql 如果导入不行&#xff0c;请直接复制数据库内容运行sql语句也可以 再修改config.php来进行数据库配置…

AI智能体|我把Kimi接入了个人微信

大家好&#xff0c;我是无界生长。 最近加入AI学习交流群的小伙伴越来越多&#xff0c;我打算在微信群接入一个聊天机器人&#xff0c;让它协助管理微信群&#xff0c;同时也帮忙给群友解答一些问题。普通的群聊机器人肯定是不能满足需求的&#xff0c;得上AI大模型&#xff0c…

EPS软件标注点坐标值

1、如下&#xff0c;点击右侧&#xff08;尺寸标注&#xff09;按钮&#xff1a; 2、弹出一个对话框&#xff0c;如下&#xff1a; 3、在上图对话框中设置好箭头样式和小数位数&#xff0c;然后点击图上一点&#xff0c;右击结束再鼠标指定位置&#xff0c;如下&#xff1a; 如…