基于SpringBoot后端導(dǎo)出Excel文件的操作方法
后端導(dǎo)出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>
寫入響應(yīng)
- 生成Workbook對(duì)象這一步應(yīng)該是個(gè)性化的。
- 中文的文件名需要經(jīng)過(guò)編碼,不然傳到前端會(huì)亂碼
- 工具類的源碼放在文末
public Object export(String orderNum) {
// 1. 生成Excel Workbook對(duì)象
XSSFWorkbook workbook = initWorkbook(orderNum);
HttpServletResponse rep = ServletUtils.getResponse();
String errMessage;
String fileName = "超市購(gòu)進(jìn)單-"+ DateUtil.today() + ".xlsx";
if(Objects.isNull(rep)){
throw new NullPointerException("HttpServletResponse 為空");
}
try {
// 2. 將HSSFWorkbook文件寫入到響應(yīng)輸出流中,供前端下載
FileUtils.writeToResponse(workbook, fileName, rep);
return null;
}catch (IOException ioe){
log.error("OrderServiceImpl export --- 導(dǎo)出過(guò)程中遇到輸入輸出異常: {}" ,ioe.toString());
errMessage = "導(dǎo)出過(guò)程中遇到輸入輸出異常" + ioe;
} catch (Exception e){
log.error("OrderServiceImpl export --- 導(dǎo)出過(guò)程中遇到其他異常: {}" ,e.toString());
errMessage = "導(dǎo)出過(guò)程中遇到其他異常:" + e;
}
return BaseResult.fail(errMessage);
}
前端下載
后端導(dǎo)出失敗和成功返回的內(nèi)容類型不同,因此需要分別判斷。
- 返回的是json類型的錯(cuò)誤信息:

- 只有導(dǎo)出成功,才是文件流:

<template>
<h1>Excel導(dǎo)出測(cè)試</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') {
// 失敗了才會(huì)返回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('導(dǎo)出失?。? + 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文件寫入到響應(yīng)輸出流中,供前端下載
* @param workbook 文件對(duì)象
* @param fileName 文件名
* @param response HttpServletResponse響應(yīng)
* @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寫入響應(yīng)失敗-----> " + e);
throw e;
}
}
/**
* 對(duì)要下載的文件的名稱進(jìn)行編碼,防止中文亂碼問(wèn)題。
*
* @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 = fileName
a.target = '_blank'
a.style.display = 'none'
document.body.appendChild(a)
a.click()
a.remove()
}
以上就是基于SpringBoot后端導(dǎo)出Excel文件的操作方法的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot后端導(dǎo)出Excel的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
PowerJob的TimingStrategyHandler工作流程源碼解讀
這篇文章主要為大家介紹了PowerJob的TimingStrategyHandler工作流程源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01
Clojure?與Java對(duì)比少數(shù)據(jù)結(jié)構(gòu)多函數(shù)勝過(guò)多個(gè)單獨(dú)類的優(yōu)點(diǎn)
這篇文章主要介紹了Clojure?與Java對(duì)比少數(shù)據(jù)結(jié)構(gòu)多函數(shù)勝過(guò)多個(gè)單獨(dú)類的優(yōu)點(diǎn),在Clojure中,我們一次又一次地使用相同的數(shù)據(jù)結(jié)構(gòu),并在其上運(yùn)行許多函,更多相關(guān)介紹需要的朋友可以參考一下下面文章內(nèi)容2022-06-06
springboot集成springdoc-openapi的案例講解(模擬前端請(qǐng)求)
文章介紹了Spring?Boot集成Swagger時(shí)版本沖突的常見(jiàn)問(wèn)題,推薦使用springdoc-openapi-ui替代Springfox,因其配置更簡(jiǎn)單且遵循OpenAPI規(guī)范,同時(shí)提供驗(yàn)證和界面優(yōu)化方法,對(duì)springboot集成springdoc-openapi相關(guān)知識(shí)感興趣的朋友一起看看吧2025-06-06
詳解Java中NullPointerException異常的原因和解決辦法
本文主要介紹了詳解Java中NullPointerException異常的原因和解決辦法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07
JVM對(duì)象創(chuàng)建和內(nèi)存分配原理解析
這篇文章主要介紹了JVM對(duì)象創(chuàng)建和內(nèi)存分配原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02
Java項(xiàng)目中“zip END header not found“錯(cuò)誤的解決方案
在 Java 項(xiàng)目構(gòu)建或運(yùn)行過(guò)程中,開(kāi)發(fā)者常會(huì)遇到 java.util.zip.ZipException: zip END header not found 錯(cuò)誤,這一異常通常與 JAR 文件損壞、下載不完整、編碼問(wèn)題或 Maven 依賴管理配置不當(dāng)有關(guān),本文給大家介紹了Java項(xiàng)目中“zip END header not found“錯(cuò)誤的解決方案2025-06-06
Java實(shí)現(xiàn)按年月打印日歷功能【基于Calendar】
這篇文章主要介紹了Java實(shí)現(xiàn)按年月打印日歷功能,涉及java基于Calendar進(jìn)行日期運(yùn)算的相關(guān)操作技巧,需要的朋友可以參考下2018-03-03
詳解mybatis 批量更新數(shù)據(jù)兩種方法效率對(duì)比
這篇文章主要介紹了詳解mybatis 批量更新數(shù)據(jù)兩種方法效率對(duì)比,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02
Java中Scanner的常用方法總結(jié)(一次學(xué)懂)
這篇文章主要給大家介紹了關(guān)于Java中Scanner常用方法的相關(guān)資料,Java中的Scanner是一個(gè)用于讀取用戶輸入的類,它可以讀取各種類型的數(shù)據(jù),包括整數(shù)、浮點(diǎn)數(shù)、字符串等等,需要的朋友可以參考下2023-11-11
springboot實(shí)現(xiàn)對(duì)接poi 導(dǎo)出excel折線圖
在Spring Boot項(xiàng)目中使用Apache POI庫(kù)可以實(shí)現(xiàn)將數(shù)據(jù)導(dǎo)出為Excel并嵌入動(dòng)態(tài)生成的折線圖,具有一定的參考價(jià)值,感興趣的可以了解一下2025-10-10

