Spring Boot中Excel處理完全指南:從基礎到高級實踐

Excel處理基礎知識

1.1 為什么需要在應用中處理Excel文件?

在企業應用開發中,Excel文件處理是一個非常常見的需求,主要用于以下場景:

數據導入:允許用戶通過Excel上傳批量數據到系統
數據導出:將系統數據導出為Excel供用戶下載分析
報表生成:生成復雜的報表并格式化為Excel
數據交換:作為不同系統間交換數據的媒介
批量數據處理:處理大量結構化數據

1.2 Java中的Excel處理庫介紹

Java中處理Excel文件的主要庫有以下幾種:

1.2.1 Apache POI

Apache POI是Java中使用最廣泛的Excel處理庫,提供了全面的API來創建、讀取和修改Office文檔。

優點:

功能全面,支持Excel所有功能
支持.xls (HSSF - Excel 97-2003)和.xlsx (XSSF - Excel 2007+)格式
社區活躍,文檔豐富
支持公式計算、圖表、合并單元格等高級功能
缺點:

API相對復雜
處理大文件時內存消耗大(尤其是XSSF)

1.2.2 EasyExcel

EasyExcel是阿里巴巴開源的Excel處理庫,基于POI,但做了大量優化。

優點:

內存占用低,使用SAX模式讀取,避免OOM
API簡單易用,注解驅動
讀寫速度快
適合處理大型Excel文件
缺點:

功能不如POI全面
靈活性相對較低

1.2.3 JExcel

JExcel是另一個處理Excel的Java庫。

優點:

API較簡單
速度較快
缺點:

僅支持舊版Excel (.xls)格式
不再積極維護
功能有限

1.2.4 Apache POI SXSSF

SXSSF是POI提供的一種流式處理模式,專為處理大型Excel文件設計。

優點:

大大降低內存占用
適合生成大型Excel文件
缺點:

僅支持寫入操作,不支持讀取
功能比XSSF受限

1.3 Spring Boot中集成Excel處理

Spring Boot本身不提供Excel處理功能,但可以輕松集成上述各種Excel處理庫。本指南將主要介紹:

如何在Spring Boot項目中集成Apache POI和EasyExcel
如何實現Excel導入導出的常見功能
如何處理常見問題和優化性能

Spring Boot中Excel處理完全指南:從基礎到高級實踐

在數據驅動的現代應用中,Excel處理能力是后端開發的必備技能。本文全面解析Spring Boot中Excel操作的12種核心技術方案。


一、基礎方案:Apache POI原生集成

1. 添加依賴

<dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>5.2.3</version>
</dependency>
<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.3</version>
</dependency>

2. 基礎讀寫操作

// 寫入Excel
public void writeExcel(List<User> users, String filePath) throws IOException {try (Workbook workbook = new XSSFWorkbook()) {Sheet sheet = workbook.createSheet("用戶表");// 創建表頭Row headerRow = sheet.createRow(0);headerRow.createCell(0).setCellValue("ID");headerRow.createCell(1).setCellValue("姓名");headerRow.createCell(2).setCellValue("年齡");// 填充數據int rowNum = 1;for (User user : users) {Row row = sheet.createRow(rowNum++);row.createCell(0).setCellValue(user.getId());row.createCell(1).setCellValue(user.getName());row.createCell(2).setCellValue(user.getAge());}// 自動調整列寬for (int i = 0; i < 3; i++) {sheet.autoSizeColumn(i);}try (FileOutputStream fos = new FileOutputStream(filePath)) {workbook.write(fos);}}
}// 讀取Excel
public List<User> readExcel(String filePath) throws IOException {List<User> users = new ArrayList<>();try (Workbook workbook = new XSSFWorkbook(new File(filePath))) {Sheet sheet = workbook.getSheetAt(0);Iterator<Row> rowIterator = sheet.iterator();// 跳過表頭if (rowIterator.hasNext()) rowIterator.next();while (rowIterator.hasNext()) {Row row = rowIterator.next();User user = new User();user.setId((long) row.getCell(0).getNumericCellValue());user.setName(row.getCell(1).getStringCellValue());user.setAge((int) row.getCell(2).getNumericCellValue());users.add(user);}}return users;
}

二、高效方案:EasyExcel處理百萬級數據

1. 添加依賴

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

2. 基于注解的實體映射

@Data
public class UserExcel {@ExcelProperty("ID")private Long id;@ExcelProperty("姓名")private String name;@ExcelProperty("年齡")private Integer age;@ExcelProperty(value = "創建時間", converter = LocalDateTimeConverter.class)private LocalDateTime createTime;
}// 自定義日期轉換器
public class LocalDateTimeConverter implements Converter<LocalDateTime> {@Overridepublic LocalDateTime convertToJavaData(ReadCellData<?> cellData) {return LocalDateTime.parse(cellData.getStringValue(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));}
}

3. 百萬數據導出(避免OOM)

@GetMapping("/exportBigData")
public void exportBigData(HttpServletResponse response) {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf-8");String fileName = URLEncoder.encode("百萬用戶數據", "UTF-8");response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");EasyExcel.write(response.getOutputStream(), UserExcel.class).sheet("用戶數據").doWrite(() -> {// 分頁查詢數據(每次查詢10000條)int page = 0;while (true) {Pageable pageable = PageRequest.of(page, 10000);Page<User> userPage = userRepository.findAll(pageable);if (userPage.isEmpty()) break;// 轉換數據List<UserExcel> data = userPage.getContent().stream().map(user -> {UserExcel excel = new UserExcel();BeanUtils.copyProperties(user, excel);return excel;}).collect(Collectors.toList());page++;return data;}return null;});
}

三、Web集成方案:文件上傳下載

1. 文件上傳解析

@PostMapping("/upload")
public String upload(@RequestParam("file") MultipartFile file) {if (file.isEmpty()) {return "請選擇文件";}try {List<User> users = EasyExcel.read(file.getInputStream()).head(User.class).sheet().doReadSync();userRepository.saveAll(users);return "導入成功,共處理數據: " + users.size() + "條";} catch (IOException e) {return "文件處理失敗: " + e.getMessage();}
}

2. 模板下載

@GetMapping("/downloadTemplate")
public void downloadTemplate(HttpServletResponse response) throws IOException {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf-8");String fileName = URLEncoder.encode("用戶導入模板", "UTF-8");response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");// 創建模板數據(帶下拉菜單)List<String> headers = Arrays.asList("ID", "姓名", "年齡", "部門");List<ExcelSelect> selects = Collections.singletonList(new ExcelSelect(3, Arrays.asList("研發部", "市場部", "財務部")));EasyExcel.write(response.getOutputStream()).head(headers).registerWriteHandler(new DropDownHandler(selects)) // 添加下拉菜單.sheet("模板").doWrite(Collections.emptyList());
}// 下拉菜單處理器
public class DropDownHandler implements SheetWriteHandler {private final List<ExcelSelect> selects;public DropDownHandler(List<ExcelSelect> selects) {this.selects = selects;}@Overridepublic void afterSheetCreate(WriteWorkbookContext context) {Sheet sheet = context.getWriteSheetHolder().getSheet();DataValidationHelper helper = sheet.getDataValidationHelper();for (ExcelSelect select : selects) {// 創建下拉數據源String range = "D2:D1048576"; // 示例:D列所有行CellRangeAddressList addressList = new CellRangeAddressList(1, 65535, select.getColIndex(), select.getColIndex());// 設置下拉選項DataValidationConstraint constraint = helper.createExplicitListConstraint(select.getOptions().toArray(new String[0]));DataValidation validation = helper.createValidation(constraint, addressList);// 應用驗證sheet.addValidationData(validation);}}
}

四、高級技巧:動態模板與復雜報表

1. 動態表頭生成

public void exportDynamicColumns(HttpServletResponse response, List<String> columns) {// 動態構建表頭List<List<String>> head = new ArrayList<>();for (String col : columns) {head.add(Collections.singletonList(col));}// 動態數據填充List<List<Object>> data = new ArrayList<>();for (User user : userRepository.findAll()) {List<Object> row = new ArrayList<>();for (String col : columns) {switch (col) {case "ID": row.add(user.getId()); break;case "姓名": row.add(user.getName()); break;case "部門": row.add(user.getDepartment()); break;// 更多字段處理...}}data.add(row);}// 導出EasyExcel.write(response.getOutputStream()).head(head).sheet("動態報表").doWrite(data);
}

2. 復雜報表合并單元格

public void exportComplexReport() {String fileName = "復雜報表.xlsx";try (ExcelWriter excelWriter = EasyExcel.write(fileName).build()) {WriteSheet writeSheet = EasyExcel.writerSheet("部門統計").build();// 設置合并策略excelWriter.registerWriteHandler(new CellMergeStrategy(Arrays.asList(new MergeRange(0, 0, 0, 3), // 第一行合并4列new MergeRange(1, 1, 0, 0),  // 第二行第一列new MergeRange(1, 1, 1, 3)   // 第二行后三列合并)));// 構建表頭List<List<String>> head = Arrays.asList(Collections.singletonList("公司年度報表"),Arrays.asList("部門", "Q1", "Q2", "Q3", "Q4"));// 填充數據List<List<Object>> data = new ArrayList<>();data.add(Arrays.asList("研發部", 150, 180, 200, 220));data.add(Arrays.asList("市場部", 120, 150, 180, 210));excelWriter.write(head, writeSheet);excelWriter.write(data, writeSheet);}
}// 自定義合并策略
public class CellMergeStrategy implements RowWriteHandler {private final List<MergeRange> mergeRanges;@Overridepublic void afterRowDispose(WriteSheetContext context) {Sheet sheet = context.getWriteSheetHolder().getSheet();for (MergeRange range : mergeRanges) {sheet.addMergedRegion(new CellRangeAddress(range.getFirstRow(), range.getLastRow(),range.getFirstCol(), range.getLastCol()));}}
}

五、性能優化與問題解決方案

1. 內存溢出解決方案

// 使用SXSSFWorkbook處理大數據
try (Workbook workbook = new SXSSFWorkbook(100)) { // 保持100行在內存中Sheet sheet = workbook.createSheet();// 寫入數據for (int i = 0; i < 1000000; i++) {Row row = sheet.createRow(i);// 填充單元格...// 定期刷新磁盤if (i % 1000 == 0) {((SXSSFSheet) sheet).flushRows(100);}}
}

2. 常見問題處理方案

問題類型解決方案
日期格式不一致自定義Converter統一處理日期格式
大文件導出超時分頁查詢+異步導出,前端輪詢結果
特殊字符(emoji)亂碼使用String sanitized = StringEscapeUtils.escapeHtml4(rawString)處理
公式計算使用FormulaEvaluator預處理公式結果
樣式丟失定義CellStyle緩存池避免重復創建
下拉菜單動態數據源使用DVConstraint.createFormulaListConstraint引用隱藏Sheet數據

3. Excel操作最佳實踐

  1. 讀寫分離原則

    • 讀操作:使用EasyExcel的監聽器模式(ReadListener
    • 寫操作:大數據用分頁寫入,小數據用全量寫入
  2. 資源管理三要素

    try (Workbook workbook = ...;InputStream is = ...) {// 操作邏輯
    } // 自動關閉資源
    
  3. 樣式復用技巧

    private CellStyle createHeaderStyle(Workbook workbook) {CellStyle style = workbook.createCellStyle();Font font = workbook.createFont();font.setBold(true);style.setFont(font);style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());style.setFillPattern(FillPatternType.SOLID_FOREGROUND);return style;
    }
    

六、擴展方案:集成第三方庫

1. JExcelAPI(適合.xls格式)

<dependency><groupId>net.sourceforge.jexcelapi</groupId><artifactId>jxl</artifactId><version>2.6.12</version>
</dependency>

2. Apache POI + JXLS模板引擎

<dependency><groupId>org.jxls</groupId><artifactId>jxls-poi</artifactId><version>2.12.0</version>
</dependency>
<dependency><groupId>org.jxls</groupId><artifactId>jxls-jexcel</artifactId><version>1.0.9</version>
</dependency>

模板示例(template.xlsx):

| 姓名 | 年齡 | 部門     |
|------|------|----------|
| ${u.name} | ${u.age} | ${u.department} |

Java代碼:

public void exportWithTemplate(HttpServletResponse response) throws IOException {try (InputStream is = getClass().getResourceAsStream("/template.xlsx");OutputStream os = response.getOutputStream()) {Context context = new Context();context.putVar("users", userRepository.findAll());JxlsHelper.getInstance().processTemplate(is, os, context);}
}

最佳實踐總結:對于中小數據量(<10萬行)推薦使用EasyExcel+注解方案;大數據場景采用POI的SXSSF模式;需要復雜報表時選擇JXLS模板引擎。始終記住:在Spring Boot中處理Excel,資源關閉和內存管理是成敗關鍵!

擴展學習

  • POI官方文檔
  • EasyExcel GitHub
  • JXLS模板語法

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

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

相關文章

Python編程基礎(四) | if語句

引言&#xff1a;很久沒有寫 Python 了&#xff0c;有一點生疏。這是學習《Python 編程&#xff1a;從入門到實踐&#xff08;第3版&#xff09;》的課后練習記錄&#xff0c;主要目的是快速回顧基礎知識。 練習1&#xff1a;條件測試 編寫一系列條件測試&#xff0c;將每個條…

使用pandas實現合并具有共同列的兩個EXCEL表

表1&#xff1a; 表2&#xff1a; 表1和表2&#xff0c;有共同的列“名稱”&#xff0c;而且&#xff0c;表1的內容&#xff08;行數&#xff09;<表2的行數。 目的&#xff0c;根據“名稱”列的對應內容&#xff0c;將表2列中的“所處行業”填寫到表1相應的位置。 實現代…

ERP學習-AP

業務需要。持續更新學習進度 借助網上零搭建平臺上手實操 這個是簡道云平臺頁面鏈接&#xff0c;登錄的化去手機號登錄 目前開始對應付模塊進行學習

Dify知識庫下載小程序

一、Dify配置 1.查看或創建知識庫的API 二、下載程序配置 1. 安裝依賴resquirements.txt ######requirements.txt##### flask2.3.3 psycopg2-binary2.9.9 requests2.31.0 python-dotenv1.0.0#####安裝依賴 pip3 install -r requirements.txt -i https://pypi.tuna.tsinghua.…

【PbstarAdmin】微前端架構下的高效后臺管理系統解決方案

如果你正在尋找一個高效、穩定、易于使用、易于擴展的管理后臺解決方案&#xff0c;PbstarAdmin 絕對值得一試。以下是它的在線演示和官方文檔地址&#xff0c;你可以先睹為快&#xff1a; 在線演示&#xff1a;http://pbstar-admin.pbstar.cn/官方文檔&#xff1a;http://pbs…

Java基礎之數組(附帶Comparator)

文章目錄 基礎概念可變參數組數組與ListComparator類1,基本概念2,使用Comparator的靜態方法&#xff08;Java 8&#xff09;3,常用Comparator方法4,例子 排序與查找數組復制其他 基礎概念 int[] anArray new int[10];只有創建對象時才會使用new關鍵字&#xff0c;所以數組是個…

Apache Doris 在數據倉庫中的作用與應用實踐

在當今數字化時代&#xff0c;企業數據呈爆炸式增長&#xff0c;數據倉庫作為企業數據管理和分析的核心基礎設施&#xff0c;其重要性不言而喻。而 Apache Doris&#xff0c;作為一款基于 MPP&#xff08;Massively Parallel Processing&#xff0c;大規模并行處理&#xff09;…

P1438 無聊的數列/P1253 扶蘇的問題

因為這兩天在寫線性代數的作業&#xff0c;沒怎么寫題…… P1438 無聊的數列 題目背景 無聊的 YYB 總喜歡搞出一些正常人無法搞出的東西。有一天&#xff0c;無聊的 YYB 想出了一道無聊的題&#xff1a;無聊的數列。。。 題目描述 維護一個數列 ai?&#xff0c;支持兩種操…

SpringBoot 自定義注解實現限流

SpringBoot 自定義注解實現限流 限流是為了防止服務器資源的過度消耗&#xff0c;通過一定的策略來控制訪問頻率&#xff0c;確保服務的高可用性和穩定性。其核心意義在于防止流量高峰時期接口過載&#xff0c;從而引起服務崩潰或響應延遲增加。本文將簡述如何通過AOP和自定義…

Unity——QFramework框架 內置工具

QFramework 除了提供了一套架構之外&#xff0c;QFramework 還提供了可以脫離架構使用的工具 TypeEventSystem、EasyEvent、BindableProperty、IOCContainer。 這些工具并不是有意提供&#xff0c;而是 QFramework 的架構在設計之初是通過這幾個工具組合使用而成的。 內置工具…

Vue3.5 企業級管理系統實戰(二十二):動態菜單

在前幾篇內容中已完成菜單、角色及菜單權限等相關開發&#xff0c;若要在左側菜單根據用戶角色動態展示菜單&#xff0c;需對 Sidebar 中的相關數據進行修改。鑒于其他相關方法及類型已在前文實現&#xff0c;本文不再重復闡述。 1 修改 Sidebar 組件 在 src/layout/componen…

014校園管理系統技術解析:構建智慧校園管理平臺

校園管理系統技術解析&#xff1a;構建智慧校園管理平臺 在教育信息化快速發展的當下&#xff0c;校園管理系統成為提升學校管理效率、優化校園服務的重要工具。該系統集成院校管理、投票管理等多個核心模塊&#xff0c;面向管理員、用戶和院內管理員三種角色&#xff0c;通過…

創新農業社會化服務 中和農信服務小農戶的探索實踐

在實現鄉村振興的道路上&#xff0c;如何讓現代農業發展成果惠及廣大小農戶&#xff0c;是一個重要課題。作為國內領先的綜合助農機構&#xff0c;中和農信多年來深耕農村市場&#xff0c;在服務小農戶方面進行了諸多創新探索&#xff0c;走出了一條具有示范意義的農業社會化服…

6.3 day 35

知識點回顧&#xff1a; 三種不同的模型可視化方法&#xff1a;推薦torchinfo打印summary權重分布可視化進度條功能&#xff1a;手動和自動寫法&#xff0c;讓打印結果更加美觀推理的寫法&#xff1a;評估模式 可視化 理解深度學習網絡最重要的2點&#xff1a; 1.了解損失如何定…

【如何在IntelliJ IDEA中新建Spring Boot項目(基于JDK 21 + Maven)】

AA. 我的開發環境配置與核心工具鏈解析 一、開發環境全覽 C:\Users\Again>java -version java version "21.0.1" 2023-10-17 LTS Java(TM) SE Runtime Environment (build 21.0.112-LTS-29) Java HotSpot(TM) 64-Bit Server VM (build 21.0.112-LTS-29, mixed m…

【C++高級主題】多重繼承下的類作用域

目錄 一、類作用域與名字查找規則&#xff1a;理解二義性的根源 1.1 類作用域的基本概念 1.2 單繼承的名字查找流程 1.3 多重繼承的名字查找特殊性 1.4 關鍵規則&#xff1a;“最近” 作用域優先&#xff0c;但多重繼承無 “最近” 二、多重繼承二義性的典型類型與代碼示…

登錄vmware vcenter報vSphere Client service has stopped working錯誤

一、問題 登錄vmware vcenter時發現報vSphere Client service has stopped working錯誤&#xff0c;導致vcenter控制臺進不去 二、解決辦法 打開vmware vcenter管理https://vcenterIP:5480&#xff0c;選擇VMware vSphere Client&#xff0c;重啟該服務后恢復正常。

MySQL關系型數據庫學習

學習參考鏈接&#xff1a;https://www.runoob.com/mysql/mysql-tutorial.html Windows 安裝MYSQL服務端的步驟&#xff1a;https://www.runoob.com/w3cnote/windows10-mysql-installer.html 1. 概念學習 MySQL 是一種關聯數據庫管理系統&#xff0c;關聯數據庫將數據保存在不…

web攻防之SSTI 注入漏洞

知識簡介 &#xff1a; 模版引擎和框架的區別 ssti的中文翻譯 &#xff1a; 服務端的模版的注入 模版引擎 &#xff1a;前端的用于裝飾優化html的模版 最簡單的就是在騰訊會議中的聊天功能 框架 &#xff1a; 這個是一套獨立存在的邏輯 如TP他是一個區別于php語法的后端邏輯…

【清晰教程】利用Git工具將本地項目push上傳至GitHub倉庫中

Git 是一個分布式版本控制系統&#xff0c;由 Linus Torvalds 創建&#xff0c;用于有效、高速地處理從小到大的項目版本管理。GitHub 是一個基于 Git 的代碼托管平臺&#xff0c;提供了額外的協作和社交功能&#xff0c;使項目管理更加高效。它們為項目代碼管理、團隊協作和持…