333 lines
8.3 KiB
Markdown
333 lines
8.3 KiB
Markdown
|
|
# 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
|
|||
|
|
|
|||
|
|
### 无
|
|||
|
|
|
|||
|
|
此变更不删除任何现有功能需求,仅替换底层实现。
|