122 lines
4.1 KiB
Markdown
122 lines
4.1 KiB
Markdown
# Proposal: Replace Apache POI with Alibaba EasyExcel
|
||
|
||
## Summary
|
||
|
||
将若依框架中的 Apache POI 替换为 Alibaba EasyExcel,以解决大文本量 Excel 导入导出时的内存占用和性能问题。当前使用 POI 的 SXSSFWorkbook 虽然支持流式写入,但在处理大量数据时仍然存在性能瓶颈,且不支持真正的流式读取。
|
||
|
||
## Motivation
|
||
|
||
### 问题分析
|
||
|
||
1. **当前 POI 实现的限制**:
|
||
- `ExcelUtil.java:112` - `sheetSize` 硬编码为 65536,这是 Excel 2003 的限制
|
||
- `ExcelUtil.java:1682` - 使用 SXSSFWorkbook 进行流式写入,但内存优化有限
|
||
- `ExcelUtil.java:325-525` - `importExcel` 方法一次性加载整个 Sheet 到内存,无法处理大文件
|
||
- POI 的 DOM 解析模式导致大文件内存占用过高
|
||
|
||
2. **业务需求**:
|
||
- 需要支持导入导出超过 10 万行数据
|
||
- 需要支持单元格内容超过 32767 字符(POI STRING 类型限制)
|
||
- 需要降低内存占用,避免 OOM
|
||
|
||
3. **EasyExcel 优势**:
|
||
- 基于 SAX 解析,真正的流式读写
|
||
- 内存占用仅与行数据大小相关,与文件大小无关
|
||
- API 设计简洁,注解驱动
|
||
- 官方维护活跃,社区成熟
|
||
|
||
## Proposed Solution
|
||
|
||
### 技术方案
|
||
|
||
1. **保持 API 兼容性**:
|
||
- 保留 `@Excel` 和 `@Excels` 注解接口
|
||
- 保留 `ExcelUtil<T>` 的公共方法签名
|
||
- 保留 `ExcelHandlerAdapter` 接口(适配 EasyExcel 的写处理器)
|
||
|
||
2. **核心实现变更**:
|
||
- 使用 `EasyExcel.write()` 替代 POI 的 Workbook/Sheet 操作
|
||
- 使用 `EasyExcel.read()` 替代 POI 的 Workbook 解析
|
||
- 实现自定义的 `HeadGenerator` 和 `ContentStyleStrategy` 以支持样式
|
||
|
||
3. **依赖变更**:
|
||
- 移除 `poi-ooxml` 依赖
|
||
- 添加 `easyexcel` 依赖(版本 3.3.4,支持 Spring Boot 3)
|
||
|
||
### 影响范围
|
||
|
||
**修改的文件**:
|
||
- `ruoyi-common/pom.xml` - 更新依赖
|
||
- `ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java` - 重写实现
|
||
- `ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java` - 调整注解属性
|
||
- `ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelHandlerAdapter.java` - 适配新接口
|
||
|
||
**无需修改的文件**(向后兼容):
|
||
- 所有 Controller 层代码(13 个文件使用 ExcelUtil)
|
||
- 实体类上的 `@Excel` 注解
|
||
|
||
## Alternatives Considered
|
||
|
||
### 方案 1:升级 POI 版本
|
||
- **优点**:代码改动最小
|
||
- **缺点**:无法从根本上解决内存问题,POI 的架构限制依然存在
|
||
|
||
### 方案 2:使用 Hutool 的 Excel 工具
|
||
- **优点**:API 简洁
|
||
- **缺点**:底层仍使用 POI,内存问题未解决
|
||
|
||
### 方案 3:使用 EasyExcel(选定方案)
|
||
- **优点**:真正的流式处理,内存占用低,社区成熟
|
||
- **缺点**:需要适配现有注解和 API
|
||
|
||
## Compatibility Notes
|
||
|
||
### 破坏性变更
|
||
|
||
1. **样式支持**:EasyExcel 的样式支持有限,以下功能可能需要简化:
|
||
- 合并单元格(`needMerge`)
|
||
- 图片插入(`ColumnType.IMAGE`)
|
||
- 数据验证(`combo`, `comboReadDict`)
|
||
- 自定义颜色(`headerBackgroundColor`, `color` 等)
|
||
|
||
2. **Sheet 分割**:EasyExcel 自动处理大文件,无需手动分割 Sheet
|
||
|
||
3. **统计行**:`isStatistics` 需要通过监听器实现
|
||
|
||
### 保留的功能
|
||
|
||
- ✅ 注解驱动配置
|
||
- ✅ 字典类型转换(`dictType`)
|
||
- ✅ 表达式转换(`readConverterExp`)
|
||
- ✅ 日期格式化(`dateFormat`)
|
||
- ✅ 导入/导出模板生成
|
||
- ✅ 字段筛选(`includeFields`, `excludeFields`)
|
||
|
||
## Success Criteria
|
||
|
||
1. **性能指标**:
|
||
- 导出 10 万行数据,内存占用 < 500MB
|
||
- 导入 100MB Excel 文件,内存占用 < 200MB
|
||
|
||
2. **功能完整性**:
|
||
- 所有现有 Controller 的导入导出功能正常工作
|
||
- 支持超过 65536 行数据
|
||
|
||
3. **兼容性**:
|
||
- 现有实体类注解无需修改
|
||
- 现有业务代码无需修改
|
||
|
||
## Timeline
|
||
|
||
阶段划分(具体任务见 tasks.md):
|
||
1. 依赖更新与环境准备
|
||
2. 核心 ExcelUtil 重写
|
||
3. 注解与接口适配
|
||
4. 集成测试与验证
|
||
5. 文档更新
|
||
|
||
## Related Changes
|
||
|
||
- 无前置依赖
|
||
- 可能影响:所有使用 Excel 导入导出的模块
|