基于SpringBoot的后端导出Excel文件
后端导出Excel,前端下载。
系列文章指路👉
系列文章-基于SpringBoot3创建项目并配置常用的工具和一些常用的类
文章目录
- 后端导出Excel
- 引入依赖
- 写入响应
- 前端下载
- 后端导出失败和成功返回的内容类型不同,因此需要分别判断。
- 工具类
- ServletUtils.java
- FileUtils.java
- file.js
后端导出Excel
引入依赖
poi 操作xls,doc…;poi-ooxml操作xlsx,docx…
⚠️使用的版本比较新,可能跟老版本有些写法不兼容
<!-- poi and poi-ooxml --><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>5.2.2</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.2</version></dependency>
写入响应
- 生成Workbook对象这一步应该是个性化的。
- 中文的文件名需要经过编码,不然传到前端会乱码
- 工具类的源码放在文末
public Object export(String orderNum) {// 1. 生成Excel Workbook对象XSSFWorkbook workbook = initWorkbook(orderNum);HttpServletResponse rep = ServletUtils.getResponse();String errMessage;String fileName = "超市购进单-"+ DateUtil.today() + ".xlsx";if(Objects.isNull(rep)){throw new NullPointerException("HttpServletResponse 为空");}try {// 2. 将HSSFWorkbook文件写入到响应输出流中,供前端下载FileUtils.writeToResponse(workbook, fileName, rep);return null;}catch (IOException ioe){log.error("OrderServiceImpl export --- 导出过程中遇到输入输出异常: {}" ,ioe.toString());errMessage = "导出过程中遇到输入输出异常" + ioe;} catch (Exception e){log.error("OrderServiceImpl export --- 导出过程中遇到其他异常: {}" ,e.toString());errMessage = "导出过程中遇到其他异常:" + e;}return BaseResult.fail(errMessage);}
前端下载
后端导出失败和成功返回的内容类型不同,因此需要分别判断。
- 返回的是json类型的错误信息:
- 只有导出成功,才是文件流:
<template><h1>Excel导出测试</h1><p style="margin-top: 40px"><a-space><a-button type="primary" :icon="h(DownloadOutlined)" @click="downloadFile">下载Excel</a-button></a-space></p>
</template>
<script setup>
import {h} from 'vue';
import {DownloadOutlined} from '@ant-design/icons-vue';
import {UploadOutlined} from '@ant-design/icons-vue';
import {message} from "ant-design-vue";
import http from "@/utils/axios/index.js";
import {downloadFile as downer} from "@/utils/file.js";function downloadFile() {http.get('/manage/order/export', {params: {orderNum: '000001'},responseType: 'blob'}).then(resp => {if (resp.data.type === 'application/json') {// 失败了才会返回json类型const reader = new FileReader();reader.readAsText(resp.data, 'utf-8');reader.onload = () => {const result = JSON.parse(reader.result)message.error(`Error: ${result.message}!`);};} else {downer(resp)}}).catch(err => {message.error('导出失败:' + err)console.log(err)})
}
</script>
工具类
ServletUtils.java
package com.ya.boottest.utils.servlet;import com.alibaba.fastjson.JSON;
import com.ya.boottest.utils.result.BaseResult;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import java.io.IOException;
import java.util.Objects;/*** <p>* Servlet 工具类* </p>** @author Ya Shi* @since 2024/1/4 14:29*/@Slf4j
public class ServletUtils {/*** 获取Attributes** @return ServletRequestAttributes*/public static ServletRequestAttributes getRequestAttributes() {RequestAttributes attributes = RequestContextHolder.getRequestAttributes();if(Objects.isNull(attributes)){log.error("ServletUtils 获取到的RequestAttributes为空");throw new RuntimeException("ServletUtils 获取到的RequestAttributes为空");}return (ServletRequestAttributes) attributes;}/*** 获取request** @return HttpServletRequest*/public static HttpServletRequest getRequest() {return getRequestAttributes().getRequest();}/*** 获取session** @return HttpSession*/public static HttpSession getSession() {return getRequest().getSession();}/*** 获取response** @return HttpServletResponse*/public static HttpServletResponse getResponse() {return getRequestAttributes().getResponse();}
}
FileUtils.java
package com.ya.boottest.utils.file;import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;/*** <p>* 文件util* </p>** @author Ya Shi* @since 2023/8/11 11:58*/
@Slf4j
public class FileUtils {/*** 将HSSFWorkbook文件写入到响应输出流中,供前端下载* @param workbook 文件对象* @param fileName 文件名* @param response HttpServletResponse响应* @throws IOException IO异常*/public static void writeToResponse(XSSFWorkbook workbook, String fileName, HttpServletResponse response) throws IOException{try {response.setHeader("Content-Disposition", "attachment;filename=" + processFileName(fileName));response.setContentType("application/octet-stream; charset=utf-8");response.setCharacterEncoding("utf-8");ByteArrayOutputStream bos = new ByteArrayOutputStream();workbook.write(bos);byte[] bytes = bos.toByteArray();OutputStream outData = response.getOutputStream();outData.write(bytes);outData.flush();} catch (IOException e) {log.error("FileUtil writeToResponse workbook写入响应失败-----> " + e);throw e;}}/*** 对要下载的文件的名称进行编码,防止中文乱码问题。** @param fileName 文件名* @return String*/public static String processFileName(String fileName) throws IOException {String codedFilename;String prefix = fileName.lastIndexOf(".") != -1 ? fileName.substring(0, fileName.lastIndexOf(".")) : fileName;String extension = fileName.lastIndexOf(".") != -1 ? fileName.substring(fileName.lastIndexOf(".")) : "";String name = java.net.URLEncoder.encode(prefix, StandardCharsets.UTF_8);if (name.lastIndexOf("%0A") != -1) {name = name.substring(0, name.length() - 3);}int limit = 150 - extension.length();if (name.length() > limit) {name = java.net.URLEncoder.encode(prefix.substring(0, Math.min(prefix.length(), limit / 9)), StandardCharsets.UTF_8);if (name.lastIndexOf("%0A") != -1) {name = name.substring(0, name.length() - 3);}}name = name.replaceAll("[+]", "%20");codedFilename = name + extension;log.info("FileUtil processFileName codedFilename-----> " + codedFilename);return codedFilename;}
}
file.js
export function downloadFile(resp) {const tmp = 'filename='const contentDisposition = decodeURIComponent(resp.headers['content-disposition'])const fileName = contentDisposition.substring(contentDisposition.indexOf(tmp) + tmp.length)const contentType = resp.headers['content-type']const blob = new Blob([resp.data], {type: contentType})let a = document.createElement('a')a.href = URL.createObjectURL(blob)a.download = fileNamea.target = '_blank'a.style.display = 'none'document.body.appendChild(a)a.click()a.remove()
}
明月别枝惊鹊,清风半夜鸣蝉。
—— 宋朝 · 辛弃疾《 西江月 夜行黄沙道中 》
相关文章:

基于SpringBoot的后端导出Excel文件
后端导出Excel,前端下载。 系列文章指路👉 系列文章-基于SpringBoot3创建项目并配置常用的工具和一些常用的类 文章目录 后端导出Excel引入依赖写入响应 前端下载后端导出失败和成功返回的内容类型不同,因此需要分别判断。 工具类ServletUti…...

2 月 5 日算法练习- 动态规划
DP(动态规划)全称Dynamic Programming,是运筹学的一个分支,是一种将复杂问题分解成很多重叠的子问题、并通过子问题的解得到整个问题的解的算法。 在动态规划中有一些概念: n<1e3 [][] ,n<100 [][][…...

SpringBoot整合EasyCaptcha图形验证码
简介 EasyCaptcha:https://github.com/ele-admin/EasyCaptcha Java图形验证码,支持gif、中文、算术等类型,可用于Java Web、JavaSE等项目。 添加依赖 <dependency><groupId>com.github.whvcse</groupId><artifactId…...
学习数据结构和算法的第3天
常数循环的复杂度 计算Func4的时间复杂度 voidFunc4(int N) { int count 0; for (int k 0; k < 100; k) { count; } printf("%d\n", count); }O(1) 不是代表算法运行一次,是常数次 strchar的时间复杂度 #include<stdi…...

SpringBoot实战第三天
今天主要完成了: 新增棋子分类 棋子分类列表 获取棋子分类详情 更新棋子分类 更新棋子分类和添加棋子分类_分组校验 新增棋子 新增棋子参数校验 棋子分类列表查询(条件分页) 先给出分类实体类 Data public class Category {private Integer id;//主键IDNot…...
mysql学习打卡day22
今日成果: select * from employees where salary > (select avg(salary) from employees); -- 查询超过平均工资的员工select * from clients where client_id not in (select distinct client_id from invoices); -- 查询没有发票的用户 感谢各位读者查阅&…...

Unity | Spine动画记录
https://blog.csdn.net/linshuhe1/article/details/79792432 https://blog.csdn.net/winds_tide/article/details/128925407 1.需要的三个文件 通常制作好的 Spine 动画导出时会有三个文件: .png 、.json 和 .atlas: skeleton-name.json 或 skeleton-…...
【Flink】FlinkSQL实现数据从MySQL到MySQL
简介 我们在实际开发过程中可以使用Flink实现数据从MySQL传输到MySQL具体操作,本例子Flink版本1.13.6,具体操作如下: 创建mysql测试表 下面语句创建了mysql原表和目标表,并插入一条语句到mysql原表中 CREATE TABLE `mysql_source` ( `id` int(11) unsigned NOT NULL AUT…...
python爬虫抓取新闻并且植入自己的mysql远程数据库内
python爬虫抓取新闻并且植入自己的mysql远程数据库内!这个代码是我自己写了很久才写好的,分享给大家。喜欢的点个赞。 # -*- coding: utf-8 -*- from xml.etree import ElementTree as ET import datetime import randomimport pymysql from selenium im…...
netty实现简单的客户端、服务端互相发消息
引入maven依赖 <dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.20.Final</version> </dependency> 一、服务端 1、创建服务端启动类 public class MyServer {public static voi…...

利用jmeter完成简单的压力测试
Jmeter是一个非常好用的压力测试工具。Jmeter用来做轻量级的压力测试,非常合适,只需要十几分钟,就能把压力测试需要的脚本写好。 1、什么是压力测试 顾名思义:压力测试,就是 被测试的系统,在一定的访问压…...
【手写数据库toadb】toadb物理存储模型,数据库物理存储原理,物理文件组织关系以及行列混合模型存储结构
存储模型概述 专栏内容: 手写数据库toadb 本专栏主要介绍如何从零开发,开发的步骤,以及开发过程中的涉及的原理,遇到的问题等,让大家能跟上并且可以一起开发,让每个需要的人成为参与者。 本专栏会定期更新,对应的代码也会定期更新,每个阶段的代码会打上tag,方便阶段…...

MySQL-----DDL基础操作
SQL通用语法 1.SQL语句可以单行或多行书写,以分号结尾。 2. SQL语句可以使用空格/缩进来增强语句的可读性。 3. MySQL数据库的SQL语句不区分大小写,关键字建议使用大写。 4.注释: 单行注释:--注释内容或#注释内容(MySQL特有) 多行注释:/*注释…...

【MySQL】在 Centos7 环境安装 MySQL -- 详细完整教程
说明: 安装与卸载中,用户全部切换成为 root,一旦安装,普通用户就能使用。 一、卸载内置环境 1、卸载不要的环境 [rootVM-8-5-centos ~]$ ps ajx | grep mariadb # 先检查是否有mariadb存在 13134 14844 14843 13134 pts/0 14843…...
理解React中的setState()方法
在React中,setState()方法是一个非常重要的概念,它用于更新组件的状态并触发重新渲染。本文将探讨setState()的使用方法、工作原理以及一些基本的用法。 setState()方法简介 setState()是React组件中用于更新状态的方法之一。它接受一个对象或一个函数作…...

数据库管理-第144期 深入使用EMCC-01(20240204)
数据库管理144期 2024-02-04 数据库管理-第144期 深入使用EMCC-01(20240204)1 用户管理2 配置告警动作3 配置意外事件规则总结 数据库管理-第144期 深入使用EMCC-01(20240204) 作者:胖头鱼的鱼缸(尹海文&am…...

flask_django_python五金电商网络营销的可视化分析研究
前面部分完成了系统需求分析,了解到新闻数据业务方面的需求,系统主要分为用户管理、五金信息管理、在线留言、系统管理等功能。销的可视化研究,并对这些数据进行处理, 然后对这些数据进行可视化分析和统计。 Python 爬虫技术目前来…...

Java并发(二十三)----同步模式之保护性暂停
1、定义 即 Guarded Suspension,用在一个线程等待另一个线程的执行结果 要点 有一个结果需要从一个线程传递到另一个线程,让他们关联同一个 GuardedObject 如果有结果不断从一个线程到另一个线程那么可以使用消息队列 JDK 中,join 的实现…...

###C语言程序设计-----C语言学习(9)#函数基础
前言:感谢您的关注哦,我会持续更新编程相关知识,愿您在这里有所收获。如果有任何问题,欢迎沟通交流!期待与您在学习编程的道路上共同进步。 一. 基础知识的学习 1.函数的定义 函数是一个完成特定工作的独立程序模块&…...

Dockerfile文件参数配置和使用
天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…...

业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...

使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...