# 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 list = userService.selectUserList(user); ExcelUtil util = new ExcelUtil(SysUser.class); util.exportExcel(response, list, "用户数据"); ``` **When** 替换为 EasyExcel 实现 **Then** 代码应无需修改即可正常工作 #### Scenario: 使用现有导入方法 **Given** 现有导入代码 ```java ExcelUtil util = new ExcelUtil(SysUser.class); List userList = util.importExcel(file.getInputStream()); ``` **When** 替换为 EasyExcel 实现 **Then** 代码应无需修改即可正常工作 --- ## REMOVED Requirements ### 无 此变更不删除任何现有功能需求,仅替换底层实现。