SpringBoot整合EasyExcel實現(xiàn)Excel表格導出功能
栗子
在后端管理系統(tǒng)的開發(fā)中,經(jīng)常有需要導出當前表格數(shù)據(jù)的功能,有些前端表格組件可以直接做到,但是不夠靈活。因為前端拿到的數(shù)據(jù)始終是經(jīng)過處理的,如果想拿到原版數(shù)據(jù),必須后端處理。如下圖:


除了使用Apache POI包,還有沒有其他的選擇?當然有! 這里我給大家推薦一款非常簡單且容易上手的開源組件:Alibaba EasyExcel
1.組件介紹
首先放出官網(wǎng)地址,歡迎大家star(目前已經(jīng)24K): https://alibaba-easyexcel.github.io/docs/current/
EasyExcel是一個基于Java的簡單、省內(nèi)存的讀寫Excel的開源項目。在盡可能節(jié)約內(nèi)存的情況下支持讀寫百M的Excel。
64M內(nèi)存20秒讀取75M(46W行25列)的Excel(3.0.2+版本)

Alibaba EasyExcel的核心類是EasyExcel類
/**
* 最簡單的讀
* <p>1. 創(chuàng)建excel對應的實體對象 參照{(diào)@link DemoData}
* <p>2. 由于默認一行行的讀取excel,所以需要創(chuàng)建excel一行一行的回調(diào)監(jiān)聽器,參照{(diào)@link DemoDataListener}
* <p>3. 直接讀即可
*/
@Test
public void simpleRead() {
String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
// 這里 需要指定讀用哪個class去讀,然后讀取第一個sheet 文件流會自動關(guān)閉
EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();
}/**
* 最簡單的寫
* <p>1. 創(chuàng)建excel對應的實體對象 參照{(diào)@link com.alibaba.easyexcel.test.demo.write.DemoData}
* <p>2. 直接寫即可
*/
@Test
public void simpleWrite() {
String fileName = TestFileUtil.getPath() + "write" + System.currentTimeMillis() + ".xlsx";
// 這里 需要指定寫用哪個class去讀,然后寫到第一個sheet,名字為模板 然后文件流會自動關(guān)閉
// 如果這里想使用03 則 傳入excelType參數(shù)即可
EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());
}2.配置文件
SpringBoot項目pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>SpringBoot-easyexcel</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>SpringBoot-easyexcel</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 一般easyexcel都會和lombok搭配使用 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
<!-- 最新版 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.1.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>3.項目代碼
項目結(jié)構(gòu)

ExportController.java
package com.example.springbooteasyexcel.controller;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.example.springbooteasyexcel.data.Mock;
import com.example.springbooteasyexcel.sheet.CitySheet;
import com.example.springbooteasyexcel.sheet.CompanySheet;
import com.example.springbooteasyexcel.sheet.UserSheet;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
@RestController
@RequestMapping("/export")
public class ExportController {
/**
* @param response
* @url <a>http://localhost:8080/export/test1</a>
* 在Excel中寫入單個sheet
*/
@RequestMapping("/test1")
public void test1(HttpServletResponse response) {
//從HttpServletResponse中獲取OutputStream輸出流
try {
// 設(shè)置響應類型
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
// 設(shè)置編碼格式
response.setCharacterEncoding("utf-8");
// 設(shè)置URLEncoder.encode 防止中文亂碼
String fileName = URLEncoder.encode("用戶信息表", "UTF-8").replaceAll("\\+", "%20");
// 設(shè)置響應頭
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
// 寫出Excel
EasyExcel.write(response.getOutputStream(), UserSheet.class).inMemory(true).sheet("用戶信息表").doWrite(Mock.userList());
} catch (IOException e) {
throw new RuntimeException("數(shù)據(jù)或文件損壞,無法下載");
}
}
/**
* 在Excel中寫入多個sheet
*
* @url <a>http://localhost:8080/export/test2</a>
*/
@RequestMapping("/test2")
public void test2(HttpServletResponse response) throws Exception {
// 設(shè)置響應類型
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
// 設(shè)置編碼格式
response.setCharacterEncoding("utf-8");
// 設(shè)置URLEncoder.encode 防止中文亂碼
String fileName = URLEncoder.encode("信息表", "UTF-8").replaceAll("\\+", "%20");
// 設(shè)置響應頭
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
// 多個sheet的輸出需要使用ExcelWriter類,這里想要下載成功,需要輸出到OutputStream中
try (ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).inMemory(true).build()) {
// 創(chuàng)建用戶信息表的sheet,寫入用戶信息數(shù)據(jù),1代表sheet的位置是第一個
WriteSheet userInfoSheet = EasyExcel.writerSheet(0, "用戶信息表").head(UserSheet.class).build();
excelWriter.write(Mock.userList(), userInfoSheet);
// 創(chuàng)建城市信息表的sheet,寫入城市信息數(shù)據(jù),2代表sheet的位置是第二個
WriteSheet cityInfoSheet = EasyExcel.writerSheet(1, "城市信息表").head(CitySheet.class).build();
excelWriter.write(Mock.cityList(), cityInfoSheet);
// 創(chuàng)建公司信息表的sheet,寫入公司信息數(shù)據(jù),3代表sheet的位置是第三個
WriteSheet companyInfoSheet = EasyExcel.writerSheet(2, "公司信息表").head(CompanySheet.class).build();
excelWriter.write(Mock.companyList(), companyInfoSheet);
}
}
}Mock.java
以下數(shù)據(jù)均來自于網(wǎng)絡(luò),如有侵權(quán),請聯(lián)系刪除
package com.example.springbooteasyexcel.data;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.data.RichTextStringData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.example.springbooteasyexcel.sheet.CitySheet;
import com.example.springbooteasyexcel.sheet.CompanySheet;
import com.example.springbooteasyexcel.sheet.UserSheet;
import org.apache.poi.ss.usermodel.IndexedColors;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
public class Mock {
public static List<UserSheet> userList() {
List<UserSheet> list = new ArrayList<>(10);
list.add(UserSheet.builder().userId(001L).userName("張三").userPhone("11112223123").userEmail("zhansan@163.com").userAddress("北京朝陽區(qū)").gender(buildCellData("男")).registerTime(Calendar.getInstance().getTime()).build());
list.add(UserSheet.builder().userId(002L).userName("李四").userPhone("11112223123").userEmail("lisi@qq.com").userAddress("南京玄武門").gender(buildCellData("女")).registerTime(Calendar.getInstance().getTime()).build());
list.add(UserSheet.builder().userId(003L).userName("王五").userPhone("11112223123").userEmail("wangwu@google.com").userAddress("杭州未來科技城").gender(buildCellData("男")).registerTime(Calendar.getInstance().getTime()).build());
list.add(UserSheet.builder().userId(004L).userName("趙六").userPhone("11112223123").userEmail("zhaoliu@baidu.com").userAddress("上海徐家匯").gender(buildCellData("女")).registerTime(Calendar.getInstance().getTime()).build());
return list;
}
private static WriteCellData<String> buildCellData(String gender) {
// 設(shè)置單個單元格多種樣式
WriteCellData<String> cellData = new WriteCellData<>();
// 設(shè)置單個單元格的填充類型
cellData.setType(CellDataTypeEnum.RICH_TEXT_STRING);
RichTextStringData richTextStringData = new RichTextStringData();
cellData.setRichTextStringDataValue(richTextStringData);
richTextStringData.setTextString(gender);
WriteFont writeFont = new WriteFont();
if ("男".equalsIgnoreCase(gender)) {
//設(shè)置顏色為紅色
writeFont.setColor(IndexedColors.RED.getIndex());
} else if ("女".equalsIgnoreCase(gender)) {
//設(shè)置顏色為綠色
writeFont.setColor(IndexedColors.GREEN.getIndex());
}
//應用顏色字體
richTextStringData.applyFont(writeFont);
return cellData;
}
public static List<CitySheet> cityList() {
List<CitySheet> list = new ArrayList<>(10);
list.add(CitySheet.builder().cityName("杭州市").cityDesc("杭州市一般指杭州。 杭州,簡稱“杭”,古稱臨安、錢塘,浙江省轄地級市、省會、副省級市、特大城市、國務院批復確定的浙江省經(jīng)濟、文化、科教中心,長江三角洲中心城市之一,環(huán)杭州灣大灣區(qū)核心城市、G60科創(chuàng)走廊中心城市。").build());
list.add(CitySheet.builder().cityName("合肥市").cityDesc("合肥市一般指合肥。 合肥,簡稱“廬”或“合”,古稱廬州、廬陽、合淝,安徽省轄地級市、省會,是合肥都市圈中心城市,國務院批復確定的中國長三角城市群副中心城市,全國四大科教基地、現(xiàn)代制造業(yè)基地和綜合交通樞紐。").build());
list.add(CitySheet.builder().cityName("武漢市").cityDesc("武漢市一般指武漢。 武漢,簡稱“漢”,別稱江城,是湖北省省會,中部六省唯一的副省級市,超大城市,中國中部地區(qū)的中心城市,全國重要的工業(yè)基地、科教基地和綜合交通樞紐,聯(lián)勤保障部隊機關(guān)駐地。").build());
list.add(CitySheet.builder().cityName("深圳市").cityDesc("深圳市一般指深圳。 深圳,簡稱“深”,別稱鵬城,廣東省轄地級市,是廣東省副省級市,國家計劃單列市,超大城市,國務院批復確定的中國經(jīng)濟特區(qū)、全國性經(jīng)濟中心城市、國際化城市、科技創(chuàng)新中心、區(qū)域金融中心、商貿(mào)物流中心。").build());
return list;
}
public static List<CompanySheet> companyList() {
List<CompanySheet> list = new ArrayList<>(10);
list.add(CompanySheet.builder().companyName("阿里巴巴").companyBoss("馬云").companyBase("杭州市").companyDesc("阿里巴巴集團經(jīng)營多項業(yè)務,另外也從關(guān)聯(lián)公司的業(yè)務和服務中取得經(jīng)營商業(yè)生態(tài)系統(tǒng)上的支援。業(yè)務和關(guān)聯(lián)公司的業(yè)務包括:淘寶網(wǎng)、天貓、聚劃算、全球速賣通、阿里巴巴國際交易市場、1688、阿里媽媽、阿里云、螞蟻集團 [408] 、菜鳥網(wǎng)絡(luò)等。").build());
list.add(CompanySheet.builder().companyName("字節(jié)跳動").companyBoss("張一鳴").companyBase("北京市").companyDesc("字節(jié)跳動的全球化布局始于2015年 [3] ,“技術(shù)出海”是字節(jié)跳動全球化發(fā)展的核心戰(zhàn)略 [4] ,其旗下產(chǎn)品有今日頭條、西瓜視頻、抖音、頭條百科、皮皮蝦、懂車帝、悟空問答等。").build());
list.add(CompanySheet.builder().companyName("騰訊").companyBoss("馬化騰").companyBase("深圳市").companyDesc("社交和通信服務QQ及微信/WeChat、社交網(wǎng)絡(luò)平臺QQ空間、騰訊游戲旗下QQ游戲平臺、門戶網(wǎng)站騰訊網(wǎng)、騰訊新聞客戶端和網(wǎng)絡(luò)視頻服務騰訊視頻等。").build());
list.add(CompanySheet.builder().companyName("百度").companyBoss("李彥宏").companyBase("北京市").companyDesc("百度(Baidu)是擁有強大互聯(lián)網(wǎng)基礎(chǔ)的領(lǐng)先AI公司。百度愿景是:成為最懂用戶,并能幫助人們成長的全球頂級高科技公司。").build());
return list;
}
}CitySheet.java
package com.example.springbooteasyexcel.sheet;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class CitySheet {
@ExcelProperty(value = "城市名稱", index = 0)
@ColumnWidth(10)
private String cityName;
@ExcelProperty(value = "城市介紹", index = 1)
@ColumnWidth(60)
private String cityDesc;
}CompanySheet.java
package com.example.springbooteasyexcel.sheet;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class CompanySheet {
@ExcelProperty(value = "公司名稱", index = 0)
@ColumnWidth(10)
private String companyName;
@ExcelProperty(value = "公司創(chuàng)始人", index = 1)
@ColumnWidth(10)
private String companyBoss;
@ExcelProperty(value = "公司總基地", index = 2)
@ColumnWidth(10)
private String companyBase;
@ExcelProperty(value = "公司簡介", index = 3)
@ColumnWidth(50)
private String companyDesc;
}UserSheet.java
package com.example.springbooteasyexcel.sheet;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.metadata.data.WriteCellData;
import lombok.Builder;
import lombok.Data;
import java.util.Date;
@Data
@Builder
public class UserSheet {
@ExcelProperty(value = "用戶ID", index = 0)
@ColumnWidth(10)
private Long userId;
@ExcelProperty(value = "用戶名稱", index = 1)
@ColumnWidth(10)
private String userName;
@ExcelProperty(value = {"基本信息", "手機號碼"}, index = 2)
@ColumnWidth(20)
private String userPhone;
@ExcelProperty(value = {"基本信息", "電子郵箱"}, index = 3)
@ColumnWidth(20)
private String userEmail;
@ExcelProperty(value = {"基本信息", "地址"}, index = 4)
@ColumnWidth(20)
private String userAddress;
@ExcelProperty(value = "注冊時間", index = 5)
@ColumnWidth(20)
private Date registerTime;
@ExcelProperty(value = "性別,男:紅色/女:綠色")
@ColumnWidth(30)
private WriteCellData<String> gender;
/**
* 忽略這個字段
*/
@ExcelIgnore
private Integer age;
}SpringBootEasyexcelApplication.java
package com.example.springbooteasyexcel;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootEasyexcelApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootEasyexcelApplication.class, args);
}
}4.效果展示
單個sheet導出

多個sheet導出



5.總結(jié)
- 1、Alibaba EasyExcel不僅支持寫Excel,還支持讀Excel和填充Excel,有興趣的話可以自己去研究,官網(wǎng)地址已經(jīng)貼在上面了,我這里只做一個引路的。
- 2、常用注解有三個
@ExcelProperty、@ColumnWidth、@ExcelIgnore。 (1)@ExcelProperty不僅確定表頭,還可以合并行,用法如下:
@ExcelProperty(value = {"基本信息", "手機號碼"}, index = 2)
@ColumnWidth(20)
private String userPhone;
@ExcelProperty(value = {"基本信息", "電子郵箱"}, index = 3)
@ColumnWidth(20)
private String userEmail;
@ExcelProperty(value = {"基本信息", "地址"}, index = 4)
@ColumnWidth(20)
private String userAddress;效果如下:

- (2)
@ColumnWidth主要是控制列寬 - (3)
@ExcelIgnore忽略不需要輸出的字段 3、寫有兩種形式 (1)寫到文件
/**
* 最簡單的寫
* <p>
* 1. 創(chuàng)建excel對應的實體對象 參照{(diào)@link DemoData}
* <p>
* 2. 直接寫即可
*/
@Test
public void simpleWrite() {
// 注意 simpleWrite在數(shù)據(jù)量不大的情況下可以使用(5000以內(nèi),具體也要看實際情況),數(shù)據(jù)量大參照 重復多次寫入
// 寫法1 JDK8+
// since: 3.0.0-beta1
String fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
// 這里 需要指定寫用哪個class去寫,然后寫到第一個sheet,名字為模板 然后文件流會自動關(guān)閉
// 如果這里想使用03 則 傳入excelType參數(shù)即可
EasyExcel.write(fileName, DemoData.class)
.sheet("模板")
.doWrite(() -> {
// 分頁查詢數(shù)據(jù)
return data();
});
// 寫法2
fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
// 這里 需要指定寫用哪個class去寫,然后寫到第一個sheet,名字為模板 然后文件流會自動關(guān)閉
// 如果這里想使用03 則 傳入excelType參數(shù)即可
EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());
// 寫法3
fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
// 這里 需要指定寫用哪個class去寫
try (ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build()) {
WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
excelWriter.write(data(), writeSheet);
}
}(2)寫到Web流,這里的ContentType和CharacterEncoding不要亂碼,否則很容易亂碼或者文件損壞
/**
* 文件下載(失敗了會返回一個有部分數(shù)據(jù)的Excel)
* <p>
* 1. 創(chuàng)建excel對應的實體對象 參照{(diào)@link DownloadData}
* <p>
* 2. 設(shè)置返回的 參數(shù)
* <p>
* 3. 直接寫,這里注意,finish的時候會自動關(guān)閉OutputStream,當然你外面再關(guān)閉流問題不大
*/
@GetMapping("download")
public void download(HttpServletResponse response) throws IOException {
// 這里注意 有同學反應使用swagger 會導致各種問題,請直接用瀏覽器或者用postman
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
// 這里URLEncoder.encode可以防止中文亂碼 當然和easyexcel沒有關(guān)系
String fileName = URLEncoder.encode("測試", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data());
}到此這篇關(guān)于SpringBoot整合EasyExcel實現(xiàn)Excel表格導出功能的文章就介紹到這了,更多相關(guān)SpringBoot整合EasyExcel內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MyBatisPlus查詢報錯Unknow?column?‘id‘?in?‘field?list‘解決分析
這篇文章主要為大家介紹了MyBatisPlus查詢報錯Unknow?column?‘id‘?in?‘field?list‘解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-09-09
詳解Mybatis核心類SqlSessionFactory的構(gòu)建
這篇文章主要為大家詳細介紹了Mybatis核心類SqlSessionFactory的構(gòu)建過程,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下2022-12-12
SpringBoot實戰(zhàn)記錄之數(shù)據(jù)訪問
對于數(shù)據(jù)訪問層,無論是SQL還是NOSQL,Spring Boot默認采用整合Spring Data的方式進行統(tǒng)一處理,添加大量自動配置,屏蔽了很多設(shè)置,下面這篇文章主要介紹了SpringBoot實戰(zhàn)記錄之數(shù)據(jù)訪問,需要的朋友可以參考下2022-04-04
SpringBoot中@ConfigurationProperties注解實現(xiàn)配置綁定的三種方法
這篇文章主要介紹了SpringBoot中@ConfigurationProperties注解實現(xiàn)配置綁定的三種方法,文章內(nèi)容介紹詳細需要的小伙伴可以參考一下2022-04-04

