【EasyExcel】导出excel-设置动态表头并导出数据
需求背景:
导出excel的设置某些表头动态导出(可以根据筛选条件或一些属性的数据量),方便导出后用户查看想看的信息。
一、技术选型:
easyExcel的原生数据处理
二、方案设计:
根据EasyExcel支持的表头List<List<String>>手动设置,可参考Easy Excel 官网(动态表头),本文给的可自行研究,Demo简单易懂。
三、代码实现:
3.1:pom.xml
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.3.2</version>
</dependency>
3.2: API
@ApiOperation(value = "导出")@PostMapping("/export")public void export(HttpServletResponse response, @RequestBody DemoExportParam param) throws BaseException {exportService.export(response, param);}
3.3:通用服务层API
import com.alibaba.excel.write.handler.WriteHandler;import javax.servlet.http.HttpServletResponse;
import java.util.List;/*** @author c*/
public interface IEasyExcelService {/*** 导出excel方法** @param exportData 需要导出的数据* @param response response* @param tClass 导出excel的字段实体类* @param fileName 文件名字* @param sheetName sheet名字*/<T> void exportExcel(List<T> exportData, HttpServletResponse response, Class<T> tClass, String fileName, String sheetName);/*** 导出excel方法 (携带自定义策略)* @param exportData 需要导出的数据* @param response HttpServletResponse* @param tClass 导出excel的字段实体类* @param fileName 文件名字* @param sheetName sheet名字* @param writeHandler 自定义策略(可扩展多个)* @param <T> T*/<T> void exportExcelWithHandler(List<T> exportData, HttpServletResponse response, Class<T> tClass, String fileName, String sheetName, WriteHandler writeHandler);/*** 导出excel方法(动态表头-动态数据) 携带自定义handler* @param response HttpServletResponse* @param head 表头* @param data 数据* @param fileName 文件名字* @param sheetName sheet名字* @param writeHandler 自定义策略(可扩展多个)* @param <T> T*/<T> void exportExcelWithDynamicsHead(HttpServletResponse response, List<List<String>> head, List<List<Object>> data,String fileName, String sheetName, WriteHandler writeHandler);
}
3.4:通用服务层API实现类
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.write.handler.WriteHandler;
import com.galaplat.marketing.oas.easyexcel.IEasyExcelService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.util.List;/*** @author c* Description: 文件excel处理方法* date: 2024-07-26 10:10:10*/
@Service
@Slf4j
public class EasyExcelServiceImpl implements IEasyExcelService {private static final String ENCODING_UTF_8 = "UTF-8";private static final String FILE_END = ".xlsx";private static final String CONTENT_DISPOSITION = "Content-Disposition";private static final String CONTENT_DISPOSITION_VALUE = "attachment;filename=";private static final String ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers";private static final String CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";/*** 本地转:response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileNameEncoder + ".xlsx");* @param exportData 需要导出的数据* @param response response* @param tClass 导出excel的字段实体类* @param fileName 文件名字* @param sheetName sheet名字* @param <T> T*/@Overridepublic <T> void exportExcel(List<T> exportData, HttpServletResponse response, Class<T> tClass, String fileName, String sheetName){// 使用swagger 会导致各种问题,直接用浏览器或者用postmanresponse.setContentType(CONTENT_TYPE);response.setCharacterEncoding(ENCODING_UTF_8);try{// fileName encoderString fileNameEncoder = URLEncoder.encode(fileName, ENCODING_UTF_8).replaceAll("\\+", "%20");response.setHeader(CONTENT_DISPOSITION, CONTENT_DISPOSITION_VALUE + fileNameEncoder + FILE_END);response.setHeader(ACCESS_CONTROL_EXPOSE_HEADERS, CONTENT_DISPOSITION);// write to excelEasyExcelFactory.write(response.getOutputStream(), tClass).autoCloseStream(Boolean.FALSE).sheet(sheetName).doWrite(exportData);}catch (Exception e){log.error("EasyExcelServiceImpl->exportExcel error, message is :{}", e.getMessage());}}@Overridepublic <T> void exportExcelWithHandler(List<T> exportData, HttpServletResponse response, Class<T> tClass,String fileName, String sheetName, WriteHandler writeHandler){// 使用swagger 会导致各种问题,直接用浏览器或者用postmanresponse.setContentType(CONTENT_TYPE);response.setCharacterEncoding(ENCODING_UTF_8);try{// fileName encoderString fileNameEncoder = URLEncoder.encode(fileName, ENCODING_UTF_8).replaceAll("\\+", "%20");response.setHeader(CONTENT_DISPOSITION, CONTENT_DISPOSITION_VALUE + fileNameEncoder + FILE_END);response.setHeader(ACCESS_CONTROL_EXPOSE_HEADERS, CONTENT_DISPOSITION);// write to excelEasyExcelFactory.write(response.getOutputStream(), tClass).autoCloseStream(Boolean.FALSE)// 自定义策略(支持扩展多个).registerWriteHandler(writeHandler).sheet(sheetName).doWrite(exportData);}catch (Exception e){log.error("EasyExcelServiceImpl->exportExcel error, message is :{}", e.getMessage());}}@Overridepublic <T> void exportExcelWithDynamicsHead(HttpServletResponse response, List<List<String>> head, List<List<Object>> data,String fileName, String sheetName, WriteHandler writeHandler){// 使用swagger 会导致各种问题,直接用浏览器或者用postmanresponse.setContentType(CONTENT_TYPE);response.setCharacterEncoding(ENCODING_UTF_8);try {// fileName encoderString fileNameEncoder = URLEncoder.encode(fileName, ENCODING_UTF_8).replaceAll("\\+", "%20");response.setHeader(CONTENT_DISPOSITION, CONTENT_DISPOSITION_VALUE + fileNameEncoder + FILE_END);response.setHeader(ACCESS_CONTROL_EXPOSE_HEADERS, CONTENT_DISPOSITION);// write to excelEasyExcelFactory.write(response.getOutputStream()).head(head).sheet(sheetName)// handle.registerWriteHandler(writeHandler).doWrite(data);} catch (Exception e) {log.error("EasyExcelServiceImpl->exportExcelWithHandlerAndHead error, message is :{}", e.getMessage());}}}
3.5:服务Demo查询参数DemoExportParam
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.util.List;@Data
public class DemoExportParam {@ApiModelProperty(value = "参数1")private String param1;@ApiModelProperty(value = "参数1")private String param2;@ApiModelProperty(value = "动态可选择参数")private List<String> choiceParam;}
注意:参数DemoExportParam 中的choiceParam是可以多个的选项,本文中的动态表头也是根据它来实现动态表头的,支持扩展(比如根据查询数据中某个字段来设置,具体可以参考下面的实现代码)
3.6:服务Demo方法实现层
注意:其中IDemoService 是自己的服务方法,可以自行修改,只用来获取数据
/*** Demo Export Service Impl* author: c* date: 2024-8-15 16:46:08*/
@Service
@Slf4j
public class DemoExportServiceImpl {private static final String FILE_NAME_PRODUCT_DETAIL = "测试动态表头";private final IDemoService service;private final IEasyExcelService excelService;public DemoExportServiceImpl(IDemoService service, IEasyExcelService excelService) {this.service = service;this.excelService = excelService;}public void export(HttpServletResponse response, DemoExportParam param) throws BaseException {// 根据param获取查询到的参数List<DemoDataVO> pageInfoList = service.listAllData(param);// export with dynamics headexcelService.exportExcelWithDynamicsHead(response, head(param), getData(pageInfoList, param),FILE_NAME_PRODUCT_DETAIL, FILE_NAME_PRODUCT_DETAIL, new FreezeRowColHandler(FreezeRowColConstant.PRODUCT_DETAIL));}public List<List<Object>> getData(List<DemoDataVO> detailList, DemoExportParam param){if (CollectionUtils.isEmpty(detailList)){return new ArrayList<>();}// 查询的动态参数List<String> choiceParam = param.getChoiceParam();return detailList.stream().map(c -> {List<Object> objectList = new LinkedList<>();objectList.add(c.getParamData1());// 设置动态表头的数据this.setChoiceParamValue(objectList, c, choiceParam);objectList.add(c.getParamData2());return objectList;}).collect(Collectors.toList());}private void setChoiceParamValue(List<Object> objectList, DemoDataVO vo, List<String> choiceParams){List<String> paramData = vo.getChoiceParamData();if (CollectionUtils.isEmpty(paramData) || CollectionUtils.isEmpty(choiceParams)){return;}// 转成mapMap<String, String> paramDataMap = paramData.stream().collect(Collectors.toMap(Function.identity(), Function.identity()));for (String choiceData : choiceParams) {// 获取对应的值String matchingValue = paramDataMap.get(choiceData);// 添加 对应的值 到 objectListif (StringUtils.isNotBlank(matchingValue)) {objectList.add(matchingValue);} else {objectList.add("");}}}private List<List<String>> head(DemoExportParam param) {List<List<String>> headList = new ArrayList<>();addHeadItem(headList, "参数1");// 动态表头 此处是根据参数中的动态参数设置,选择多少参数就动态加多少表头 其它同理// 这里也可以自定义:比如 根据查询的数据量设置等List<String> choiceParam = param.getChoiceParam();if (!CollectionUtils.isEmpty(choiceParam)){for (String choice : choiceParam) {addHeadItem(headList, "动态头" + "-" + choice);}}addHeadItem(headList, "参数2");// .......其他表头return headList;}private static void addHeadItem(List<List<String>> headList, String value) {List<String> item = new ArrayList<>();item.add(value);headList.add(item);}}
四、总结
本文主要通过EasyExcel实现动态表头,扩展性还可以,提供的是基本实现,方便自行研究,本文所在栏目有多个EasyExcel实现可以自行查看,如有其它问题或者好的方法,可直接留言或私信,欢迎指正。
👍如果对你有帮助,给博主一个免费的点赞以示鼓励
欢迎各位🔎点赞👍评论收藏⭐️
相关文章:
【EasyExcel】导出excel-设置动态表头并导出数据
需求背景: 导出excel的设置某些表头动态导出(可以根据筛选条件或一些属性的数据量),方便导出后用户查看想看的信息。 一、技术选型: easyExcel的原生数据处理 二、方案设计: 根据EasyExcel支持的表头List<List<String>…...
深入探索 Elasticsearch 8:新特性与核心原理剖析(上)
深入探索 Elasticsearch 8:新特性与核心原理剖析 目录 一、引言 (二)版本 8 的重要意义 二、Elasticsearch 8 的新特性 三、Elasticsearch 的核心原理 一、引言 (一)Elasticsearch 简介 在大数据处理和搜索领域…...
瑜伽馆预约小程序,在线预约,提高商业价值
随着大众生活质量的提高,对休闲运动的关注逐渐加大,瑜伽作为一种身心放松、改善体态的运动,深受女性用户的喜爱。目前,各大瑜伽馆开始结合数字化,建立了新型的线上小程序,帮助大众快速预约体验瑜伽…...
Python--数据类型转换
在Python中,数据类型的转换是一个常见的操作,涉及将一种数据类型转换为另一种数据类型。Python提供了多种内置函数用于执行这种转换,如 int()、str()、float()、list()、tuple()、set()、dict() 等。下面详细讨论Python的基本数据类型及它们之…...
域控ntdsutil修改架构、域命名、PDC、RID、结构主机
#笔记记录# FSMO盒修改 1、提示访问特权不够,不能执行该操作,0x2098 清除缓存账号密码并修改新架构管理员账号密码即可。 背景:更替架构主机、域命名主机 C:\Windows\system32>ntdsutil ntdsutil: roles fsmo maintenance: ?? …...
解决 Swift 6 全局变量不能满足并发安全(concurrency-safe)读写的问题
概述 WWDC 24 终于在 Swift 十岁生日发布了全新的 Swift 6。这不仅意味着 Swift 进入了全新的“大”版本时代,而且 Swift 编译器终于做到了并发代码执行的“绝对安全”。 不过,从 Swift 5 一步迈入“新时代”的小伙伴们可能对新的并发检查有些许“水土不…...
迈入退休生活,全职开发ue独立游戏上架steam
决定退休了。算了算睡后收入,也可以达到每月一万一,正好可以养家糊口。 既然退休了,那就做些想做的事情,别人养花养草,而我打算开发独立游戏上架steam。 一,盘点下目前的技术体系。 1,图形学底…...
什么是光伏气象站——仁科测控
【仁科测控,品质保障】光伏气象站,这一专门为光伏发电系统设计的监测设备,其核心能力在于精确且实时地捕捉那些对光伏发电效率产生关键影响的气象因素。这些数据不仅为评估光伏电站的发电性能提供了重要依据,更是优化运维…...
webshell免杀--免杀入门
前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文主要整理webshell免杀的一些基础思路 入门级,不是很深入,主要是整理相关概念 免杀对象 1.各类杀毒软件 类似360,火绒等,查杀己方webshell的软件。 2.各类流量…...
Linux---02---系统目录及文件基本操作命令
课程回顾 操作系统 虚拟机安装 本章重点 Linux系统目录结构 常用命令 熟练区分Linux下各层目录的作用 熟练掌握Linux的常用命令(文件命令、时间命令等) 一、Linux系统目录结构 1.1 目录结构 /: 根目录,一般根目录下只存放…...
CSP-J/S第一轮初赛模拟赛试题
本模拟试题为本人自创,由于发布在 LG 所以就直接放入链接。 非经允许,不得转载。 本套模拟题只供大家练习使用,不保证难度与真实 CSP-J/S 完全符合。 本模拟赛为专业CSP类型的模拟赛,不存在错题、超出知识的题目。 CSP-J/S 20…...
LangGPT结构化提示词
LangGPT是Language For GPT-like LLMs的简称,中文名为结构化提示词,LangGPT是一个帮助你编写高质量提示词的工具,理论基础是我们提出的一套模块化、标准化的提斯提编写方法论——结构化提示词。我们希望揭开提示工程的神秘面纱,为…...
如何为个人网站更换ssl证书
关键步骤 1,确认服务器类型并下载对应证书(这个超级简单,阿里云现在可以下3月免费的); 2,本文以nginx服务为例,主打的就是一个简单且快速让你搞清楚实操流程; linux命令 ps-ef|gr…...
RabbitMQ-消息队列延迟队列一
1、安装rabbitmq 怎么安装rabbitmq请查看之前课程,如果已经安装,请略过此步。 2、创建vendor文件夹或是直接采用PHP框架 mkdir vendor 3、进入文件 cd vendor 4、安装php扩展 composer require php-amqplib/php-amqplib 5、进入上级创建dead文件…...
JavaScript中普通对象和Map对象的区别
在JavaScript中,普通对象({})和 Map 对象都是用于存储键值对的数据结构,但是他们有一些区别。 1. 键的类型 普通对象: 对象的键必须是字符串或 Symbol 类型。其他类型的值(如数字、布尔值、对象等&#x…...
Liunx搭建Rustdesk远程桌面服务
1、环境准备 Linux:centos7.9 rustdesk server安装包 很多新服务器并没有 wget 和unzip 可以通过yum自行安装下,如果系统中有wget但不能使用,直接卸载重装即可。 yum install wget wget --no-check-certificate https://github.com/rust…...
antv X6--实现节点旁添加多个text标签
前言:接本专栏上篇文章,实现一个新需求,如有不懂的可先去看新手教程 需求描述:如何在节点旁添加多个标签,如下图所示: 实现该需求目前我只想到两种方法: 方法一:使用换行符将不同的…...
JAVA--多线程
Java中的多线程是指在同一个Java虚拟机(JVM)中并发执行多个线程的能力。线程是程序执行的最小单元,Java提供了丰富的API来创建和管理线程。以下是Java中实现多线程的一些关键概念和方法: Thread 类:Java提供了Thread类…...
ADB-DROM
# 读硬件信息 adb shell "cat /sys/block/mmcblk0/device/name" # MT6767/MT6768/MT6769/MT6762/MT6765/MT6761... # 频率档位 # 固定频率 adb shell "echo 0 > /sys/devices/platform/10012000.dvfsrc/helio-dvfsrc/dvfsrc_force_vcore_dvfs_opp" # …...
mysql 之 explain
1. 查看表的创建字段以及索引情况 show create table user_recommend; 2. 创建索引的原则:列的值比较离散 像性别字段,只有男,女 或者其他;expose字段,只有1分发,0不可分发。就不适宜在这种字段上添加索引…...
IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...
ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
