【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不可分发。就不适宜在这种字段上添加索引…...
Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...
Git常用命令完全指南:从入门到精通
Git常用命令完全指南:从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...
从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障
关键领域软件测试的"安全密码":Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力,从金融交易到交通管控,这些关乎国计民生的关键领域…...
路由基础-路由表
本篇将会向读者介绍路由的基本概念。 前言 在一个典型的数据通信网络中,往往存在多个不同的IP网段,数据在不同的IP网段之间交互是需要借助三层设备的,这些设备具备路由能力,能够实现数据的跨网段转发。 路由是数据通信网络中最基…...
