【经验分享】EasyExcel实现自定义动态化导出excel

需求:

        需求涉及保存设备的灵活属性,设备的属性并不固定。允许设备的属性动态扩展。最终数据库采用EAV 模型的设计模式,使用三张表实现:设备表 、属性定义表、属性值表。

        现在堆上述数据进行导入和导出。

解决:

        这里使用EasyExcel,处理数据的导入导出。工具类核心方法如下:

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.resource.ClassPathResource;
import cn.hutool.core.util.IdUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import com.alibaba.excel.write.merge.LoopMergeStrategy;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.excel.write.metadata.fill.FillWrapper;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.util.CollectionUtils;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.stream.Collectors;/*** 自定义导出* @param os* @param titleList* @param mergeTitles* @param dataList*/public static void customDynamicExport(OutputStream os, List<String> titleList,List<String> mergeTitles, List<List<Object>> dataList) {
//        fileName = fileName + ".xlsx";// 导出的数据转换为Map数据结构, k -> 标题,v -> 此标题下的数据按顺序Map<String, List<Object>> dataMap = new HashMap<>(titleList.size());for (int i = 0 ; i < titleList.size(); i++) {// 当前列数据List<Object> currectTitleDatas = new ArrayList<>();for (int j = 0; j < dataList.size(); j++) {currectTitleDatas.add(dataList.get(j).get(i));}dataMap.put(titleList.get(i), currectTitleDatas);}// **标题信息List<List<String>> headTitleInfo = excelTitle(titleList);// **数据信息List<List<Object>> excelDataInfo = excelData(dataList);// **合并单元格信息List<LoopMergeStrategy> mergeStrategies = mergeCells(titleList, mergeTitles, dataMap);ExcelWriterBuilder excelWriterBuilder = EasyExcel.write(os);if (!CollectionUtils.isEmpty(mergeStrategies)) {
//            log.info("开始进行合并单元格操作 mergeStrategies ===> {}", mergeStrategies);mergeStrategies.forEach(m -> {excelWriterBuilder.registerWriteHandler(m);});}excelWriterBuilder.head(headTitleInfo).sheet("模板")// 当然这里数据也可以用 List<List<String>> 去传入.doWrite(excelDataInfo);}/*** **excel标题** @param titleList* @return*/private static List<List<String>> excelTitle(List<String> titleList) {List<List<String>> excelTitleList = new ArrayList<>(titleList.size());titleList.forEach(k -> {List<String> titles = new ArrayList<>(1);titles.add(k);excelTitleList.add(titles);});return excelTitleList;}private static List<List<Object>> excelData(List<List<Object>> dataList) {return dataList;}private static List<LoopMergeStrategy> mergeCells(List<String> titleList, List<String> mergeTitles, Map<String, List<Object>> dataMap) {// 将需要合并的项转换为Map,以便**合并位置Map<String, String> mergeTitleMap = mergeTitles.stream().collect(Collectors.toMap(k -> k, k -> k));// **合并位置Map<String, Integer> mergeLocationMap = new HashMap<>(mergeTitles.size());for (int i = 0; i < titleList.size(); i++) {if (Objects.nonNull(mergeTitleMap.get(titleList.get(i)))) {mergeLocationMap.put(titleList.get(i), i);}}List<LoopMergeStrategy> mergeStrategyList = new ArrayList<>();mergeTitles.forEach(k -> {// 合并数据所在的列数Integer columnIndex = mergeLocationMap.get(k);List<Object> mergeDatas = dataMap.get(k);// 需要合并的数量Integer currectMergeNum = 1;for (int m = 0; m < mergeDatas.size(); m++) {// 是否存在合并环节Boolean isMerge = false;if (m != 0 && Objects.equals(mergeDatas.get(m), mergeDatas.get(m - 1))) {isMerge = true;currectMergeNum = currectMergeNum + 1;if (m == mergeDatas.size() - 1) {isMerge = false;}}if (!isMerge && currectMergeNum > 1) {// 合并的行数Integer eachRow = currectMergeNum;mergeStrategyList.add(new LoopMergeStrategy(eachRow, columnIndex));currectMergeNum = 1;}}});return mergeStrategyList;}

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

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

相关文章

Docker入门系列——网络

Docker 通过容器化应用程序&#xff0c;彻底改变了我们构建、分发和运行应用程序的方式。然而&#xff0c;有效使用 Docker 的一个关键方面是理解容器如何相互通信以及与外界通信。 1. 什么是 Docker 网络&#xff1f; Docker 网络允许容器相互通信以及与外部资源通信。默认情况…

2024年大厂AI大模型面试题精选与答案解析

前言 随着AI市场&#xff0c;人工智能的爆火&#xff0c;在接下来的金九银十招聘高峰期&#xff0c;各大科技巨头和国有企业将会对AGI人才的争夺展开一场大战&#xff0c;为求职市场注入了新的活力。 为了助力求职者在面试中展现最佳状态&#xff0c;深入理解行业巨头的选拔标…

Nico,从零开始干掉Appium,移动端自动化测试框架实现

开头先让我碎碎念一波~去年差不多时间发布了一篇《 UiAutomator Nico&#xff0c;一个基于纯 adb 命令实现的安卓自动化测试框》&#xff08;https://testerhome.com/topics/37042&#xff09;&#xff0c; 由于种种原因 (详见此篇帖子) 当时选择了用纯 adb 命令来实现安卓自动…

RTP和RTCP的详细介绍及其C代码示例

RTP和RTCP的详细介绍及其C代码示例 RTP和RTCP简介RTP协议详解RTCP协议详解RTP和RTCP之间的关系C代码示例RTP和RTCP简介 RTP(Real-time Transport Protocol,实时传输协议)和RTCP(Real-time Transport Control Protocol,实时传输控制协议)是流媒体传输中常用的两个协议。R…

国内能用的Docker镜像源【2024最新持续更新】

国内能用的Docker镜像源【2024最新持续更新】 Docker 镜像加速列表&#xff08;2024年11月已更新&#xff09;配置方式1&#xff1a;临时使用配置方式2&#xff1a;长久有效 在国内使用 Docker 的朋友们&#xff0c;可能都遇到过配置镜像源来加速镜像拉取的操作。然而&#xff…

MySQL 的 select * 会用到事务吗?

我们都知道&#xff0c;在InnoDB存储引擎中&#xff0c;所有的修改操作都必须在事务中进行的。 那么&#xff0c;而 SELECT * 这种普通的读取操作其实也会在事务的上下文中执行&#xff0c;即使没有明确的开启事务语句InnoDB存储引擎也会为查询自动开启一个隐式事务。 因此&a…

队列(Queue)的介绍与实现

文章目录 队列队列的概念及结构 队列的实现初始化队列销毁队列队尾入队列队头出队列获取队列头部元素检测队列是否为空获取队列中有效元素个数 队列 队列的概念及结构 队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表。队列遵…

3.1 快速启动Flink集群

文章目录 1. 环境配置2. 本地启动3. 集群启动4. 向集群提交作业4.1 提交作业概述4.2 添加打包插件4.3 将项目打包4.4 在Web UI上提交作业4.5 命令行提交作业 在本实战中&#xff0c;我们将快速启动Apache Flink 1.13.0集群&#xff0c;并在Hadoop集群环境中提交作业。首先&…

[sa-token]StpUtil.getLoginId

闲聊 一般情况下&#xff0c;我们想用uid&#xff0c;可能需要前端将uid传过来&#xff0c;或者将token传来&#xff0c;然后我们进行识别。 用了sa-token之后&#xff0c;可以使用StpUtil.getLoginId()方法获取当前会话的用户id 代码展示 例如以下代码&#xff1a; public Res…

算法实现 - 快速排序(Quick Sort) - 理解版

文章目录 算法介绍算法分析核心思想三个版本运行过程挖坑法Hoare 原版前后指针法 算法稳定性和复杂度稳定性时间复杂度平均情况O(nlogn)最差情况O( n 2 n^2 n2) 空间复杂度 算法介绍 快速排序是一种高效的排序算法&#xff0c;由英国计算机科学家C. A. R. Hoare在1960年提出&a…

算法【Java】—— 动态规划之斐波那契数列模型

动态规划 动态规划的思路一共有五个步骤&#xff1a; 状态表示&#xff1a;由经验和题目要求得出&#xff0c;这个确实有点抽象&#xff0c;下面的题目会带大家慢慢感受状态标识状态转移方程初始化&#xff1a;避免越界访问 dp 表&#xff0c;所以在进行填表之前我们要预先填…

03:选择语句的练习

选择语句的练习 1、分数判断2、判断年份3、判断水仙花数 1、分数判断 输入分数判断为&#xff1a;不及格(0 ≤ x <60)&#xff0c;一般(60 ≤ x < 75)&#xff0c;良好(75 ≤ x < 85)&#xff0c;优秀(85 ≤ x ≤ 99)&#xff0c;满分(100)。 #include <stdio.h&g…

gulp入门教程2:gulp发展历史

早期阶段&#xff08;2013年-2014年&#xff09; 诞生背景&#xff1a;随着前端开发复杂度的增加&#xff0c;开发者们开始寻求自动化工具来简化构建流程。2013年&#xff0c;由Fractal Innovations的Eric Schoffstall首次发布。它借鉴了Unix管道的流式处理思想&#xff0c;通…

SpringBoot学生请假系统:从零到一的构建过程

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

json-server的使用(根据json数据一键生成接口)

一.使用目的 在前端开发初期&#xff0c;后端 API 可能还未完成&#xff0c;json-server 可以快速创建模拟的 RESTful API&#xff0c;帮助前端开发者进行开发和测试。 二.安装 npm install json-server //局部安装npm i json-server -g //全局安装 三.使用教程 1.准备一…

【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型

一、介绍 车辆车型识别&#xff0c;使用Python作为主要编程语言&#xff0c;通过收集多种车辆车型图像数据集&#xff0c;然后基于TensorFlow搭建卷积网络算法模型&#xff0c;并对数据集进行训练&#xff0c;最后得到一个识别精度较高的模型文件。再基于Django搭建web网页端操…

【Redis】浅析Redis大Key

目录 1、什么是Redis大Key 2、大 Key 是怎么产生的 3、大 Key 导致的问题 4、如何快速找到 Redis 大 Key 5、大 Key 优化策略 6、总结 我们在使用 Redis 的过程中&#xff0c;如果未能及时发现并处理 Big keys&#xff08;下文称为“大Key”&#xff09;&#xff0c;可能…

Rocky DEM tutorial3_Vibrating Screen_振荡筛

tutorial3_Vibrating Screen_振荡筛 文章目录 tutorial3_Vibrating Screen_振荡筛0. 目的1. 模型介绍2. 模型设置2.1 Physics设置2.2 导入几何2.3 创建一个进口的几何面2.4 定义运动 Motion frame2.5 材料设置&#xff0c;保持默认即可2.6 设置材料间的相互作用 materials inte…

小林渗透入门:burpsuite+proxifier抓取小程序流量

目录 前提&#xff1a; 代理&#xff1a; proxifier&#xff1a; 步骤&#xff1a; bp证书安装 bp设置代理端口&#xff1a; proxifier设置规则&#xff1a; proxifier应用规则&#xff1a; 结果&#xff1a; 前提&#xff1a; 在介绍这两个工具具体实现方法之前&#xff0…

阿里云-防火墙设置不当导致ssh无法连接

今天学网络编程的时候&#xff0c;看见有陌生ip连接&#xff0c;所以打开了防火墙禁止除本机之外的其他ip连接&#xff1a; 但是当我再次用ssh的时候&#xff0c;连不上了才发现大事不妙。 折腾了半天&#xff0c;发现阿里云上可以在线向服务器发送命令&#xff0c;所以赶紧把2…