Files
ccdi/openspec/changes/replace-poi-with-easyexcel/specs/excel-import-export/spec.md

333 lines
8.3 KiB
Markdown
Raw Normal View History

2026-01-27 17:55:53 +08:00
# Spec: Excel Import/Export with EasyExcel
## ADDED Requirements
### Requirement: 流式导出大量数据
The system **MUST** support streaming export using EasyExcel to handle datasets exceeding 100,000 rows while maintaining low memory footprint.
系统**必须**支持使用 EasyExcel 进行流式导出,以处理超过 10 万行的数据集,同时保持低内存占用。
#### Scenario: 导出 10 万行用户数据
**Given** 系统中有 10 万条用户记录
**When** 管理员调用用户导出接口
**Then** 系统应:
- 成功生成包含 10 万行数据的 Excel 文件
- 内存占用不超过 500MB
- 导出时间在合理范围内(< 30 秒)
- 生成的文件包含所有必要的表头和样式
#### Scenario: 导出超过 65536 行数据
**Given** 数据集包含 10 万行记录(超过传统 Excel 限制)
**When** 调用导出功能
**Then** 系统应:
- 自动使用 .xlsx 格式
- 不进行 Sheet 分割EasyExcel 自动处理)
- 所有数据完整导出到单个文件
---
### Requirement: 流式导入大文件
The system **MUST** support streaming import using EasyExcel to process Excel files larger than 100MB.
系统**必须**支持使用 EasyExcel 进行流式读取,以处理超过 100MB 的 Excel 文件。
#### Scenario: 导入包含 10 万行数据的 Excel 文件
**Given** 一个包含 10 万行数据的 Excel 文件(约 50MB
**When** 管理员上传该文件进行导入
**Then** 系统应:
- 逐行解析文件,不一次性加载到内存
- 内存占用不超过 200MB
- 正确解析所有数据行
- 返回完整的解析结果列表
#### Scenario: 导入包含超长文本的单元格
**Given** Excel 文件中某些单元格包含超过 32,767 个字符(超过 POI 限制)
**When** 执行导入操作
**Then** 系统应:
- 完整读取单元格内容
- 不截断或丢失数据
- 正确映射到实体类字段
---
### Requirement: 保持注解驱动配置兼容性
The system **MUST** maintain compatibility with existing `@Excel` and `@Excels` annotations, allowing existing entity classes to work without modification.
系统**必须**保持与现有 `@Excel``@Excels` 注解的兼容性,使现有实体类无需修改即可使用新实现。
#### Scenario: 使用现有注解导出数据
**Given** 实体类上已定义 `@Excel` 注解
```java
@Excel(name = "用户名", sort = 1)
private String userName;
@Excel(name = "性别", dictType = "sys_user_sex", sort = 2)
private String sex;
@Excel(name = "创建时间", dateFormat = "yyyy-MM-dd HH:mm:ss", sort = 3)
private Date createTime;
```
**When** 调用导出功能
**Then** 系统应:
- 正确解析 `@Excel` 注解配置
- 按指定的 `sort` 顺序排列列
- 应用字典转换(`dictType`
- 应用日期格式化(`dateFormat`
- 生成包含正确表头的 Excel 文件
#### Scenario: 使用复合注解导出嵌套属性
**Given** 实体类使用 `@Excels` 注解配置多个导出规则
```java
@Excels({
@Excel(name = "部门名称", targetAttr = "deptName", sort = 10),
@Excel(name = "部门编码", targetAttr = "deptCode", sort = 11)
})
private SysDept dept;
```
**When** 调用导出功能
**Then** 系统应:
- 正确解析嵌套对象属性
- 生成多个对应的列
- 正确填充数据
---
### Requirement: 样式与格式支持
The system **SHALL** support basic cell styling configuration through annotations, including alignment, background color, etc.
系统**应当**支持通过注解配置基本的单元格样式,包括对齐方式、背景色等。
#### Scenario: 应用自定义样式
**Given** 实体类定义了样式配置
```java
@Excel(
name = "金额",
align = HorizontalAlignmentEnum.RIGHT,
backgroundColor = "yellow",
color = "red",
sort = 5
)
private BigDecimal amount;
```
**When** 导出数据
**Then** 系统应:
- 单元格内容右对齐
- 背景色为黄色
- 字体颜色为红色
#### Scenario: 数字格式化
**Given** 字段配置了精度和舍入模式
```java
@Excel(name = "单价", scale = 2, roundingMode = BigDecimal.ROUND_HALF_UP)
private BigDecimal price;
```
**When** 导出包含该字段的数据
**Then** 系统应:
- 数值保留 2 位小数
- 使用四舍五入规则
---
### Requirement: 导入模板生成
The system **MUST** support generating empty import templates for users to fill and upload.
系统**必须**支持生成空的导入模板,供用户填写后上传。
#### Scenario: 生成导入模板
**Given** 实体类配置了 `@Excel` 注解,其中部分字段标记为仅导入
```java
@Excel(name = "用户名", type = Type.ALL)
private String userName;
@Excel(name = "密码", type = Type.IMPORT) // 仅导入
private String password;
```
**When** 调用 `importTemplateExcel()` 方法
**Then** 系统应:
- 生成包含所有 `type=IMPORT``type=ALL` 字段的表头
- 仅导入字段(`type=IMPORT`)不出现在模板中
- 应用数据验证配置(如果有)
- 设置合适的列宽
---
### Requirement: 字段筛选功能
The system **MUST** support runtime control of exported fields.
系统**必须**支持运行时动态控制导出包含的字段。
#### Scenario: 显示指定字段
**Given** 实体类有 20 个字段,但只想导出其中 5 个
**When** 调用 `util.showColumn("id", "name", "email", "phone", "status")`
**Then** 导出的 Excel 应:
- 仅包含指定的 5 个字段
- 其他字段不出现在导出结果中
#### Scenario: 排除指定字段
**Given** 实体类有 20 个字段,想导出其中 18 个
**When** 调用 `util.hideColumn("password", "salt")`
**Then** 导出的 Excel 应:
- 包含除 `password``salt` 外的所有字段
- 敏感字段不出现在导出结果中
---
### Requirement: 自定义数据处理器
The system **MUST** support custom data handlers for special cell data processing.
系统**必须**支持通过自定义处理器对单元格数据进行特殊处理。
#### Scenario: 使用自定义处理器格式化数据
**Given** 定义了自定义处理器
```java
public class CustomAmountHandler implements ExcelHandlerAdapter {
@Override
public Object format(Object value, String[] args, Cell cell, Workbook wb) {
// 将金额转换为中文大写
return convertToChinese((BigDecimal) value);
}
}
```
**And** 实体字段配置使用该处理器
```java
@Excel(name = "金额(大写)", handler = CustomAmountHandler.class)
private BigDecimal amount;
```
**When** 导出数据
**Then** 金额列应显示为中文大写形式(如:壹万贰仟叁佰肆拾伍元陆角柒分)
---
### Requirement: 数据验证支持
The system **SHALL** support configuring dropdown options and prompt information for import templates.
系统**应当**支持为导入模板配置下拉选项和提示信息。
#### Scenario: 配置下拉选项
**Given** 字段配置了固定的下拉选项
```java
@Excel(name = "状态", combo = {"启用", "禁用"})
private String status;
```
**When** 生成导入模板
**Then** 该单元格应:
- 显示下拉箭头
- 仅能选择"启用"或"禁用"
- 无法输入其他值
#### Scenario: 从字典读取下拉选项
**Given** 字段配置从字典读取选项
```java
@Excel(name = "性别", dictType = "sys_user_sex", comboReadDict = true)
private String sex;
```
**When** 生成导入模板
**Then** 该单元格的下拉列表应:
- 包含字典中定义的所有选项
- 动态从系统缓存读取
---
## MODIFIED Requirements
### Requirement: ExcelUtil API 兼容性
The modified `ExcelUtil` **MUST** maintain API compatibility with existing code.
修改后的 `ExcelUtil` **必须**保持与现有代码的 API 兼容性。
#### Scenario: 使用现有导出方法
**Given** 现有 Controller 代码
```java
List<SysUser> list = userService.selectUserList(user);
ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
util.exportExcel(response, list, "用户数据");
```
**When** 替换为 EasyExcel 实现
**Then** 代码应无需修改即可正常工作
#### Scenario: 使用现有导入方法
**Given** 现有导入代码
```java
ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
List<SysUser> userList = util.importExcel(file.getInputStream());
```
**When** 替换为 EasyExcel 实现
**Then** 代码应无需修改即可正常工作
---
## REMOVED Requirements
### 无
此变更不删除任何现有功能需求,仅替换底层实现。