SpringBoot整合FastExcel實(shí)現(xiàn)導(dǎo)入導(dǎo)出功能的操作詳解
一、前言
在微服務(wù)項(xiàng)目中經(jīng)常會(huì)涉及到excel的導(dǎo)入導(dǎo)出功能,隨著要處理的業(yè)務(wù)數(shù)據(jù)量越來越大,這也對程序提出了更高的要求,因?yàn)榇笈康臄?shù)據(jù)導(dǎo)入導(dǎo)出對性能提出了更高的挑戰(zhàn)。在早些年使用poi等工具進(jìn)行導(dǎo)入導(dǎo)出的時(shí)候,經(jīng)常會(huì)被吐槽有各種問題,比如API使用復(fù)雜,數(shù)據(jù)量過大時(shí)容易OOM等問題,所以在后面當(dāng)EasyExcel推出來之后,其優(yōu)異的性能得到了很多程序開發(fā)者的認(rèn)可??上У氖?,隨著EasyExcel的設(shè)計(jì)者離場,EasyExcel的維護(hù)面臨著考驗(yàn),于是又推出FastExcel 。作為EasyExcel的替代者,不僅完全兼容EasyExcel的功能,同時(shí)也對其進(jìn)行了進(jìn)一步的優(yōu)化,并增加了一些新的功能,本篇將詳細(xì)介紹下FastExcel 的使用。
二、FastExcel 介紹
2.1 FastExcel 是什么
FastExcel 是一款基于 Java 的開源庫,旨在提供快速、簡潔且能解決大文件內(nèi)存溢出問題的 Excel 處理工具。它兼容 EasyExcel,提供性能優(yōu)化、bug 修復(fù),并新增了如讀取指定行數(shù)和將 Excel 轉(zhuǎn)換為 PDF 的功能。
FastExcel 以 MIT 協(xié)議發(fā)布,適用于任何商業(yè)場景。其高性能讀寫、簡單易用的 API 和流式操作能力,使其特別適合處理大規(guī)模數(shù)據(jù)。FastExcel 支持無縫從 EasyExcel 遷移,極大地簡化了 Excel 文件的讀寫操作,提升了開發(fā)效率。git地址:GitHub - apache/fesod: Fast. Easy. Done. Processing Excels without worrying about large files causing OOM.

2.2 FastExcel 主要特點(diǎn)
FastExcel 具備如下特點(diǎn):
完全兼容EasyExcel的所有功能和特性,這使得用戶可以無縫遷移和過渡;
從EasyExcel升級到EasyExcel,只需要簡單的更換包名和maven依賴即可完成成升級;
從功能上,比EasyExcel提供更多創(chuàng)新改進(jìn),比如 FastExcel 1.0.0版本新增了:
- 讀取excel指定的行數(shù);
- 將excel轉(zhuǎn)為pdf;
2.3 FastExcel 主要功能
FastExcel 主要提供了以下功能
- 高性能讀寫:FastExcel 專注于性能優(yōu)化,能高效處理大規(guī)模 Excel 數(shù)據(jù),顯著降低內(nèi)存占用。
- 簡單易用:提供簡潔直觀的 API,易于集成和使用。
- 流式操作:支持流式讀取,減少一次性加載大量數(shù)據(jù)的問題。
- 讀取指定行數(shù):可以根據(jù)需求,只讀取感興趣的部分?jǐn)?shù)據(jù),提高數(shù)據(jù)處理效率。
- Excel 轉(zhuǎn)換為 PDF:支持直接將 Excel 文件轉(zhuǎn)換為 PDF,滿足多樣化的文檔輸出需求。
2.4 FastExcel 核心技術(shù)實(shí)現(xiàn)原理
FastExcel 核心原理參考下面的理解:
- 內(nèi)存優(yōu)化:基于流式讀取技術(shù),不需要一次性將整個(gè) Excel 文件加載到內(nèi)存中,逐行或逐塊讀取數(shù)據(jù)。
- 事件驅(qū)動(dòng)模型:基于實(shí)現(xiàn)
ReadListener接口處理讀取操作。當(dāng)讀取到數(shù)據(jù)時(shí),會(huì)觸發(fā)接口中的方法,如invoke方法,支持開發(fā)者對每行數(shù)據(jù)進(jìn)行即時(shí)處理。 - 注解映射:用注解將 Excel 文件中的列與 Java 對象的屬性進(jìn)行映射。開發(fā)者能輕松地將 Excel 數(shù)據(jù)轉(zhuǎn)換為 Java 對象,同時(shí)也支持反向操作,將 Java 對象寫入 Excel。
三、springboot 整合FastExcel 操作過程
接下來通過實(shí)際案例演示下如何在springboot 項(xiàng)目中整合FastExcel 。
3.1 開發(fā)環(huán)境準(zhǔn)備
為了確保后續(xù)你的工程也能正常的使用,建議參考下面的技術(shù)棧:
- JDK 17;
- SpringBoot 3.3 ;
3.2 完整整合過程
3.2.1 添加依賴
創(chuàng)建一個(gè)全新的springboot工程,在pom文件中添加如下的依賴
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.3</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>cn.idev.excel</groupId>
<artifactId>fastexcel</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>3.2.2 配置文件信息
本例僅演示導(dǎo)入導(dǎo)出功能,配置文件只需要配置下端口即可
server: port: 8082
3.2.3 增加一個(gè)實(shí)體類
之前有使用過easyexcel經(jīng)驗(yàn)的同學(xué)應(yīng)該不陌生,一般導(dǎo)入的數(shù)據(jù)最終需要落庫,為了讓excel的列與數(shù)據(jù)庫表字段進(jìn)行對應(yīng),一般需要一個(gè)自定義的對象,用easyexcel提供的相應(yīng)注解來標(biāo)準(zhǔn)字段信息,這樣easyexcel在解析的時(shí)候才能進(jìn)行映射,如下,增加一個(gè)自定義的User類,里面有3個(gè)基本屬性
package com.congge.entity;
import cn.idev.excel.annotation.ExcelProperty;
import lombok.*;
@Setter
@Getter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class User {
@ExcelProperty("編號")
private Integer id;
@ExcelProperty("名字")
private String name;
@ExcelProperty("年齡")
private Integer age;
}3.2.4 增加一個(gè)事件監(jiān)聽器
監(jiān)聽器的作用也可以理解為FastExcel 內(nèi)部封裝的一個(gè)兼具數(shù)據(jù)讀取,數(shù)據(jù)緩存,數(shù)據(jù)轉(zhuǎn)換為一體的組件,有了這個(gè)監(jiān)聽器,上層只需要在上傳或下載excel的時(shí)候代入進(jìn)去,該監(jiān)聽器就可以發(fā)揮作用,從而完成數(shù)據(jù)的轉(zhuǎn)換。參考下面的代碼。
package com.congge.component;
import cn.idev.excel.context.AnalysisContext;
import cn.idev.excel.event.AnalysisEventListener;
import java.util.ArrayList;
import java.util.List;
public class BaseExcelListener<T> extends AnalysisEventListener<T> {
private final List<T> dataList = new ArrayList<>();
@Override
public void invoke(T t, AnalysisContext analysisContext) {
// 每讀取一行數(shù)據(jù),就將其添加到dataList中
dataList.add(t);
System.out.println("解析到數(shù)據(jù): " + t);
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
System.out.println("讀取完成,共讀取了 " + dataList.size() + " 條數(shù)據(jù)");
}
public List<T> getDataList() {
return dataList;
}
}3.2.5 增加一個(gè)測試使用的接口類
為了方便測試看效果,增加一個(gè)controller控制器類,提供2個(gè)基本的上傳下載接口,參考下面的代碼
package com.congge.controller;
import cn.idev.excel.FastExcel;
import com.congge.component.BaseExcelListener;
import com.congge.entity.User;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;
@RestController
@RequestMapping("/api/excel")
public class ExcelController {
/**
* Excel導(dǎo)出功能
* @param response
* @throws IOException
* localhost:8082/api/excel/download
*/
@GetMapping("/download")
public void download(HttpServletResponse response) throws IOException {
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode("用戶數(shù)據(jù)", "UTF-8");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
// 寫入數(shù)據(jù)
FastExcel.write(response.getOutputStream(), User.class)
.sheet("用戶信息")
.doWrite(buildData());
}
/**
* Excel導(dǎo)出功能
* @param file
* @return
* localhost:8082/api/excel/upload
*/
@PostMapping("/upload")
public ResponseEntity<String> upload(@RequestParam("file") MultipartFile file) {
if (file.isEmpty()) {
return ResponseEntity.badRequest().body("請選擇一個(gè)文件上傳!");
}
try {
BaseExcelListener<User> baseExcelListener = new BaseExcelListener<>();
FastExcel.read(file.getInputStream(), User.class, baseExcelListener)
.sheet()
.doRead();
// 獲取讀取的數(shù)據(jù)
List<User> dataList = baseExcelListener.getDataList();
System.out.println("讀取到的數(shù)據(jù): " + dataList);
return ResponseEntity.ok("文件上傳并處理成功!共處理 " + dataList.size() + " 條數(shù)據(jù)");
} catch (IOException e) {
return ResponseEntity.status(500).body("文件處理失敗: " + e.getMessage());
}
}
// 創(chuàng)建測試數(shù)據(jù)
private List<User> buildData() {
User user1 = new User();
user1.setId(1);
user1.setName("張三");
user1.setAge(18);
User user2 = new User();
user2.setId(2);
user2.setName("李四");
user2.setAge(19);
return List.of(user1, user2);
}
}3.2.6 效果測試與驗(yàn)證
分別測試一下上面兩個(gè)接口,啟動(dòng)工程
1)下載接口測試
啟動(dòng)工程后,瀏覽器調(diào)用接口:localhost:8082/api/excel/download ,按照預(yù)期的效果下載為一個(gè)excel

2)上傳接口測試
使用接口工具模擬接口調(diào)用,就用上面的這個(gè)excel,主要是看看控制臺(tái)的輸出日志,接口調(diào)用成功

通過控制臺(tái)的輸出日志可以看到,待導(dǎo)入的數(shù)據(jù)也成功進(jìn)行了加載

3.2.7 補(bǔ)充說明
有的同學(xué)可能會(huì)有這樣的擔(dān)心,當(dāng)excel數(shù)據(jù)量太大的時(shí)候,會(huì)不會(huì)有性能問題,關(guān)于這一點(diǎn),F(xiàn)astExcel 的作者在設(shè)計(jì)的時(shí)候就考慮到了,當(dāng)你要上傳的excel里面的數(shù)據(jù)量比較大,工具方法內(nèi)部會(huì)進(jìn)行分批讀取,從而減少OOM的風(fēng)險(xiǎn)

3.3 FastExcel 高級功能
3.3.1 大量數(shù)據(jù)導(dǎo)入優(yōu)化
對于大數(shù)據(jù)量導(dǎo)入,建議使用批量處理模式,因此需要改寫和優(yōu)化上述的事件監(jiān)聽器,參考下面的代碼
import cn.idev.excel.context.AnalysisContext;
import cn.idev.excel.event.AnalysisEventListener;
import java.util.ArrayList;
import java.util.List;
public class BatchExcelListener<T> extends AnalysisEventListener<T> {
private static final int BATCH_COUNT = 1000;
private List<T> dataList = new ArrayList<>(BATCH_COUNT);
@Override
public void invoke(T data, AnalysisContext context) {
dataList.add(data);
// 達(dá)到BATCH_COUNT了,需要去存儲(chǔ)一次數(shù)據(jù)庫,防止數(shù)據(jù)幾萬條數(shù)據(jù)在內(nèi)存,容易OOM
if (dataList.size() >= BATCH_COUNT) {
saveData();
// 存儲(chǔ)完成清理 list
dataList = new ArrayList<>(BATCH_COUNT);
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 確保最后遺留的數(shù)據(jù)也存儲(chǔ)到數(shù)據(jù)庫
if (!dataList.isEmpty()) {
saveData();
}
System.out.println("所有數(shù)據(jù)解析完成!");
}
private void saveData() {
// 這里實(shí)現(xiàn)批量保存到數(shù)據(jù)庫的邏輯
System.out.println("批量保存" + dataList.size() + "條數(shù)據(jù)到數(shù)據(jù)庫");
// userService.saveBatch(dataList);
}
}3.3.2 excel轉(zhuǎn)pdf功能
添加下面的測試接口驗(yàn)證excel轉(zhuǎn)pdf功能
//localhost:8082/api/excel/convertToPdf
@GetMapping("/convertToPdf")
public void convertToPdf(){
String excelPath = "D:\\data\\用戶數(shù)據(jù).xlsx";
String pdfFilePath = "D:\\data\\用戶數(shù)據(jù).pdf";
FastExcel.convertToPdf(new File(excelPath), new File(pdfFilePath), null, null);
System.out.println("轉(zhuǎn)換完成");
}3.4 EasyExcel 升級到FastExcel
有一些伙伴之前項(xiàng)目中使用的是EasyExcel ,那么如果要升級到FastExcel該怎么做呢,可以參考下面的步驟
3.4.1 修改依賴
將 EasyExcel 的依賴替換為 FastExcel 的依賴,如下:
<!-- easyexcel 依賴 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>xxxx</version> </dependency>
依賴替換為:
<dependency> <groupId>cn.idev.excel</groupId> <artifactId>fastexcel</artifactId> <version>1.0.0</version> </dependency>
3.4.2 修改代碼
將 EasyExcel 的包名替換為 FastExcel 的包名,如下:
// 將 easyexcel 的包名替換為 FastExcel 的包名 import com.alibaba.excel.**;
替換為:
import cn.idev.excel.**;
本文通過案例代碼演示了FastExcel 的使用,通過案例介紹了FastExcel 具體的導(dǎo)入導(dǎo)出的使用,更多功能有興趣的同學(xué)可以繼續(xù)深入研究,本篇到此結(jié)束,感謝觀看。
到此這篇關(guān)于SpringBoot整合FastExcel實(shí)現(xiàn)導(dǎo)入導(dǎo)出功能的操作詳解的文章就介紹到這了,更多相關(guān)SpringBoot FastExcel導(dǎo)入導(dǎo)出內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 一文帶你了解FastExcel的使用
- Java使用FastExcel實(shí)現(xiàn)合并單元格
- Java使用FastExcel導(dǎo)入支持多種時(shí)間格式
- 在Vue+SpringBoot應(yīng)用中實(shí)現(xiàn)導(dǎo)入導(dǎo)出excel表功能全過程
- SpringBoot集成EasyExcel實(shí)現(xiàn)百萬級別的數(shù)據(jù)導(dǎo)入導(dǎo)出實(shí)踐指南
- SpringBoot+EasyExcel實(shí)現(xiàn)自定義復(fù)雜樣式導(dǎo)入導(dǎo)出
- Springboot整合easyexcel實(shí)現(xiàn)一個(gè)接口任意表的Excel導(dǎo)入導(dǎo)出
- SpringBoot使用Apache?POI實(shí)現(xiàn)導(dǎo)入導(dǎo)出Excel文件
相關(guān)文章
使用InputStream的available()能否用來判斷當(dāng)前流是否讀取到文件
這篇文章主要介紹了使用InputStream的available()能否用來判斷當(dāng)前流是否讀取到文件問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06
idea2020.2卡死在reading maven projects
這篇文章主要介紹了idea2020.2卡死在reading maven projects,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(27)
下面小編就為大家?guī)硪黄狫ava基礎(chǔ)的幾道練習(xí)題(分享)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧,希望可以幫到你2021-07-07
java中BeanNotOfRequiredTypeException的問題解決(@Autowired和@Resourc
本文主要介紹了java中BeanNotOfRequiredTypeException的問題解決(@Autowired和@Resource注解的不同),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07
RocketMQ NameServer保障數(shù)據(jù)一致性實(shí)現(xiàn)方法講解
這篇文章主要介紹了RocketMQ NameServer保障數(shù)據(jù)一致性實(shí)現(xiàn)方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
JAVA使用ElasticSearch查詢in和not in的實(shí)現(xiàn)方式
今天小編就為大家分享一篇關(guān)于JAVA使用Elasticsearch查詢in和not in的實(shí)現(xiàn)方式,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-12-12
深入了解JVM(Java虛擬機(jī))內(nèi)存結(jié)構(gòu)
Java虛擬機(jī)(Java Virtual Machine,JVM)是Java程序的運(yùn)行環(huán)境,它是一個(gè)抽象的計(jì)算機(jī)模型,通過解釋和執(zhí)行Java字節(jié)碼來運(yùn)行Java程序,本將大家深入了解JVM(Java虛擬機(jī))內(nèi)存結(jié)構(gòu),需要的朋友可以參考下2023-08-08

