老碼農教你:Solon + EasyExcel 導出工具
關于 "Excel 導出" ——POI API 是比較復雜的,CellStyle 能把人調得眼冒金星,大數據量導出時內存飆到 90% 的恐懼至今難忘。直到發現了 Alibaba 的 EasyExcel,從此打開新世界的大門。今天就把這套 "導出救命錦囊" 分享給大家,順便穿插點踩坑經驗。
一、先整合項目環境
1. 引入依賴
首先在 pom.xml 里加依賴,這里得注意版本兼容性。加完后記得刷新 Maven。
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-web</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>4.0.3</version>
</dependency>
2. 創建實體類
定義 Excel 里每一列的數據結構,就像給每個字段安排 "座位"。比如導出用戶信息:
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import lombok.Data;
import java.util.Date;
@Data
public class UserExcelVO {
// 這里是表頭名稱,寬度設置成20
@ExcelProperty(value = "用戶ID", index = 0)
@ColumnWidth(20)
private Long userId;
// 設定日期為"yyyy-MM-dd"格式
@ExcelProperty(value = "注冊時間", index = 1)
@DateTimeFormat("yyyy-MM-dd")
private Date registerTime;
// 性別要轉換為友好描述
@ExcelProperty(value = "性別", index = 2, converter = SexConverter.class)
private Integer sex;
}
這里的 @ExcelProperty 就像給數據貼標簽,index是列順序。別標錯號,不然數據錯位時會懷疑人生 —— 筆者曾把金額和年齡的位置搞反,會被財務小姐姐罵得狗血淋頭。
3. 編寫導出工具類:避免重復工作
把通用導出邏輯封裝起來,以后每次導出就簡單了。創建EasyExcelUtils:
import com.alibaba.excel.EasyExcel;
import org.noear.solon.core.handle.Context;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;
public class EasyExcelUtils {
public static <T> void exportExcel(Context ctx,
List<T> dataList,
Class<T> clazz,
String fileName) throws IOException {
ctx.contentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
ctx.charset("utf-8");
// 文件名得處理中文,不然下載下來是亂碼
fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
ctx.headerSet("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
// 這里用EasyExcel.write()就像啟動一個Excel生成器
EasyExcel.write(ctx.outputStream(), clazz)
.sheet("數據報表")
.doWrite(dataList);
}
}
二、實戰演練:從 "基礎導出" 到 "高深玩法"
1. 基礎導出
import org.noear.solon.annotation.*;
import org.noear.solon.core.handle.Context;
import java.io.IOException;
import java.util.List;
@Controller
public class DemoController {
@Inject
UserService userService;
@Get
@Mapping("/exportUser")
public void exportUser(Context ctx) throws IOException {
List<UserExcelVO> dataList = userService.getUserListForExport(); // 假設這是從數據庫查的數據
EasyExcelUtils.exportExcel(ctx, dataList, UserExcelVO.class, "用戶信息表");
}
}
2. 復雜表頭,加一層分類
有時候表頭需要多級結構,比如 "用戶信息" 下分 "基本信息"" 聯系方式 "。這時候需要用@ExcelProperty的數組形式:
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
@Data
public class ComplexHeaderVO {
@ExcelProperty({"用戶信息", "用戶ID"})
private Long userId;
@ExcelProperty({"用戶信息", "姓名"})
private String userName;
@ExcelProperty({"聯系方式", "手機號"})
private String phone;
@ExcelProperty({"聯系方式", "郵箱"})
private String email;
}
3. 合并單元格
比如導出報表時需要合并相同內容的單元格,這時候得自定義CellWriteHandler。舉個例子,合并連續相同的部門名稱:
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.handler.context.CellWriteHandlerContext;
public class MergeCellHandler implements CellWriteHandler {
@Override
public void afterCellDispose(CellWriteHandlerContext context) {
// 這里省略具體實現,核心是通過行號和列號判斷是否合并
// 就像拼拼圖,找到相同的部分粘在一起
}
}
在導出時注冊這個處理器:
EasyExcel.write(...)
.registerWriteHandler(new MergeCellHandler())
.doWrite(...);
4. 自定義格式:美化效果
比如金額需要顯示成 "¥1,000.00",日期要顯示成 "2025 年 5 月 29 日"。除了前面提到的 @DateTimeFormat,數值格式可以用 @NumberFormat:
@ExcelProperty("金額")
@NumberFormat("#,##0.00")
private Double amount;
5. 大數據量導出,要避免 OOM
當數據量超過 10 萬條時,直接導出會OOM的,這時候要用流式處理。EasyExcel 貼心地支持分頁導出,分批次寫入:
EasyExcel.write(ctx.outputStream(), UserExcelVO.class)
.sheet("大數據報表")
.registerWriteHandler(...) // 可選的樣式處理器
.doWrite(new AnalysisContext() -> {
// 這里每次調用獲取一頁數據,直到沒有數據為止
List<UserExcelVO> pageData = userService.getPageData(analysisContext.readRowHolder().getRowIndex());
return pageData;
});
三、避坑指南
1. 依賴沖突:當 Maven 開始 "鬧別扭"
如果有引入舊版 POI 依賴,可能會和 EasyExcel 的 POI 版本沖突。這時候可用 mvn dependency:tree 命令排查,然后在pom.xml里用排除沖突項。
2. 注解優先級:別讓 "標簽" 打架
@ExcelProperty 可以寫在字段上或方法上,建議統一寫在字段上,不然容易混亂。
3. 樣式設置:別把 Excel 變成 "花臉貓"
雖然 EasyExcel 支持自定義樣式,但別過度使用,比如給每個單元格設置不同顏色,導出的 Excel 可能打不開。樣式設置要適度,就像化妝,自然美就好。

浙公網安備 33010602011771號