Java實(shí)現(xiàn)讀取Excel文件功能(EasyExcel初使用)
前言
在我們項(xiàng)目的開(kāi)發(fā)中啊,前端有時(shí)候會(huì)傳送 Excel 文件給后端(Java)去解析,那我們作為后端該如何實(shí)現(xiàn)對(duì) Excel 文件的解析和數(shù)據(jù)讀取呢?說(shuō)到這我就不得不推薦 EasyExcel 了!
EasyExcel 介紹
引用下官方對(duì)于 EasyExcel 介紹:EasyExcel是一個(gè)基于Java的、快速、簡(jiǎn)潔、解決大文件內(nèi)存溢出的Excel處理工具。他能讓你在不用考慮性能、內(nèi)存的等因素的情況下,快速完成Excel的讀、寫(xiě)等功能。
官方網(wǎng)址:EasyExcel官方文檔 - 基于Java的Excel處理工具 | Easy Excel
快速上手 EasyExcel
前置工作
先創(chuàng)建一個(gè) Spring Boot 工程,并在 pom.xml 文件添加 EasyExcel 和 Lombok 依賴。
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.1.1</version>
</dependency>知道表頭
如果我們知道 Excel 數(shù)據(jù)的表頭,即每列數(shù)據(jù)的類(lèi)型包括有多少列時(shí)就可以用此方法讀取 Excel 文件數(shù)據(jù)。
我們以下圖數(shù)據(jù)為例,對(duì)改 Excel 中的數(shù)據(jù)進(jìn)行獲取和處理。

方法一:
首先我們創(chuàng)建一個(gè)名為 ExcelData 的 Java 對(duì)象,共有兩個(gè)屬性,分別是 date(日期列數(shù)據(jù))和 useNum(用戶列數(shù)據(jù)),每個(gè)屬性對(duì)應(yīng) Excel 每列某一行中的數(shù)據(jù)。那么很顯而易見(jiàn),每一行的數(shù)據(jù)就是一個(gè) ExcelData 對(duì)象,所有行的數(shù)據(jù)合起來(lái)就是一個(gè)泛型為 ExcelData 的 ExcelData 的集合。
@Data
public class ExcelData implements Serializable {
/**
* 對(duì)應(yīng)表格的日期列
*/
private String date;
/**
* 對(duì)應(yīng)表格的用戶數(shù)列
*/
private Integer userNum;
}隨后編寫(xiě)一個(gè)測(cè)試類(lèi),并在其中編寫(xiě)測(cè)試方法。
EasyExcel 的 read 方法有很多中構(gòu)造方法,其中 Class head 就是表頭類(lèi)型,傳入它還要傳入 ReadListener 監(jiān)聽(tīng)器,以便在去讀取每行數(shù)據(jù)時(shí)做些自定義操作。我們直接傳入它的實(shí)現(xiàn)類(lèi)實(shí)例,因?yàn)?PageReadListener 支持逐頁(yè)讀取數(shù)據(jù),通過(guò)讀取指定行數(shù)的數(shù)據(jù)保證占用更少的內(nèi)存。

話不多說(shuō)直接上代碼:
/**
* 知道表頭,并形成映射關(guān)系
*/
@Test
public void doImportsForMapping() throws FileNotFoundException{
// 讀取 resource 目錄下的 Excel 文件(網(wǎng)站數(shù)據(jù).xlsx)
File file = ResourceUtils.getFile("classpath:網(wǎng)站數(shù)據(jù).xlsx");
// 創(chuàng)建一個(gè) list 存儲(chǔ)每行的數(shù)據(jù),即 ExcelData 對(duì)象
List<ExcelData> list = new ArrayList<>();
// 直接使用 EasyExcel 的 read 方法,同時(shí)定義表頭的類(lèi)型,以便將列中數(shù)據(jù)映射為 ExcelData 對(duì)象
EasyExcel.read(file, ExcelData.class, new PageReadListener<ExcelData>(dataList -> {
// 并且每行數(shù)據(jù),并將其 add 至 list 中
for (ExcelData excelData : dataList) {
if (excelData != null) {
list.add(excelData);
}
}
})).excelType(ExcelTypeEnum.XLSX).sheet().doRead(); // 指定 Excel 的文件后綴,開(kāi)始分析讀取
for (ExcelData excelData : list) {
System.out.println(excelData.getDate() + "," + excelData.getUserNum());
}
}執(zhí)行結(jié)果:

方法二:
方法一是直接一次性讀取 Excel 中的數(shù)據(jù),缺少要讀取的數(shù)據(jù)行數(shù)和一些自定義操作,所以我們?cè)谶@里對(duì)上面的代碼增強(qiáng)一下。
在此方法中我們通過(guò)匿名內(nèi)部類(lèi)的方式實(shí)現(xiàn) ReadListenser 接口,無(wú)需額外寫(xiě)一個(gè)類(lèi)去實(shí)現(xiàn) ReadListener了。我們?cè)O(shè)置了一個(gè)臨時(shí)存儲(chǔ)的列表(大小為 2),當(dāng)每次讀取的數(shù)據(jù)(執(zhí)行 invoke 方法)添加到臨時(shí)存儲(chǔ)表中。當(dāng)其長(zhǎng)度超過(guò) 2 時(shí)進(jìn)行全部刪除,在刪除前我們可以將臨時(shí)存儲(chǔ)的列表存到數(shù)據(jù)庫(kù)中,或進(jìn)行一些其他的自定義操作。
doAfterAllAnalysed 方法是分析并獲取所有的數(shù)據(jù)后會(huì)執(zhí)行的一個(gè)方法,我們可以在其中打上日志,表示 Excel 所有數(shù)據(jù)已存入數(shù)據(jù)庫(kù)中。
/**
* 知道表頭,并形成映射關(guān)系
* @throws FileNotFoundException
*/
@Test
public void doImportsForMappingByInnerClass() throws FileNotFoundException{
File file = ResourceUtils.getFile("classpath:網(wǎng)站數(shù)據(jù).xlsx");
EasyExcel.read(file, ExcelData.class, new ReadListener<ExcelData>() {
// 單次緩存的數(shù)據(jù)量
public static final int BATCH_COUNT = 2;
// 臨時(shí)存儲(chǔ)的列表
private List<ExcelData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
@Override
public void invoke(ExcelData excelData, AnalysisContext analysisContext) {
cachedDataList.add(excelData);
getData(excelData);
if (cachedDataList.size() >= BATCH_COUNT) {
cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
System.out.println("存儲(chǔ)數(shù)據(jù)庫(kù)成功");
}
private void getData(ExcelData excelData) {
System.out.println(excelData.getDate() + "," + excelData.getUserNum());
}
}).excelType(ExcelTypeEnum.XLSX).sheet().doRead();
}執(zhí)行結(jié)果:

不知道表頭
方法三:
上面的兩種方法都是我們知道表頭,包括列的類(lèi)型和列數(shù)量的情況下對(duì) Excel 文件進(jìn)行數(shù)據(jù)獲取的。那我們不知道表頭信息,又該如何操作呢?
我們依賴?yán)?EasyExcel 的 read 方法,和前面的步驟大差不差,只不過(guò)這次參數(shù)少了,如果你還要獲取表頭即表格的第一行數(shù)據(jù),還可通過(guò) headRowNumber 方法指定首行編號(hào)為 0。
此時(shí)返回的是一個(gè) List<Map<Integer, String>> 集合,其中 Map 的 鍵對(duì)應(yīng)表格的列編號(hào)(從 0 開(kāi)始),值就是對(duì)應(yīng)某一行某一列的值,List 的索引代表某一行的數(shù)據(jù)。調(diào)用 Map 對(duì)象的 values() 方法即可直接獲取某一行數(shù)據(jù)的集合,List<Map<Integer, String>> 就是所有行數(shù)據(jù)的集合。我們這說(shuō)可能不太直觀,我把它打印出來(lái)給你們看就很簡(jiǎn)單明了了。
[{0=日期, 1=用戶數(shù)}, {0=1號(hào), 1=10}, {0=2號(hào), 1=20}, {0=3號(hào), 1=30}, {0=4號(hào), 1=70}, {0=5號(hào), 1=20}, {0=6號(hào), 1=29}, {0=7號(hào), 1=24}, {0=8號(hào), 1=31}, {0=9號(hào), 1=40}, {0=10號(hào), 1=38}, {0=11號(hào), 1=43}]代碼如下:
@Test
public void doImport() throws FileNotFoundException {
List<Map<Integer, String>> list = null;
File file = ResourceUtils.getFile("classpath:網(wǎng)站數(shù)據(jù).xlsx");
try {
list = EasyExcel.read(file)
.excelType(ExcelTypeEnum.XLSX)
.sheet()
.headRowNumber(0)
.doReadSync();
} catch (Exception e) {
throw new RuntimeException("讀取 Excel 文件失敗");
}
StringBuilder stringBuilder = new StringBuilder();
for (int i=0;i<list.size();i++) {
// 轉(zhuǎn)為 LinkedHashMap 主要是為了保證讀取的數(shù)據(jù)和表格順序一致
LinkedHashMap<Integer, String> linkedHashMap = (LinkedHashMap) list.get(i);
List<String> dataList = linkedHashMap.values().stream()
.filter(ObjectUtils::isNotEmpty).collect(Collectors.toList());
stringBuilder.append(StringUtils.join(dataList, ",")).append("\n");
}
System.out.println(stringBuilder.toString());
}執(zhí)行結(jié)果:

總結(jié)
如果知道表頭并且數(shù)據(jù)量較小,就用方法一,如果數(shù)據(jù)量較大或者想添加一些自定操作就用方法二。如果不知道表頭并且想要讀取表頭的信息就用方法三。
到此這篇關(guān)于Java實(shí)現(xiàn)讀取Excel文件功能的文章就介紹到這了,更多相關(guān)Java讀取Excel文件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java使用easyExcel導(dǎo)出excel數(shù)據(jù)案例
- Java使用EasyExcel動(dòng)態(tài)添加自增序號(hào)列
- Java中Easyexcel?實(shí)現(xiàn)批量插入圖片功能
- Java利用EasyExcel實(shí)現(xiàn)合并單元格
- Java使用EasyExcel進(jìn)行單元格合并的問(wèn)題詳解
- Java?easyExcel的復(fù)雜表頭多級(jí)表頭導(dǎo)入
- Java利用EasyExcel解析動(dòng)態(tài)表頭及導(dǎo)出實(shí)現(xiàn)過(guò)程
- Java使用EasyExcel實(shí)現(xiàn)Excel的導(dǎo)入導(dǎo)出
- Java EasyExcel實(shí)現(xiàn)導(dǎo)出多sheet并設(shè)置單元格樣式
- Java?EasyExcel實(shí)現(xiàn)合并相同內(nèi)容單元格與動(dòng)態(tài)標(biāo)題功能
相關(guān)文章
SpringBoot利用filter實(shí)現(xiàn)xss防御功能
Cross-Site?Scripting(跨站腳本攻擊)簡(jiǎn)稱?XSS,是一種代碼注入攻擊,攻擊者通過(guò)在目標(biāo)網(wǎng)站上注入惡意腳本,使之在用戶的瀏覽器上運(yùn)行,利用這些惡意腳本,攻擊者可獲取用戶的敏感信息,本文給大家介紹了SpringBoot利用filter實(shí)現(xiàn)xss防御功能,需要的朋友可以參考下2024-09-09
spring boot+mybatis 多數(shù)據(jù)源切換(實(shí)例講解)
下面小編就為大家?guī)?lái)一篇spring boot+mybatis 多數(shù)據(jù)源切換(實(shí)例講解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-09-09
5分鐘快速搭建SpringBoot3?+?MyBatis-Plus工程/項(xiàng)目的實(shí)現(xiàn)示例
本文主要介紹了使用IntelliJ?IDEA創(chuàng)建Spring?Boot工程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-01-01
如何讀取properties或yml文件數(shù)據(jù)并匹配
這篇文章主要介紹了如何讀取properties或yml文件數(shù)據(jù)并匹配方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
詳解SpringBoot如何創(chuàng)建自定義Starter
Spring Boot的自動(dòng)配置機(jī)制為開(kāi)發(fā)人員提供了一種輕松集成和配置各種功能的便捷方式,本文將深入探討在Spring Boot中如何創(chuàng)建自定義Starter,為構(gòu)建模塊化且易維護(hù)的應(yīng)用提供有力的支持,需要的朋友可以參考下2024-02-02

