当前位置: 首页 > news >正文

SpringBoot实现导出Excel功能

在这里插入图片描述

1 问题背景

需求要做一个导出excel的功能

2 前言

  1. 本篇着重阐述后端怎么实现,前端实现的部分只会粗略阐述。该实现方案是经过生产环境考验的,不是那些拿来练手的小demo。本文阐述的方案可以借鉴用来做毕设或者加到自己玩的项目中去。
  2. 再次声明,本文是百万级数据量的企业级解决方案,不是学校里面的毕设或者自己搭环境玩玩的小demo。客户不会去一页一页地点击导出,本文阐述的是一键导出几千行甚至上万行的数据。如果本文与你了解到的方案有出入可以在评论区交流,像那种导出几行或十来行的方案就不要说了。
  3. 有读者在评论里提问“请教百万行能撑住吗?”笔者没有去验证,有兴趣或者有疑问的读者可以去验证下,本文的解决方案是导出几千或上万行数据。本文也只是想介绍电商生产环境中真实的需求以及真实的解决方案,如果要导出百万行,那就只能采用异步方式去进行导出了,文末有提供思路。

3 实现思路

  1. 后端查询要导出的数据,此处简称data
  2. 使用阿里的EasyExcel组件将data写到HttpServletResponse里面,返回指定的响应头、响应内容的类型、字符编码。响应出去的数据是二进制数据,此处简称bytes数据
  3. 前端使用前端框架提供的方法,将 bytes数据转成blob,然后生成下载地址,然后进行下载

4 后端实现

要引入阿里的EasyExcel依赖,此处不赘述

<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.1.7</version></dependency>

下面是excel文件要保存的信息,需要指定列头

@Data
public class UserInfoVO {@ExcelProperty(value = "用户ID",index = 0)private Long id;@ExcelProperty(value = "用户姓名",index = 1)private String username;@ExcelProperty(value = "性别",index = 2)private String sex;
}

导出的伪代码如下:

  @PostMapping("/xx/xxx/xxx")public void export(HttpServletResponse reponse) {// 设置响应头等response.setHeader("Content-Disposition", "attachment;filename=" + "文件名(随便定义).xlsx");response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("UTF-8");// 查数据,假如要导出UserInfo的列表信息List<UserInfoVO> data = selectData();// 导出数据 EasyExcel.write(response.getOutputStream()).head(UserInfoVO.class).sheet().doWrite(data);}

5 设置Excel自适应列宽

思路:实现easyexcel提供的类并重写方法,写数据到HttpServletReponse的时候注册一个自适应列宽的bean

实现AbstractColumnWidthStyleStrategy类,如下所示:

public class CustomCellWriteWeightConfig extends AbstractColumnWidthStyleStrategy {private Map<Integer, Map<Integer, Integer>> CACHE = new HashMap<>();@Overrideprotected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<CellData> cellDataList, Cell cell, Head head, Integer integer, Boolean isHead) {boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList);if (needSetWidth) {Map<Integer, Integer> maxColumnWidthMap = CACHE.get(writeSheetHolder.getSheetNo());if (maxColumnWidthMap == null) {maxColumnWidthMap = new HashMap<>();CACHE.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap);}Integer columnWidth = this.dataLength(cellDataList, cell, isHead);if (columnWidth >= 0) {if (columnWidth > 254) {columnWidth = 254;}Integer maxColumnWidth = maxColumnWidthMap.get(cell.getColumnIndex());if (maxColumnWidth == null || columnWidth > maxColumnWidth) {maxColumnWidthMap.put(cell.getColumnIndex(), columnWidth);Sheet sheet = writeSheetHolder.getSheet();sheet.setColumnWidth(cell.getColumnIndex(), columnWidth * 256);}}}}/*** 计算长度* @param cellDataList* @param cell* @param isHead* @return*/private Integer dataLength(List<CellData> cellDataList, Cell cell, Boolean isHead) {if (isHead) {return cell.getStringCellValue().getBytes().length;} else {CellData cellData = cellDataList.get(0);CellDataTypeEnum type = cellData.getType();if (type == null) {return -1;} else {switch (type) {case STRING:// 换行符(数据需要提前解析好)int index = cellData.getStringValue().indexOf("\n");return index != -1 ?cellData.getStringValue().substring(0, index).getBytes().length + 1 : cellData.getStringValue().getBytes().length + 1;case BOOLEAN:return cellData.getBooleanValue().toString().getBytes().length;case NUMBER:return cellData.getNumberValue().toString().getBytes().length;default:return -1;}}}}
}

注册自适应列宽的组件:

EasyExcel.write(response.getOutputStream()).head(SubscriptionOrderExportResp.class)//  注册自适应列宽组件.registerWriteHandler(new CustomCellWriteWeightConfig()).sheet().doWrite(data);

6 方案优缺点

优点:实现简单,轻量级。能快速迭代上线 。

缺点:使用了同步方式返回数据,如果excel文件的数据量很多,那么将耗费很多时间,甚至http连接已经断开了还未响应出去。

改进:本文解决方案是采用了同步方式导出,实时返回excel文件。可以做一个异步方式,后端创建一个任务异步生成excel文件,然后文件上传到对象存储服务器。前端轮询任务是否完成,后端返回文件地址给前端下载。

相关文章:

SpringBoot实现导出Excel功能

1 问题背景 需求要做一个导出excel的功能 2 前言 本篇着重阐述后端怎么实现&#xff0c;前端实现的部分只会粗略阐述。该实现方案是经过生产环境考验的&#xff0c;不是那些拿来练手的小demo。本文阐述的方案可以借鉴用来做毕设或者加到自己玩的项目中去。再次声明&#xff0c;…...

NSSCTF之Misc篇刷题记录⑧

NSSCTF之Misc篇刷题记录 [MMACTF 2015]welcome[广东强网杯 2021 团队组]欢迎参加强网杯[虎符CTF 2022]Plain Text[SWPUCTF 2021 新生赛]原来你也玩原神[SWPUCTF 2021 新生赛]我flag呢&#xff1f;[鹤城杯 2021]New MISC NSSCTF平台&#xff1a;https://www.nssctf.cn/ PS&…...

从零开始学习Linux运维,成为IT领域翘楚(七)

文章目录 &#x1f525;Linux下常用软件安装_JDK和Tomcat安装&#x1f525;Linux下常用软件安装_MySQL安装&#x1f525;Linux下常用软件安装_MySQL卸载 &#x1f525;Linux下常用软件安装_JDK和Tomcat安装 Jdk 安装 解压jdk安装包 tar -zxvf jdk-8u201-linux-x64.tar.gz -C/…...

优漫动游设计APP的UI界面需要注意哪些问题?

一、加载   加载时间的长短&#xff0c;很大程度的决定了用户体验是否有所提升&#xff0c;虽然理想中的页面加载出来应该一秒就够了&#xff0c;但是设计师不要忽略网络问题!如果网速不够的话&#xff0c;页面加载三五秒都算是快的了&#xff0c;所以在用户等待的过程中&a…...

面试 004

什么是 Java 内存结构 Java 内存结构就是 JVM 的运行书数据区的内存结构&#xff1a; 里面有堆、虚拟机栈、本地方法栈、程序计数器&#xff1b; 虚拟机栈&#xff1a;里面的数据结构是栈帧&#xff0c;存放了方法名&#xff0c;局部变量等信息 方法区在 1.8 的时候&#xf…...

CCF-202206-2-寻宝!大冒险!

目录 题目背景 问题描述 一、思路&#xff1a; 二、实现方法&#xff08;C&#xff09; 2.1、方法一&#xff08;int储存&#xff09; 思路&#xff1a; C实现如下&#xff1a; 2.2、方法二&#xff08;结构体储存&#xff09; 思路&#xff1a; 注意&#xff1a;边界…...

二叉搜索树中的众数

1题目 给你一个含重复值的二叉搜索树&#xff08;BST&#xff09;的根节点 root &#xff0c;找出并返回 BST 中的所有 众数&#xff08;即&#xff0c;出现频率最高的元素&#xff09;。 如果树中有不止一个众数&#xff0c;可以按 任意顺序 返回。 假定 BST 满足如下定义&…...

认识JSP

什么是JSP? JSP&#xff08;Java Server Pages&#xff09;是一种类似于HTML的标记语言&#xff0c;用于创建动态Web页面。与HTML不同的是&#xff0c;JSP页面中可以嵌入Java代码&#xff0c;由Web服务器在动态页面中生成HTML代码&#xff0c;从而实现Web应用程序的前端交互效…...

MySQL数据管理

一、MySQL数据库管理 1、库和表 行&#xff08;记录&#xff09;&#xff1a;用来描述一个对象的信息 列&#xff08;字段&#xff09;&#xff1a;用来描述对象的一个属性 2、常用的数据类型 int &#xff1a;整型 float &#xff1a;单精度浮点 4字节32位 double &…...

第十九章 Unity 其他 API

本节介绍一些其他经常使用的Unity类。首先&#xff0c;我们回顾一下Vector3向量类&#xff0c;它既可以表示方向&#xff0c;也可以表示大小。它在游戏中可以用来表示角色的位置&#xff0c;物体的移动/旋转&#xff0c;设置两个游戏对象之间的距离。在我们之前的课程中&#x…...

sha256算法详解,用C语言模拟sha256算法

SHA-256是一种加密算法,它可以将任意长度的数据块计算出一个固定长度的输出值,通常是256位。SHA-256具有以下特点: 1. 固定输出长度:SHA-256的输出长度为256位,不受输入数据的长度限制。 2. 不可逆性:SHA-256采用单向哈希函数,即无法从输出值反向推出输入数据。 3. 抗…...

前端技术未来发展展望

前端技术在未来的发展中将继续保持快速、变化多样和创新性强的趋势。以下是我认为前端技术未来发展的几个方向&#xff1a; 框架和库的演进&#xff1a;框架和库的更新换代将继续加速。React、Vue、Angular等主流框架的更新周期将会缩短&#xff0c;同时各自的生态系统也将更加…...

第四十六天|dp

今天的题还是完全背包的题 139. Word Break 这道题其实用deque也能做,但是需要cache去记录之前尝试过的值,.相对简单的办法就是用完全背包了 这道题worddict就是物品.我们的dp[i]代表到i为止是不是能满足题意分成segmentation 处置化全为false,但是dp[0]True.这是因为为0时…...

汇编语言-复习自用

本文用于自我复习汇编语言&#xff0c;参考b站一位老师的讲解整理而成&#xff0c;感谢老师的无私付出视频链接链接 文章目录 1.第一章1.1计算机组成1.2读取1.3 寄存器及数据存储1.4 mov和and指令1.5 确定物理地址1.6 内存分段表示法1.7debug使用1.8CS:IP1.9jmp指令改变csip1.1…...

Android moneky自动点击应用设想

近期又有人发错私密消息到群聊天里&#xff0c;造成巨大反应的事件&#xff0c;可谓是一失手成大恨&#xff0c;名利受损。 而如果手机里安装一个monkey自动点击程序&#xff0c;没事的时候&#xff0c;跑跑monkey&#xff0c;倒一杯茶&#xff0c;静静的看手机屏幕在那里点击&…...

16.基于主从博弈理论的共享储能与综合能源微网优化运行研究

说明书 MATLAB代码&#xff1a;基于主从博弈理论的共享储能与综合能源微网优化运行研究 关键词&#xff1a;主从博弈 共享储能 综合能源微网 优化调度 参考文档&#xff1a;《基于主从博弈理论的共享储能与综合能源微网优化运行研究》完全复现 仿真平台&#xff1a;MATLAB …...

使用 ESP32 设计智能手表第 2 部分 - 环境光和心率传感器

我们研究了如何为我们的智能手表项目制作一些有趣的表盘。在这一部分中,我们将研究如何将一些传感器连接到我们的智能手表,并将连接 BH1750 环境光传感器和 MAX30102 心率传感器。我们将分别研究这些模块中的每一个的接口。 先决条件——安装必要的库 本文下方提供的 GitHub …...

分布式事务 --- 理论基础、Seata架构、部署

一、分布式事务问题 1.1、本地事务 本地事务&#xff0c;也就是传统的单机事务。在传统数据库事务中&#xff0c;必须要满足四个原则&#xff1a; 1.2、分布式事务 分布式事务&#xff0c;就是指不是在单个服务或单个数据库架构下&#xff0c;产生的事务&#xff0c;例如&am…...

低代码开发重要工具:JVS列表页字段样式配置说明

列表页中&#xff0c;通常存在各种各样的样式控制&#xff0c;例如字段宽度需要可调、字段的颜色根据内容变化等&#xff0c;那么我们接下来介绍下字段的样式控制的内容以及对应的效果。 1、字段样式控制配置位置 进入列表页的 数据配置界面&#xff0c;每个字段可以有独立的配…...

explain结果字段分析

select_type simple&#xff1a;表示不需要union操作或者不包含子查询的简单select语句。有连接查询时&#xff0c;外层的查询为simple且只有一个。 primary&#xff1a;一个需要union操作或者含有子查询的select&#xff0c;位于最外层的单位查询的select_type即为primary且只…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

多种风格导航菜单 HTML 实现(附源码)

下面我将为您展示 6 种不同风格的导航菜单实现&#xff0c;每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?

uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件&#xff0c;用于在原生应用中加载 HTML 页面&#xff1a; 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

基于IDIG-GAN的小样本电机轴承故障诊断

目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) ​梯度归一化(Gradient Normalization)​​ (2) ​判别器梯度间隙正则化(Discriminator Gradient Gap Regularization)​​ (3) ​自注意力机制(Self-Attention)​​ 3. 完整损失函数 二…...

适应性Java用于现代 API:REST、GraphQL 和事件驱动

在快速发展的软件开发领域&#xff0c;REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名&#xff0c;不断适应这些现代范式的需求。随着不断发展的生态系统&#xff0c;Java 在现代 API 方…...

零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程

STM32F1 本教程使用零知标准板&#xff08;STM32F103RBT6&#xff09;通过I2C驱动ICM20948九轴传感器&#xff0c;实现姿态解算&#xff0c;并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化&#xff0c;适合嵌入式及物联网开发者。在基础驱动上新增…...