EasyExcel讀寫(xiě)、模板填充、Web上傳下載入門(mén)到實(shí)戰(zhàn)全指南
EasyExcel 是阿里巴巴開(kāi)源的一款 基于 Java 的高性能、簡(jiǎn)單易用的 Excel 讀寫(xiě)工具庫(kù),專(zhuān)注于解決使用 Apache POI(Java 操作 Excel 的底層庫(kù))時(shí)常見(jiàn)的 內(nèi)存溢出(OOM) 和 API 復(fù)雜 問(wèn)題。
一、 主要功能
1. 讀 Excel(支持 .xls / .xlsx)
- 按行讀取,自動(dòng)映射到 Java 對(duì)象
- 支持讀取表頭、數(shù)據(jù)、異常處理
- 可監(jiān)聽(tīng)每行數(shù)據(jù)(適合大數(shù)據(jù)量)
EasyExcel.read(fileName, DemoData.class, new MyReadListener())
.sheet()
.doRead();
2. 寫(xiě) Excel
- 自動(dòng)根據(jù)對(duì)象字段生成表頭和數(shù)據(jù)
- 支持大數(shù)據(jù)量分批寫(xiě)入(百萬(wàn)行無(wú)壓力)
- 可指定列寬、行高、樣式等
EasyExcel.write(fileName, DemoData.class)
.sheet("Sheet1")
.doWrite(dataList);
3. Excel 填充(模板填充)
- 提供 Excel 模板(帶占位符如
{name}) - 自動(dòng)填充數(shù)據(jù),適合生成報(bào)表、證書(shū)等
EasyExcel.write(out, DemoData.class)
.withTemplate(templateFile)
.sheet()
.doFill(data);
4. 豐富的注解支持
@ExcelProperty("姓名"):指定列名@ColumnWidth(20):設(shè)置列寬@DateTimeFormat("yyyy-MM-dd"):日期格式化@NumberFormat("#,##0.00"):數(shù)字格式化@ExcelIgnore:忽略字段
public class User {
@ExcelProperty("用戶姓名")
private String name;
@ExcelProperty("注冊(cè)時(shí)間")
@DateTimeFormat("yyyy年MM月dd日")
private Date registerTime;
}
二、 快速開(kāi)始
1. 引入依賴
<!--Lombok依賴-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--easyexcel依賴-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>4.0.3</version>
</dependency>
<!--fastjson依賴-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.57</version>
</dependency>
2. 寫(xiě)實(shí)體類(lèi)
package com.nuc.demoexcel.entity;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
import java.util.Date;
@Data
@HeadRowHeight(20)
@ColumnWidth(20)
public class DemoDate {
@ExcelProperty("字符串標(biāo)題")
private String name;
@ExcelProperty("日期標(biāo)題")
@JSONField(format = "yyyy-MM-dd,HH:mm:ss") // 格式化日期 沒(méi)有注解會(huì)默認(rèn)轉(zhuǎn)成時(shí)間戳
private Date date;
@ExcelProperty("數(shù)字標(biāo)題")
private Double doubleData;
@ExcelIgnore
private String ignore;
}
3. Excel讀取
讀取常用有三種方法
- 這是我提前準(zhǔn)備好的excel文件

方法一:
有封裝的實(shí)體類(lèi)
用.head(DemoData.class)封裝
結(jié)果用List<DemoData>存
/**
* 測(cè)試讀1
* 有封裝的實(shí)體類(lèi)
*/
@Test
void readExcel1() {
System.out.println("測(cè)試");
List<DemoDate> list = EasyExcel.read("D:\\測(cè)試\\demo.xlsx").head(DemoDate.class).sheet().doReadSync();
list.forEach(data ->{
String jsonString = JSON.toJSONString(data);
log.info("讀取到數(shù)據(jù){}",jsonString);
});
}
- 測(cè)試結(jié)果

方法二:沒(méi)有封裝的實(shí)體類(lèi)
沒(méi)有封裝的實(shí)體類(lèi)
結(jié)果用List<Map<Integer,String>>存
/**
* 測(cè)試讀2
* 沒(méi)有分裝的實(shí)體類(lèi)用Map來(lái)存
*/
@Test
void readExcel2() {
System.out.println("測(cè)試");
List<Map<Integer,String>> list = EasyExcel.read("D:\\測(cè)試\\demo.xlsx").sheet().doReadSync();
list.forEach(data ->{
String string = data.toString();
log.info("讀取到數(shù)據(jù){}",string);
});
}
- 測(cè)試結(jié)果同上
方法三:使用監(jiān)聽(tīng)器來(lái)讀取文件
使用監(jiān)聽(tīng)器來(lái)讀取文件
/**
* 測(cè)試讀3
* 使用監(jiān)聽(tīng)器讀取文件。
* 需要我們額外創(chuàng)建一個(gè)監(jiān)聽(tīng)器
*/
@Test
void readExcel3() {
System.out.println("測(cè)試");
EasyExcel.read("D:\\測(cè)試\\demo.xlsx", DemoDate.class, new ExcelListener(demoService)).sheet().doRead();
}
- 這里需要額外寫(xiě)一個(gè)監(jiān)聽(tīng)器
package com.nuc.demoexcel.listener;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;
import com.nuc.demoexcel.entity.DemoDate;
import com.nuc.demoexcel.service.DemoService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
/**
* 這里不能用SprongIoC容器來(lái)管理Listener,Listener可添加多個(gè),會(huì)自動(dòng)執(zhí)行
*/
@Slf4j
@RequiredArgsConstructor
public class ExcelListener extends AnalysisEventListener<DemoDate> {
/**
* 每隔5條存儲(chǔ)數(shù)據(jù)庫(kù),清理list,方便內(nèi)存回收
*/
private static final int BATCH_COUNT = 5;
private List<DemoDate> list = new ArrayList<DemoDate>();
private final DemoService demoService;
@Override
public void invoke(DemoDate demoDate, AnalysisContext analysisContext) {
log.info("讀取到數(shù)據(jù){}", JSON.toJSONString(demoDate));
list.add(demoDate);
// 到達(dá)批次數(shù),保存數(shù)據(jù),防止數(shù)據(jù)幾萬(wàn)條數(shù)據(jù)在內(nèi)存中,容易OOM
if (list.size() >= BATCH_COUNT) {
saveData();
// 保存完成,清理list
list.clear();
}
}
/**
* 所有的數(shù)據(jù)都讀完,最后收尾數(shù)據(jù)
* @param analysisContext
*/
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
//這里也要保存數(shù)據(jù),確保最后遺留的數(shù)據(jù)也存儲(chǔ)到數(shù)據(jù)庫(kù)
saveData();
log.info("所有數(shù)據(jù)解析完成!");
}
/**
* 存儲(chǔ)數(shù)據(jù)到數(shù)據(jù)庫(kù)
*/
private void saveData() {
log.info("{}條數(shù)據(jù),開(kāi)始存儲(chǔ)數(shù)據(jù)庫(kù)!", list.size());
demoService.saveData(list);
log.info("存儲(chǔ)數(shù)據(jù)庫(kù)成功!");
}
}
這里只是演示EasyExcel
所以就不寫(xiě)Service層代碼
4. Excel寫(xiě)入
/**
* 測(cè)試寫(xiě)
*/
@Test
void testWrite() {
// 文件輸出位置
String fileName = "D:\\text" + System.currentTimeMillis() + ".xlsx";
EasyExcel.write(fileName, DemoDate.class).sheet("模板").doWrite(data());
}
private List<DemoDate> data(){
//模擬數(shù)據(jù)
List<DemoDate> list = new ArrayList<>();
for (int i = 0; i < 13; i++) {
DemoDate data = new DemoDate();
data.setName("張三"+i);
data.setDate(new Date());
data.setDoubleData(Math.random()*100);
list.add(data);
}
return list;
}
- 成功寫(xiě)入

5. Excel下載&上傳
package com.nuc.demoexcel.controller;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.nuc.demoexcel.entity.DemoDate;
import com.nuc.demoexcel.listener.ExcelListener;
import com.nuc.demoexcel.service.DemoService;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;
@Controller
public class UploadDownController {
@Autowired
private DemoService demoService;
/**
* 下載失敗了(會(huì)返回一個(gè)有部分?jǐn)?shù)據(jù)的Excel)
* @param response
* @throws IOException
*/ @RequestMapping("/download")
public void download(HttpServletResponse response) throws IOException {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
//這里的encode是解決中文亂碼, 這里必須使用UTF-8, 不然亂碼
String fileName = URLEncoder.encode("測(cè)試", "UTF-8").replaceAll("\\+", "%20");
//這里使用附件的形式下載
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream(), DemoDate.class).sheet("模板").doWrite(data());
}
@RequestMapping("/api/download")
public void downloadApi(HttpServletResponse response) throws IOException {
try {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
//這里的encode是解決中文亂碼, 這里必須使用UTF-8, 不然亂碼
String fileName = URLEncoder.encode("測(cè)試", "UTF-8").replaceAll("\\+", "%20");
//這里使用附件的形式下載
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream(), DemoDate.class).sheet("模板").doWrite(data());
} catch (IOException e) {
//重置響應(yīng)
response.reset();
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
Map<String, Object> map = new HashMap<>();
map.put("status", 500);
map.put("message", "數(shù)據(jù)寫(xiě)入失敗" + e.getMessage());
response.getWriter().println(JSON.toJSONString(map));
}
}
@PostMapping("/upload")
@ResponseBody
public String upload(MultipartFile file) throws IOException {
EasyExcel.read(file.getInputStream(), DemoDate.class, new ExcelListener(demoService)).sheet().doRead();
return "success";
}
private List<DemoDate> data(){
//模擬數(shù)據(jù)
List<DemoDate> list = new ArrayList<>();
for (int i = 0; i < 13; i++) {
DemoDate data = new DemoDate();
data.setName("張三"+i);
data.setDate(new Date());
data.setDoubleData(Math.random()*100);
list.add(data);
}
return list;
}
}
- 調(diào)用
localhost:8080/download接口
5. Excel下載&上傳
package com.nuc.demoexcel.controller;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.nuc.demoexcel.entity.DemoDate;
import com.nuc.demoexcel.listener.ExcelListener;
import com.nuc.demoexcel.service.DemoService;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;
@Controller
public class UploadDownController {
@Autowired
private DemoService demoService;
/**
* 下載失敗了(會(huì)返回一個(gè)有部分?jǐn)?shù)據(jù)的Excel)
* @param response
* @throws IOException
*/ @RequestMapping("/download")
public void download(HttpServletResponse response) throws IOException {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
//這里的encode是解決中文亂碼, 這里必須使用UTF-8, 不然亂碼
String fileName = URLEncoder.encode("測(cè)試", "UTF-8").replaceAll("\\+", "%20");
//這里使用附件的形式下載
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream(), DemoDate.class).sheet("模板").doWrite(data());
}
@RequestMapping("/api/download")
public void downloadApi(HttpServletResponse response) throws IOException {
try {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
//這里的encode是解決中文亂碼, 這里必須使用UTF-8, 不然亂碼
String fileName = URLEncoder.encode("測(cè)試", "UTF-8").replaceAll("\\+", "%20");
//這里使用附件的形式下載
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream(), DemoDate.class).sheet("模板").doWrite(data());
} catch (IOException e) {
//重置響應(yīng)
response.reset();
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
Map<String, Object> map = new HashMap<>();
map.put("status", 500);
map.put("message", "數(shù)據(jù)寫(xiě)入失敗" + e.getMessage());
response.getWriter().println(JSON.toJSONString(map));
}
}
@PostMapping("/upload")
@ResponseBody
public String upload(MultipartFile file) throws IOException {
EasyExcel.read(file.getInputStream(), DemoDate.class, new ExcelListener(demoService)).sheet().doRead();
return "success";
}
private List<DemoDate> data(){
//模擬數(shù)據(jù)
List<DemoDate> list = new ArrayList<>();
for (int i = 0; i < 13; i++) {
DemoDate data = new DemoDate();
data.setName("張三"+i);
data.setDate(new Date());
data.setDoubleData(Math.random()*100);
list.add(data);
}
return list;
}
}
調(diào)用
localhost:8080/download接口
調(diào)用
localhost:8080/api/upload接口
使用postman 調(diào)用
localhost:8080/upload接口
- 后端

- 后端
總結(jié)
到此這篇關(guān)于EasyExcel讀寫(xiě)、模板填充、Web上傳下載入門(mén)到實(shí)戰(zhàn)的文章就介紹到這了,更多相關(guān)EasyExcel讀寫(xiě)、模板填充、Web上傳下載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mac下eclipse項(xiàng)目根目錄沒(méi)有.setting文件夾的解決方案
文章介紹了如何通過(guò)修改項(xiàng)目根路徑下.setting文件夾中的org.eclipse.wst.common.project.facet.core.xml文件來(lái)解決Web版本問(wèn)題2026-02-02
Redisson分布式鎖實(shí)現(xiàn)原理示例詳解
Redisson分布式鎖通過(guò)Lua腳本保證原子性操作,實(shí)現(xiàn)了分布式互斥、可重入、自動(dòng)續(xù)期等核心特性,其高級(jí)特性包括公平鎖、讀寫(xiě)鎖和紅鎖算法,能夠滿足不同場(chǎng)景下的并發(fā)控制需求,這篇文章主要介紹了Redisson分布式鎖實(shí)現(xiàn)原理的相關(guān)資料,需要的朋友可以參考下2026-04-04
用java實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)學(xué)生信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-09-09
詳解Java如何優(yōu)雅的實(shí)現(xiàn)異常捕獲
在一個(gè)優(yōu)秀的項(xiàng)目中一定少不了對(duì)程序流程良好的異常捕獲與日志打印,所以本文主要為大家介紹了如何優(yōu)雅的實(shí)現(xiàn)異常捕獲與日志打印輸出,有需要的可以參考下2023-09-09
開(kāi)源項(xiàng)目ERM模型轉(zhuǎn)jpa實(shí)體maven插件使用
這篇文章主要為大家介紹了開(kāi)源項(xiàng)目ERM模型轉(zhuǎn)jpa實(shí)體maven插件的使用說(shuō)明,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-03-03
SpringCloud Zuul過(guò)濾器實(shí)現(xiàn)登陸鑒權(quán)代碼實(shí)例
這篇文章主要介紹了SpringCloud Zuul過(guò)濾器實(shí)現(xiàn)登陸鑒權(quán)代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03
java 數(shù)據(jù)的加密與解密普遍實(shí)例代碼
本篇文章介紹了一個(gè)關(guān)于密鑰查詢的jsp文件簡(jiǎn)單實(shí)例代碼,需要的朋友可以參考下2017-04-04
一種類(lèi)似JAVA線程池的C++線程池實(shí)現(xiàn)方法
線程池(thread pool)是一種線程使用模式。線程過(guò)多或者頻繁創(chuàng)建和銷(xiāo)毀線程會(huì)帶來(lái)調(diào)度開(kāi)銷(xiāo),進(jìn)而影響緩存局部性和整體性能。這篇文章主要介紹了一種類(lèi)似JAVA線程池的C++線程池實(shí)現(xiàn)方法,需要的朋友可以參考下2019-07-07
使用@RequestParam設(shè)置默認(rèn)可以傳空值
這篇文章主要介紹了使用@RequestParam設(shè)置默認(rèn)可以傳空值的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08

