Spring Boot集成EasyExcel

1. 初始化Spring Boot項目

首先,使用Spring Initializr(https://start.spring.io/)生成一個基本的Spring Boot項目。選擇以下依賴項:

  • Spring Web
  • Lombok (用于減少樣板代碼)
  • SLF4J (用于日志記錄)

2. 添加依賴

在你的pom.xml文件中添加EasyExcel的Maven依賴。確保版本號是最新的,你可以訪問Maven倉庫來獲取最新版。

<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>最新的版本號</version>
</dependency>

3. 創建實體類

假設我們需要處理一個用戶信息表,包含姓名和年齡兩個字段。以下是實體類的設計,并使用Lombok簡化代碼:

package com.example.demo.model;import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;// 使用@Data注解自動生成getter、setter等方法
@Data
public class UserData {// 指定Excel列標題為“姓名”@ExcelProperty("姓名")private String name; // 用戶姓名// 指定Excel列標題為“年齡”@ExcelProperty("年齡")private Integer age; // 用戶年齡
}

4. 創建監聽器類

創建一個監聽器類來處理每一行的數據,并在服務類中調用它。我們使用@Slf4j注解簡化日志記錄:

package com.example.demo.listener;import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.example.demo.model.UserData;
import lombok.extern.slf4j.Slf4j;import java.util.ArrayList;
import java.util.List;@Slf4j // 使用@Slf4j注解簡化日志記錄
public class UserDataListener extends AnalysisEventListener<UserData> {private final List<UserData> dataList = new ArrayList<>(); // 存儲讀取的數據/*** 當解析一行數據時調用* @param userData 解析得到的用戶數據* @param analysisContext 上下文對象*/@Overridepublic void invoke(UserData userData, AnalysisContext analysisContext) {dataList.add(userData); // 將每一行的數據添加到列表中log.info("讀取到一條數據: {} {}", userData.getName(), userData.getAge()); // 日志記錄}/*** 所有數據解析完成后調用* @param analysisContext 上下文對象*/@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {log.info("所有數據解析完成"); // 數據解析完成后記錄日志}/*** 獲取讀取的數據列表* @return 讀取的數據列表*/public List<UserData> getDataList() {return dataList; // 返回讀取的數據列表}
}

5. 實現服務類

編寫一個服務類來實現數據的讀寫操作,并增加異常處理和日志記錄。我們將在此處添加分頁功能,以確保當單個頁面數據達到一定量時重新生成新的頁面進行寫入:

package com.example.demo.service;import com.alibaba.excel.EasyExcel;
import com.example.demo.listener.UserDataListener;
import com.example.demo.model.UserData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.List;@Slf4j // 使用@Slf4j注解簡化日志記錄
@Service
public class ExcelService {private static final int PAGE_SIZE = 100; // 每頁最大數據條數/*** 寫入Excel文件* @param filePath 文件路徑* @param data 要寫入的數據列表*/public void writeExcel(String filePath, List<UserData> data) {try {log.info("開始寫入Excel文件: {}", filePath); // 記錄日志int totalRows = data.size();int totalPages = (int) Math.ceil((double) totalRows / PAGE_SIZE);for (int page = 0; page < totalPages; page++) {int fromIndex = page * PAGE_SIZE;int toIndex = Math.min(fromIndex + PAGE_SIZE, totalRows);List<UserData> currentPageData = data.subList(fromIndex, toIndex);String sheetName = "用戶信息" + (page + 1); // 設置工作表名稱// 開始寫入Excel文件EasyExcel.write(filePath, UserData.class).sheet(sheetName) // 設置工作表名稱.doWrite(currentPageData); // 執行寫入操作log.info("寫入第 {} 頁數據完成", page + 1); // 寫入完成后記錄日志}log.info("寫入Excel文件完成"); // 寫入完成后記錄日志} catch (Exception e) {log.error("寫入Excel失敗", e); // 記錄錯誤日志}}/*** 讀取所有工作表的Excel文件* @param inputStream 輸入流* @return 讀取的數據列表*/public List<UserData> readAllSheets(InputStream inputStream) {List<UserData> allData = new ArrayList<>();try {log.info("開始讀取所有工作表的Excel文件"); // 記錄日志// 獲取Excel文件中的所有Sheet信息List<String> sheetNames = EasyExcel.read(inputStream).excelExecutor().sheetList().get();for (String sheetName : sheetNames) {log.info("開始讀取工作表: {}", sheetName);UserDataListener listener = new UserDataListener();// 執行讀取操作EasyExcel.read(inputStream, UserData.class, listener).sheet(sheetName) // 指定工作表名稱.doRead(); // 執行讀取操作// 處理listener.getDataList()allData.addAll(listener.getDataList());log.info("讀取工作表 {} 完成", sheetName);}log.info("讀取所有工作表的Excel文件完成"); // 讀取完成后記錄日志} catch (Exception e) {log.error("讀取所有工作表的Excel失敗", e); // 記錄錯誤日志}return allData;}/*** 讀取特定工作表的Excel文件* @param filePath 文件路徑* @param sheetIndex 工作表索引(從0開始)*/public void readSpecificSheet(String filePath, int sheetIndex) {try {log.info("開始讀取特定工作表的Excel文件: {}, Sheet Index: {}", filePath, sheetIndex); // 記錄日志UserDataListener listener = new UserDataListener();// 執行讀取操作EasyExcel.read(filePath, UserData.class, listener).sheet(sheetIndex) // 指定工作表索引.doRead(); // 執行讀取操作// 處理listener.getDataList()for (UserData userData : listener.getDataList()) {log.info("{} {}", userData.getName(), userData.getAge()); // 記錄每條數據的日志}log.info("讀取特定工作表的Excel文件完成"); // 讀取完成后記錄日志} catch (Exception e) {log.error("讀取特定工作表的Excel失敗", e); // 記錄錯誤日志}}/*** 使用模板填充數據并生成新的Excel文件* @param templateFilePath 模板文件路徑* @param outputFilePath 輸出文件路徑* @param data 要填充的數據列表*/public void fillTemplate(String templateFilePath, String outputFilePath, List<UserData> data) {try {log.info("開始使用模板填充數據: {}, 輸出文件路徑: {}", templateFilePath, outputFilePath); // 記錄日志// 使用模板填充數據EasyExcel.write(outputFilePath).withTemplate(templateFilePath).sheet().doFill(data);log.info("模板填充數據完成"); // 填充完成后記錄日志} catch (Exception e) {log.error("模板填充數據失敗", e); // 記錄錯誤日志}}/*** 下載文件并在失敗時返回JSON* @param response HttpServletResponse 對象* @throws IOException 如果寫入文件失敗*/public void downloadFailedUsingJson(HttpServletResponse response) throws IOException {try {response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("utf-8");// 這里URLEncoder.encode可以防止中文亂碼String fileName = URLEncoder.encode("測試", "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");List<UserData> data = new ArrayList<>();for (int i = 1; i <= 100; i++) { // 假設我們有100條數據data.add(new UserData().setName("張三" + i).setAge(20 + i % 50));}EasyExcel.write(response.getOutputStream(), UserData.class).autoCloseStream(Boolean.FALSE).sheet("模板").doWrite(data);} catch (Exception e) {// 重置responseresponse.reset();response.setContentType("application/json");response.setCharacterEncoding("utf-8");Map<String, String> map = Map.of("status", "failure", "message", "下載文件失敗: " + e.getMessage());response.getWriter().println(JSON.toJSONString(map));}}
}
}

6. 創建控制器類

為了方便測試,我們可以創建一個簡單的控制器類來調用服務類中的方法:

package com.example.demo.controller;import com.example.demo.service.ExcelService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@Slf4j // 使用@Slf4j注解簡化日志記錄
@RestController
@RequestMapping("/excel")
public class ExcelController {@Autowiredprivate ExcelService excelService; // 自動注入ExcelService/*** 文件上傳* @param file 上傳的文件* @return 成功消息* @throws IOException 如果讀取文件失敗*/@PostMapping("upload")@ResponseBodypublic String upload(@RequestParam("file") MultipartFile file) throws IOException {InputStream inputStream = file.getInputStream();List<UserData> data = excelService.readAllSheets(inputStream);log.info("成功讀取到 {} 條數據", data.size());return "success";}/*** 文件下載并且失敗的時候返回json(默認失敗了會返回一個有部分數據的Excel)** @param response HttpServletResponse 對象* @throws IOException 如果寫入文件失敗*/@GetMapping("downloadFailedUsingJson")public void downloadFailedUsingJson(HttpServletResponse response) throws IOException {excelService.downloadFailedUsingJson(response);}/*** 寫入Excel文件* @param filePath 文件路徑* @return 成功消息*/@GetMapping("/write")public String writeExcel(@RequestParam String filePath) {log.info("準備寫入Excel文件: {}", filePath); // 記錄日志List<UserData> data = new ArrayList<>();for (int i = 1; i <= 500; i++) { // 假設我們有500條數據data.add(new UserData().setName("張三" + i).setAge(20 + i % 50));}excelService.writeExcel(filePath, data); // 調用寫入方法log.info("寫入Excel文件完成"); // 返回成功消息return "寫入Excel成功"; // 返回成功消息}/*** 讀取所有工作表的Excel文件* @param filePath 文件路徑* @return 成功消息*/@GetMapping("/read/allSheets")public String readAllSheets(@RequestParam String filePath) {log.info("準備讀取所有工作表的Excel文件: {}", filePath); // 記錄日志excelService.readAllSheets(filePath); // 調用讀取方法log.info("讀取所有工作表的Excel文件完成"); // 返回成功消息return "讀取所有工作表的Excel成功"; // 返回成功消息}/*** 讀取特定工作表的Excel文件* @param filePath 文件路徑* @param sheetIndex 工作表索引(從0開始)* @return 成功消息*/@GetMapping("/read/specificSheet")public String readSpecificSheet(@RequestParam String filePath, @RequestParam int sheetIndex) {log.info("準備讀取特定工作表的Excel文件: {}, Sheet Index: {}", filePath, sheetIndex); // 記錄日志excelService.readSpecificSheet(filePath, sheetIndex); // 調用讀取方法log.info("讀取特定工作表的Excel文件完成"); // 返回成功消息return "讀取特定工作表的Excel成功"; // 返回成功消息}/*** 使用模板填充數據并生成新的Excel文件* @param templateFilePath 模板文件路徑* @param outputFilePath 輸出文件路徑* @return 成功消息*/@GetMapping("/fill/template")public String fillTemplate(@RequestParam String templateFilePath, @RequestParam String outputFilePath) {log.info("準備使用模板填充數據: {}, 輸出文件路徑: {}", templateFilePath, outputFilePath); // 記錄日志List<UserData> data = new ArrayList<>();for (int i = 1; i <= 500; i++) { // 假設我們有500條數據data.add(new UserData().setName("張三" + i).setAge(20 + i % 50));}excelService.fillTemplate(templateFilePath, outputFilePath, data); // 調用模板填充方法log.info("模板填充數據完成"); // 返回成功消息return "模板填充數據成功"; // 返回成功消息}
}

7. 異常處理與日志記錄

在實際應用中,建議增加更多的異常處理邏輯和日志記錄,以便更好地調試和維護。我們已經在服務類中添加了基本的日志記錄和異常處理機制。

全局異常處理

你可以在項目中添加全局異常處理器來捕獲和處理未處理的異常:

package com.example.demo.exception;import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import lombok.extern.slf4j.Slf4j;@Slf4j // 使用@Slf4j注解簡化日志記錄
@ControllerAdvice
public class GlobalExceptionHandler {/*** 處理所有異常* @param e 異常對象* @return 錯誤響應*/@ExceptionHandler(Exception.class)public ResponseEntity<String> handleException(Exception e) {log.error("發生錯誤: ", e); // 記錄錯誤日志return new ResponseEntity<>("發生錯誤: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); // 返回錯誤消息}
}

8. 啟動應用程序

確保你的主應用程序類正確配置:

package com.example.demo;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import lombok.extern.slf4j.Slf4j;@SpringBootApplication
@Slf4j // 使用@Slf4j注解簡化日志記錄
public class DemoApplication {/*** 主函數,啟動Spring Boot應用* @param args 命令行參數*/public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args); // 啟動Spring Boot應用log.info("Spring Boot應用已啟動"); // 記錄啟動日志}
}

9. 測試

啟動應用程序后,你可以通過瀏覽器或Postman等工具訪問以下URL來測試Excel的讀寫功能:

  • 寫入Excel:http://localhost:8080/excel/write?filePath=/path/to/your/output.xlsx
  • 讀取Excel:http://localhost:8080/excel/read?filePath=/path/to/your/input.xlsx

總結

以上是完整的Spring Boot集成EasyExcel的詳細步驟和代碼示例,包括詳細的注釋以及實現了當單個頁面數據達到一定量時重新生成新的頁面進行寫入的功能。

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

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

相關文章

(2025|ICLR|廈大華為,LoSA,基于表示互信息的動態層級稀疏率,基于重構誤差的秩分配)LLM 的動態低秩稀疏自適應

Dynamic Low-Rank Sparse Adaptation for Large Language Models 目錄 1. 引言 1.1 關鍵詞 2. 方法 2.1 預備知識 2.2 層級稀疏率確定 2.3 稀疏感知的秩分配 2.4 動態稀疏與適配 3. 實驗 3.1 實驗設置 3.2 語言建模 3.3 零樣本任務 3.4 N:M 稀疏性 3.5 消融實驗 …

p5.js:sound(音樂)可視化,動畫顯示音頻高低變化

本文通過4個案例介紹了使用 p5.js 進行音樂可視化的實踐&#xff0c;包括將音頻振幅轉化為圖形、生成波形圖。 承上一篇&#xff1a;vite&#xff1a;初學 p5.js demo 畫圓圈 cd p5-demo copy .\node_modules\p5\lib\p5.min.js . copy .\node_modules\p5\lib\addons\p5.soun…

linux 進程和計劃管理

查看進程 在Linux系統中&#xff0c;有多個命令可以用來查看進程 以下是一些常用的命令&#xff1a; ps命令&#xff1a;用于查看當前系統中的進程狀態。 基本用法&#xff1a;ps -ef&#xff0c;該命令會以完整格式顯示所有進程的詳細信息&#xff0c;包括用戶ID、進程ID、父…

DeepSeek 多模態大模型 Janus-Pro 本地部署教程

下載模型倉庫 git clone https://github.com/deepseek-ai/Janus.git 國內下載倉庫失敗時&#xff0c;可以使用以下代理&#xff1a; git clone https://github.moeyy.xyz/https://github.com/deepseek-ai/Janus.git 準備 Conda 3.12 虛擬環境 conda create --name deepseek7B p…

Qt開源控件庫(qt-material-widgets)的編譯及使用

項目簡介 qt-material-widgets是一個基于 Qt 小部件的 Material Design 規范實現。 項目地址 項目地址&#xff1a;qt-material-widgets 本地構建環境 Win11 家庭中文版 VS2019 Qt5.15.2 (MSVC2019) 本地構建流程 克隆后的目錄結構如圖&#xff1a; 直接使用Qt Crea…

ARM 嵌入式處理器內核與架構深度剖析(2): ARM 處理器架構剖析

目錄 一、ARM處理器架構剖析 1.1. 指令集架構&#xff08;ISA&#xff09; 1.2. 寄存器集 1.3. 存儲模型 1.4. 異常模型 二、架構設計精要 2.1 處理器模式與特權分級 2.2 寄存器銀行化技術 2.3 指令集演化 三、微架構核心技術 3.1 流水線創新 3.2 內存子系統 3.3 …

Flutter 按鈕組件 TextButton 詳解

目錄 1. 引言 2. TextButton 的基本用法 3. 主要屬性 4. 自定義按鈕樣式 4.1 修改文本顏色 4.2 添加背景色 4.3 修改按鈕形狀和邊距 4.4 樣式定制 5. 高級應用技巧 5.1 圖標文本組合 5.2 主題統一配置 5.3 動態交互 6. 性能優化與注意事項 6.1 點擊區域優化 6.…

std::ranges::views::split, lazy_split, std::ranges::split_view, lazy_split_view

std::ranges::views::split, std::ranges::split_view C20 中引入的用于分割范圍&#xff08;range&#xff09;的組件&#xff0c;允許將輸入范圍按特定分隔符或條件分割成多個子范圍。以下是詳細說明和示例&#xff1a; 基本概念 1. 功能 分割范圍&#xff1a;將輸入范圍&…

c++ constraints與concepts使用筆記

c constraints與concepts使用筆記 1. 模板參數缺乏約束的問題2. Concepts 基本概念3. Concept 的定義與使用4. requires 表達式詳解5. requires 從句 vs requires 表達式完整示例&#xff1a;約束矩陣運算 1. 模板參數缺乏約束的問題 問題分析&#xff1a; 傳統模板參數沒有語…

Qt | 屏幕截圖實現

01 全局截屏控件 1. 鼠標右鍵彈出菜單。 2. 支持全局截屏。 3. 支持局部截屏。 4. 支持截圖區域拖動。 5. 支持圖片另存為。 演示 點擊按鈕即可截圖 源碼: 通過網盤分享的文件:screenwidget屏幕截圖 鏈接: https://pan.baidu.com/s/1PZfQlUXNIoZKEfEtLNV2jQ?pwd=5jsg 提…

2.angular指令

初級使用可以查看視頻 參考手冊 注意 像ng-class,ng-value,ng-href等這些&#xff0c;很多都可以直接用class“{{}}” 原生寫&#xff0c;為啥還出這些指令&#xff0c;是因為原生的比如剛一進頁面就先出現表達式了&#xff0c;瀏覽器走到這里的時候才去解析&#xff0c;給用戶…

CTFshow 【WEB入門】信息搜集 【VIP限免】 web1-web17

CTFshow 【 WEB入門】、【VIP限免】 web1 ----源碼泄露 首先第一步&#xff0c;看源代碼 web2----前臺JS繞過 簡單點擊查看不了源代碼&#xff0c;可以強制查看 比如 Ctrl Shift ICtrl U或者在url前加一個view-source: view-source:http://79999ca1-7403-46da-b25b-7ba9…

java 手搓一個http工具類請求傳body

import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets;public class HttpUtil {/*** JSON請求發起*/public static String httpJsonRequest(String requestUrl, String requestJson) {String responseJson &…

Spring boot3-WebClient遠程調用非阻塞、響應式HTTP客戶端

來吧&#xff0c;會用就行具體理論不討論 1、首先pom.xml引入webflux依賴 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId> </dependency> 別問為什么因為是響應式....…

寫了一個二叉樹構造函數和畫圖函數,方便debug

代碼 class TreeNode(object):def __init__(self, val, leftNone, rightNone):self.val valself.left leftself.right rightdef construct_tree(nodes):if not nodes:return Noneroot TreeNode(nodes[0])queue [root]index 1while index < len(nodes):node queue.p…

QT:串口上位機

創建工程 布局UI界面 設置名稱 設置數據 設置波特率 波特率默認9600 設置數據位 數據位默認8 設置停止位 設置校驗位 調整串口設置、接收設置、發送設置為Group Box 修改配置 QT core gui serialport 代碼詳解 mianwindow.h 首先在mianwindow.h當中定義一個串口指…

【Pandas】pandas Series asof

Pandas2.2 Series Time Series-related 方法描述Series.asfreq(freq[, method, how, …])用于將時間序列數據轉換為指定的頻率Series.asof(where[, subset])用于返回時間序列中指定索引位置的最近一個非缺失值 pandas.Series.asof pandas.Series.asof 方法用于返回時間序列…

沉浸式CSS學習路徑

好的!我將以魔法學院成長故事為框架,為您設計一套沉浸式CSS學習路徑。以下是敘事化學習提綱: 第一卷:像素學徒的覺醒 章節1:被封印的魔法書 發現HTML的"素顏"本質,通過<!DOCTYPE html>解除網頁封印用style標簽打開CSS魔法書,學會給文字穿上color斗篷和…

使用netlify部署github的vue/react項目或本地的dist,國內也可以正常訪問

提供簡潔的部署流程和豐富功能&#xff0c;如自定義域名、自動構建和服務器端功能。通過連接到 Git 倉庫實現持續部署&#xff0c;每次推送代碼都會自動構建和發布&#xff0c;支持無服務器函數&#xff0c;允許在前端項目中實現后端邏輯&#xff0c;提供直觀的用戶界面來管理和…

復現 MoGe

要復現 MoGe&#xff0c;以下給出一般性的復現訓練過程步驟示例&#xff09;的訓練過程&#xff0c;你可以參考以下步驟&#xff1a; 環境準備 安裝必要的深度學習框架&#xff0c;如 TensorFlow 或 PyTorch&#xff0c;以及相關的庫&#xff0c;例如用于數據處理的 NumPy、Pan…