springboot+vue實現通過poi完成excel

前端

1、按鈕

              <el-buttontype="text"size="mini"@click="handleExport">導出</el-button>

2、方法

 //導出async handleExport() {if (!this.activityId) {this.$message.warning('活動ID不存在');return;}try {this.loading = true;const res = await exportSignSheet({activityId: this.activityId});//文件名let fileName = `活動簽到表_${this.activity?.activityTitle || '未知活動'}_${Date.now()}.xlsx`;//創建下載鏈接const blob = new Blob([res.data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});const url = window.URL.createObjectURL(blob);const link = document.createElement('a');link.href = url;link.download = fileName;document.body.appendChild(link);link.click();// 清理setTimeout(() => {document.body.removeChild(link);window.URL.revokeObjectURL(url);}, 100);this.$message.success('簽到表下載已開始');} catch (error) {console.error('導出失敗:', error);this.$message.error(`導出失敗: ${error.message}`);} finally {this.loading = false;}},

3、路由

export function exportSignSheet(data) {return request({url: '/association/detail/signSheet',//后端接口地址method: 'post',data,responseType: 'blob',//一定要指定類型為blob// 確保能獲取到headerstransformResponse: (data, headers) => {return {data,headers: headers || {}};}});
}

4、后端

      <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>4.1.2</version></dependency>
 @PostMapping("/signSheet")public void exportSignSheet(@RequestBody Map<String, Long> request, // 前端參數HttpServletResponse response) throws IOException {// 設置CORS頭(如果存在跨域問題)response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");// 1. 驗證活動IDLong activityId = request.get("activityId");if (activityId == null) {throw new IllegalArgumentException("活動ID不能為空");}// 2. 獲取活動完整信息(復用已有查詢方法)ActivityDetailVO activityVO = activityDetailService.getActivityDetail(activityId);if (activityVO == null) {throw new RuntimeException("活動不存在或已刪除");}// 3. 處理文件名String activityName = activityVO.getActivityTitle() != null ? activityVO.getActivityTitle() : "未知活動";String fileName = "活動簽到表_" + activityName + "_" + System.currentTimeMillis() + ".xlsx";// 4. 處理文件名避免亂碼String encodedFileName = URLEncoder.encode(fileName, "UTF-8").replace("+", "%20"); // 替換空格編碼// 5. 設置請求頭        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setHeader("Content-Disposition","attachment; filename=\"" + encodedFileName + "\"; filename*=UTF-8''" + encodedFileName);// 6. 創建并填充Exceltry (XSSFWorkbook workbook = new XSSFWorkbook()) {buildExcelContent(workbook, activityVO);//可以將文件存入本地進行調試//workbook.write(Files.newOutputStream(Paths.get("debug.xlsx")));workbook.write(response.getOutputStream());} catch (Exception e) {response.reset();response.setContentType("application/json");response.setCharacterEncoding("UTF-8");response.getWriter().write("{\"error\":\"" + e.getMessage() + "\"}");}}
private void buildExcelContent(XSSFWorkbook workbook, ActivityDetailVO activityVO) {Sheet sheet = workbook.createSheet("活動簽到表");sheet.setDefaultColumnWidth(15);// 創建樣式(保持不變)CellStyle titleStyle = createTitleStyle(workbook);CellStyle borderStyle = createBorderStyle(workbook);CellStyle headerStyle = createHeaderStyle(workbook);// 標題行(第0行)- 修復合并單元格邊框Row titleRow = sheet.createRow(0);Cell titleCell = titleRow.createCell(0);titleCell.setCellValue("活動簽到表");CellRangeAddress titleRegion = new CellRangeAddress(0, 0, 0, 5);sheet.addMergedRegion(titleRegion);titleCell.setCellStyle(titleStyle);setRegionBorder(BorderStyle.THIN, titleRegion, sheet, workbook); // 新增:設置合并區域邊框// 第二行:活動名稱(第1行)- 修復合并單元格邊框Row nameRow = sheet.createRow(1);Cell nameCell = nameRow.createCell(0);nameCell.setCellValue(activityVO.getActivityTitle() != null ? activityVO.getActivityTitle() : "未設置");CellRangeAddress nameRegion = new CellRangeAddress(1, 1, 0, 5);sheet.addMergedRegion(nameRegion);nameCell.setCellStyle(borderStyle);setRegionBorder(BorderStyle.THIN, nameRegion, sheet, workbook); // 新增:設置合并區域邊框// 第三行:活動地點和活動時間(第2行)- 修復合并單元格邊框Row locationTimeRow = sheet.createRow(2);// 活動地點標簽Cell locationLabelCell = locationTimeRow.createCell(0);locationLabelCell.setCellValue("活動地點");locationLabelCell.setCellStyle(borderStyle);// 活動地點內容(合并1-2列)Cell locationCell = locationTimeRow.createCell(1);locationCell.setCellValue(getFirstActivityLocation(activityVO));CellRangeAddress locationRegion = new CellRangeAddress(2, 2, 1, 2);sheet.addMergedRegion(locationRegion);locationCell.setCellStyle(borderStyle);setRegionBorder(BorderStyle.THIN, locationRegion, sheet, workbook); // 新增:設置合并區域邊框// 活動時間標簽Cell timeLabelCell = locationTimeRow.createCell(3);timeLabelCell.setCellValue("活動時間");timeLabelCell.setCellStyle(borderStyle);// 活動時間內容(合并4-5列)Cell timeCell = locationTimeRow.createCell(4);timeCell.setCellValue(formatActivityTimeRange(activityVO.getStartTime(), activityVO.getEndTime()));CellRangeAddress timeRegion = new CellRangeAddress(2, 2, 4, 5);sheet.addMergedRegion(timeRegion);timeCell.setCellStyle(borderStyle);setRegionBorder(BorderStyle.THIN, timeRegion, sheet, workbook); // 新增:設置合并區域邊框// 第四行:活動召集人和報名人數(第3行)- 修復合并單元格邊框Row organizerCountRow = sheet.createRow(3);// 活動召集人標簽Cell organizerLabelCell = organizerCountRow.createCell(0);organizerLabelCell.setCellValue("活動召集人");organizerLabelCell.setCellStyle(borderStyle);// 活動召集人內容(合并1-2列)Cell organizerCell = organizerCountRow.createCell(1);organizerCell.setCellValue(activityVO.getEntrepreneurNames() != null ? activityVO.getEntrepreneurNames() : "未設置");CellRangeAddress organizerRegion = new CellRangeAddress(3, 3, 1, 2);sheet.addMergedRegion(organizerRegion);organizerCell.setCellStyle(borderStyle);setRegionBorder(BorderStyle.THIN, organizerRegion, sheet, workbook); // 新增:設置合并區域邊框// 報名人數標簽Cell countLabelCell = organizerCountRow.createCell(3);countLabelCell.setCellValue("報名人數");countLabelCell.setCellStyle(borderStyle);// 報名人數內容(合并4-5列)Cell countCell = organizerCountRow.createCell(4);countCell.setCellValue(String.valueOf(getParticipantCount(activityVO)));CellRangeAddress countRegion = new CellRangeAddress(3, 3, 4, 5);sheet.addMergedRegion(countRegion);countCell.setCellStyle(borderStyle);setRegionBorder(BorderStyle.THIN, countRegion, sheet, workbook); // 新增:設置合并區域邊框// 第五行:簽到處(第4行)- 修復合并單元格邊框Row signRow = sheet.createRow(4);Cell signCell = signRow.createCell(0);signCell.setCellValue("簽到處");CellRangeAddress signRegion = new CellRangeAddress(4, 4, 0, 5);sheet.addMergedRegion(signRegion);signCell.setCellStyle(borderStyle);setRegionBorder(BorderStyle.THIN, signRegion, sheet, workbook); // 新增:設置合并區域邊框// 表頭行(第5行)- 保持不變Row headerRow = sheet.createRow(5);String[] headers = {"序號", "報名人", "聯系電話", "序號", "報名人", "聯系電話"};for (int i = 0; i < headers.length; i++) {Cell cell = headerRow.createCell(i);cell.setCellValue(headers[i]);cell.setCellStyle(headerStyle);}}// 帶邊框的樣式private CellStyle createBorderStyle(XSSFWorkbook workbook) {CellStyle style = workbook.createCellStyle();// 設置邊框style.setBorderTop(BorderStyle.THIN);style.setBorderBottom(BorderStyle.THIN);style.setBorderLeft(BorderStyle.THIN);style.setBorderRight(BorderStyle.THIN);// 設置邊框顏色(黑色)style.setTopBorderColor(IndexedColors.BLACK.getIndex());style.setBottomBorderColor(IndexedColors.BLACK.getIndex());style.setLeftBorderColor(IndexedColors.BLACK.getIndex());style.setRightBorderColor(IndexedColors.BLACK.getIndex());// 居中對齊style.setAlignment(HorizontalAlignment.CENTER);style.setVerticalAlignment(VerticalAlignment.CENTER);return style;}// 標題樣式(繼承邊框樣式并加大字體)private CellStyle createTitleStyle(XSSFWorkbook workbook) {CellStyle style = createBorderStyle(workbook);Font font = workbook.createFont();font.setBold(true);font.setFontHeightInPoints((short) 16);style.setFont(font);return style;}// 表頭樣式(繼承邊框樣式并加粗)private CellStyle createHeaderStyle(XSSFWorkbook workbook) {CellStyle style = createBorderStyle(workbook);Font font = workbook.createFont();font.setBold(true);style.setFont(font);return style;}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/95528.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/95528.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/95528.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

JMeter性能測試詳細版(適合0基礎小白學習--非常詳細)

01性能測試的概念 02性能測試的概念 基準測試 負載測試 穩定性測試 其他&#xff1a;并發測試、壓力測試、回歸測試等 壓力測試就是在系統強負載的情況下&#xff0c;是否會出現功能隱患問題&#xff0c;出現問題后是否可以盡快恢復 負載測試和壓力測試的區別: 1,核心目標不…

QT6(創建第一個QT項目)

編寫第一個QT項目 QT官網 安裝完QT后的界面 創建第一個項目 這里我們選擇第一個就好 下一步 下一步 選擇CMake&#xff0c;QMake是QT的CMAKE&#xff08;現在官方自己都不推薦了&#xff09; 下一步 選擇QWidget我們先創建一個最簡單的窗口程序 QMainWindow&#xff1a;主窗…

Golang指針操作

在 Go 語言&#xff08;Golang&#xff09;中&#xff0c;* 和 & 是與指針相關的兩個重要操作符。 理解它們對于掌握 Go 的內存管理和函數參數傳遞機制非常關鍵。 文章目錄一、& 操作符&#xff1a;取地址&#xff08;Address-of&#xff09;示例&#xff1a;二、* 操…

微服務從0到1

微服務從0到1實施步驟與注意事項一、核心實施步驟??需求分析與架構設計??明確業務邊界?&#xff1a;根據業務模塊&#xff08;如用戶管理、訂單系統&#xff09;劃分服務職責&#xff0c;避免服務職責重疊或耦合?。?定義接口契約?&#xff1a;通過 OpenAPI/Swagger 規范…

小程序排名優化:功能迭代如何助力排名攀升

小程序的功能不是一成不變的&#xff0c;持續的功能迭代不僅能滿足用戶不斷變化的需求&#xff0c;也是提升排名的重要途徑。平臺更傾向于推薦那些不斷更新、功能完善的小程序&#xff0c;因為它們能為用戶提供更優質的服務。合理規劃功能迭代方向和節奏&#xff0c;能讓小程序…

Unity TextMeshPro(二)優化

文章目錄前言一、字體打包優化二、ab打包冗余1、問題1、解決方法三、字體靜態優化四、擴展總結前言 優化TextMeshPro包體大小的方法記錄。 一、字體打包優化 游戲開發階段通常使用Fast打包方式&#xff0c;在正式項目發布的時候需要切換一下打包方式&#xff0c;重新將字體打…

C++ 之 【簡介 set、multiset、map、multimap 的使用】

目錄 1.序列式、關聯式容器 2.鍵值對 3.set 3.1set的簡介 3.2set的常用函數 4.multiset 5.map 5.1map的簡介 5.2map的常用函數 6.multimap 7.練習題 1.序列式、關聯式容器 vector、deque、list、forward_list、array等是CSTL中的序列式容器 其核心特性是 元素按插入…

數據結構——排序(升級篇:快速排序、堆排序、希爾排序、計數排序)

1. 快速排序&#xff08;Quick Sort&#xff09; 原理&#xff1a; 選擇一個基準值&#xff08;pivot&#xff09;將數組分成兩部分&#xff1a;小于 pivot 的放左邊&#xff0c;大于 pivot 的放右邊。然后遞歸處理 工作過程示例&#xff1a; 示例數組&#xff1a;[5, 3, 8, 4,…

C++:淺嘗gdb

hp window11 wsl ubuntu what is gdb&#xff1f; GNU調試器&#xff08;英語&#xff1a;GNU Debugger&#xff0c;縮寫&#xff1a;GDB&#xff09;&#xff0c;是GNU軟件系統中的標準調試器&#xff0c;此外GDB也是個具有移攜性的調試器&#xff0c;經過移攜需求的調修與…

Android輸入法一些常用的命令

Android開發過程可能會遇到Android輸入法異常的問題&#xff0c;可以通過如下命令來查看和修改系統的輸入法。方便調試。 獲取當下系統的所有輸入法 adb shell ime list獲取當前的可用輸入法 adb shell ime list -s獲取當前的輸入法 adb shell settings get secure default_inp…

Sklearn 機器學習 手寫數字識別 加載并查看數據

??親愛的技術愛好者們,熱烈歡迎來到 Kant2048 的博客!我是 Thomas Kant,很開心能在CSDN上與你們相遇~?? 本博客的精華專欄: 【自動化測試】 【測試經驗】 【人工智能】 【Python】 Sklearn 機器學習 手寫數字識別:加載并查看數據 在機器學習入門案例中,手寫數字識別…

衛星通信鏈路預算之七:上行載噪比計算

在前面的文章中我們介紹了衛星通信鏈路計算的基礎知識&#xff0c;包括&#xff1a; 信噪比分配&#xff1b; 帶寬和功帶平衡原則&#xff1b; EIRP和G/T&#xff1b; 輸入回退&#xff1b; 輸入飽和通量密度SFD&#xff1b; 輸出回退&#xff1b; 這次我們正式進入正題…

一文讀懂PDB格式

最近在做分子對接和分子模擬&#xff0c;涉及到了一些盲區&#xff0c;必去pdb文件是按照列位數儲存信息的&#xff0c;跟其他文件的空格或者制表符分割很不同&#xff0c;所以也可能出現一些錯誤&#xff0c;比如信息錯位&#xff0c;因此有必要了深入解下結構相關的格式pdb、…

進階:PGCE中級專家認證精要

PGCE中級認證的核心價值技術深度&#xff1a;掌控未來生態PostgreSQL不僅是傳統關系型數據庫的標桿&#xff0c;更是云原生、AI大模型訓練、物聯網平臺等前沿場景的核心支撐。通過PGCE認證&#xff0c;你將掌握&#xff1a;萬億級數據性能調優&#xff1a;從查詢優化器原理到執…

AI增強SEO關鍵詞表現

內容概要 隨著人工智能技術的不斷演進&#xff0c;其在搜索引擎優化領域展現出顯著潛力&#xff0c;尤其在關鍵詞表現優化方面發揮著核心作用。本文將從基礎概念入手&#xff0c;系統探討AI如何智能提升關鍵詞的搜索可見性、流量吸引力和轉化效率&#xff0c;從而驅動整體SEO策…

PG靶機 - PayDay

一、 初步偵察與服務探測 1.1 端口掃描與服務識別 首先&#xff0c;對目標主機 192.168.163.39 進行一次全面的端口掃描&#xff0c;以識別其上運行的各項服務。 sudo nmap 192.168.163.39 -p- --min-rate5000 -A圖 1: Nmap 掃描結果&#xff0c;顯示開放 80、445 和 995 等端口…

MySQLl中OFFSET 的使用方法

MySQLl中OFFSET 的使用方法基本語法SELECT column1, column2, ... FROM table_name LIMIT number_of_rows OFFSET offset_value;number_of_rows&#xff1a;指定返回的記錄數量。offset_value&#xff1a;從第幾條記錄開始返回&#xff08;偏移量從 0 開始計數&#xff09;。示…

監管科技(RegTech)應用:技術驅動的合規革命

目錄 監管科技(RegTech)應用:技術驅動的合規革命 1. 監管科技革命:數字化合規新范式 2. 技術架構全景 2.1 現代RegTech架構 2.2 合規效率公式 3. 核心技術實現 3.1 智能合約自動化合規 3.2 AI驅動的風險監測引擎 4. 核心應用場景 4.1 KYC/AML全流程自動化 4.2 實時交易監控系…

解決SQL Server連接失敗:Connection refused: connect

今天創建數據庫&#xff0c;本地連接SQL Server報錯&#xff1a;“通過端口 1433 連接到主機 127.0.0.1 的 TCP/IP 連接失敗。錯誤&#xff1a;Connection refused: connect”報錯圖如下&#xff1a;查了一圈&#xff0c;問題出在&#xff1a;TCP/IP 沒啟用。如果問題和我一樣&…

Windows bypassUAC 提權技法詳解(一)

引言 用戶賬戶控制&#xff08;User Account Control, 簡稱 UAC&#xff09;是微軟自 Windows Vista 起引入的一項安全功能&#xff0c;旨在通過要求用戶在執行需要管理員權限的操作時進行確認&#xff0c;從而防止未經授權的系統更改。UAC 的設計初衷是提高系統安全性&#xf…