
后端【免费下载链接】fesodFast. Easy. Done. Processing spreadsheets without worrying about large files causing OOM.项目地址https://gitcode.com/gh_mirrors/fast/fesod点击查看免费下载本篇技术指南聚焦 Apache FesodIncubating写 Sheet 时的“附加信息Extra Information”能力覆盖单元格批注Comment、超链接Hyperlink、公式Formula、基于模板的填充写入Template-based Writing以及通过写拦截器WriteHandler自定义下拉框等高级逻辑。读者将掌握如何在 extra.md 所描述的五大场景中写出可运行代码并理解其底层实现如WriteCellData元数据模型与AbstractExcelWriteExecutor的写入链路直接用于报表、表单和模板化输出的实战开发。一、为什么需要“附加信息”写入能力常规的 POJO 写操作只能表达“表头 一行行数据”。但在真实业务中表格往往还需要携带元信息某个单元格需要一段说明性批注、某个单元格需要可点击跳转的超链接、某个单元格需要根据其它列计算得出公式结果、整份文件需要基于既有模板生成甚至整列需要提供下拉选择。这些内容在 Apache Fesod 中被统一归类为“Extra Information”与普通数据写入正交但又共用同一套写执行器。从实现上看这些能力被收敛在单元格数据模型WriteCellDataTWriteCellData.java中该类继承自CellDataT额外持有CommentData commentData、HyperlinkData hyperlinkData、FormulaData相关的组合字段、ImageData列表、WriteCellStyle样式等属性因此一个单元格可以同时承载“值 批注 超链接 样式”的复合信息。写执行器 AbstractExcelWriteExecutor.java 在填充单元格时会依次调用fillComment(...)、fillHyperLink(...)、fillFormula(...)等方法见该文件第 94、97 行附近的调用将这些附加数据真正落盘到 POI 单元格对象上。二、给单元格写批注Comments2.1 适用场景批注用于给特定单元格附加说明或特殊提醒例如表头字段的释义、数据的口径说明。Fesod 通过自定义RowWriteHandler 拦截器实现在行处理完成后afterRowDispose拿到 POI 的Sheet对象直接创建绘图画布Drawing并挂载批注。2.2 自定义批注拦截器Slf4j public class CommentWriteHandler implements RowWriteHandler { Override public void afterRowDispose(RowWriteHandlerContext context) { if (BooleanUtils.isTrue(context.getHead())) { Sheet sheet context.getWriteSheetHolder().getSheet(); Drawing? drawingPatriarch sheet.createDrawingPatriarch(); // Create comment in first row, second column Comment comment drawingPatriarch.createCellComment( new XSSFClientAnchor(0, 0, 0, 0, (short) 1, 0, (short) 2, 1)); comment.setString(new XSSFRichTextString(Comments)); sheet.getRow(0).getCell(1).setCellComment(comment); } } }要点说明context.getHead()用于判断当前行是否为表头行。RowWriteHandlerContextRowWriteHandlerContext.java中head字段在填充fill场景下为null因此注释中提到“fill data 时为 null”判断时需使用BooleanUtils.isTrue(...)做空安全处理。XSSFClientAnchor的参数(short) 1, 0, (short) 2, 1表示批注锚点覆盖第 2 列B 列第 0~1 行区域即最终批注挂在B1单元格上。批注文本通过XSSFRichTextString写入支持富文本格式。2.3 启用拦截器并写文件Test public void commentWrite() { String fileName commentWrite System.currentTimeMillis() .xlsx; FesodSheet.write(fileName, DemoData.class) .inMemory(Boolean.TRUE) // Comments must enable in-memory mode .registerWriteHandler(new CommentWriteHandler()) .sheet() .doWrite(data()); }关键约束必须开启内存模式。inMemory(Boolean.TRUE)的本质是设置WriteWorkbook.setInMemory(...)。从 ExcelWriterBuilder.java 的源码注释可知Write excel in memory. Default false, the cache file is created and finally written to excel.Comment and RichTextString are only supported in memory mode.即默认false情况下 Excel 会先写缓存文件再落盘而批注与富文本字符串仅在内存模式下受支持因此使用批注前必须显式调用.inMemory(Boolean.TRUE)。2.4 写入结果批注被附加到B1单元格只有当鼠标悬停到该单元格时才会显示批注内容演示表格中 B1 上以 Comments 角标形式呈现不影响其它单元格的取值。三、给单元格写超链接Hyperlinks3.1 POJO 中使用 WriteCellData超链接不再依赖拦截器而是直接通过单元格数据类型WriteCellDataT表达。POJO 中把对应字段声明为WriteCellDataStringGetter Setter EqualsAndHashCode public class WriteCellDemoData { private WriteCellDataString hyperlink; }3.2 组装 HyperlinkData 并写入Test public void writeHyperlinkDataWrite() { String fileName writeCellDataWrite System.currentTimeMillis() .xlsx; WriteCellDemoData data new WriteCellDemoData(); // Set hyperlink WriteCellData cellData new WriteCellData(Click to visit); HyperlinkData hyperlinkData new HyperlinkData(); hyperlinkData.setAddress(https://example.com); hyperlinkData.setHyperlinkType(HyperlinkData.HyperlinkType.URL); cellData.setHyperlinkData(hyperlinkData); data.setHyperlink(cellData); FesodSheet.write(fileName, WriteCellDemoData.class) .sheet() .doWrite(Collections.singletonList(data)); }3.3 底层原理HyperlinkData 与超链接类型HyperlinkDataHyperlinkData.java继承自CoordinateData包含两个核心字段address超链接目标地址注释明确其为 “URL, e-mail, path to a file, etc”即可不局限于网页地址hyperlinkType枚举HyperlinkType共五种取值NONE非超链接URL链接到已有网页或文件示例中的用法DOCUMENT链接到本文档内的某个位置书签/内部锚点EMAIL链接到邮箱地址FILE链接到某个文件。该枚举内部一一映射 POI 的org.apache.poi.common.usermodel.HyperlinkType。在写执行器 AbstractExcelWriteExecutor.java 的fillHyperLink(...)中通过StyleUtil.getHyperlinkType(hyperlinkData.getHyperlinkType())完成枚举转换再经helper.createHyperlink(...)创建超链接、hyperlink.setAddress(...)设置地址并依据HyperlinkData从CoordinateData继承的行列区间字段firstRowIndex、firstColumnIndex等均支持相对索引回退确定超链接覆盖的单元格区域最后cell.setHyperlink(hyperlink)挂载到目标单元格。换言之HyperlinkData同时承载了“地址 类型 作用区域”三部分信息。3.4 写入结果写入后 A2 单元格显示为可点击文本 “Click to visit”点击即跳转到所配置的地址演示表格中呈现为带链接样式的内容表头为 “hyperlink”。四、给单元格写公式Formulas4.1 POJO 中使用 WriteCellData公式同样走WriteCellData路径。POJO 中既包含普通数值列也包含承载公式的列Getter Setter EqualsAndHashCode public class WriteCellDemoData { private Integer num1; private Integer num2; private WriteCellDataString formulaData; }4.2 组装 FormulaData 并写入Test public void writeFormulaDataWrite() { String fileName writeCellDataWrite System.currentTimeMillis() .xlsx; WriteCellDemoData data new WriteCellDemoData(); data.setNum1(10); data.setNum2(20); // Set formula WriteCellDataString cellData new WriteCellData(); FormulaData formulaData new FormulaData(); formulaData.setFormulaValue(SUM(A2:B2)); // Or // formulaData.setFormulaValue(SUM(A2:B2)); cellData.setFormulaData(formulaData); data.setFormulaData(cellData); FesodSheet.write(fileName, WriteCellDemoData.class) .sheet() .doWrite(Collections.singletonList(data)); }4.3 底层原理FormulaData 与公式写入FormulaDataFormulaData.java结构非常轻量只有一个formulaValue字段提供clone()方法用于内部拷贝。在 AbstractExcelWriteExecutor.java 的fillFormula(...)中逻辑为若formulaData与formulaValue均非空则直接调用cell.setCellFormula(formulaData.getFormulaValue())。两个值得注意的细节公式字符串带不带前导均可。示例注释中同时给出SUM(A2:B2)与SUM(A2:B2)两种写法因为 POI 的setCellFormula对两者均能识别公式引用的单元格以写入后的实际行号为准示例数据位于第 2 行因此SUM(A2:B2)即对num1A210与num2B220求和最终 C2 显示计算值为30。这意味着公式本身与数据行位置强耦合动态生成数据时建议按实际起始行号拼接公式。五、基于模板的写入Template-based Writing5.1 适用场景当输出需要保持固定版式Logo、合并单元格、预设样式、页眉页脚等时可以预先制作一个.xlsx模板文件再让 Fesod 把数据填充进模板适合标准化输出场景。5.2 代码示例Test public void templateWrite() { String templateFileName path/to/template.xlsx; String fileName templateWrite System.currentTimeMillis() .xlsx; FesodSheet.write(fileName, DemoData.class) .withTemplate(templateFileName) .sheet() .doWrite(data()); }5.3 模板 API 与内存约束withTemplate在 ExcelWriterBuilder.java 中提供了三种重载InputStream、File、String字符串路径最终也会转换为File。源码注释给出明确警告Template file. This file is read into memory, excessive cases can lead to OOM.即模板文件会被整体读入内存模板过大时存在 OOM 风险因此超大模板应谨慎使用。这也与项目“处理大文件避免 OOM”的整体设计理念相呼应——常规写入默认走缓存文件非内存模式而模板属于例外场景。5.4 组合进阶模板写入可与前文的自定义拦截器叠加使用例如先在模板上通过SheetWriteHandler预设下拉框、批注或数据校验再填充业务数据模板负责“版式”拦截器负责“交互能力”数据写入负责“内容”。六、自定义拦截器实现下拉框Custom Interceptors6.1 适用场景写拦截器WriteHandler体系允许在写流程的关键节点插入自定义逻辑。除了前文批注用到的RowWriteHandler还有SheetWriteHandler、CellWriteHandler、WorkbookWriteHandler等接口定义见 write/handler 目录。下拉框数据校验下拉列表是SheetWriteHandler的典型应用在sheet 创建完成之后afterSheetCreate一次性为整列挂上数据校验。6.2 实现下拉框拦截器public class DropdownWriteHandler implements SheetWriteHandler { Override public void afterSheetCreate(SheetWriteHandlerContext context) { DataValidationHelper helper context.getWriteSheetHolder().getSheet().getDataValidationHelper(); CellRangeAddressList range new CellRangeAddressList(1, 10, 0, 0); // Dropdown area DataValidationConstraint constraint helper.createExplicitListConstraint(new String[] {Option1, Option2}); DataValidation validation helper.createValidation(constraint, range); context.getWriteSheetHolder().getSheet().addValidationData(validation); } }要点说明SheetWriteHandlerContextSheetWriteHandlerContext.java提供writeContext、writeWorkbookHolder、writeSheetHolder三个访问入口这里的getWriteSheetHolder().getSheet()即当前写入的 POI Sheetnew CellRangeAddressList(1, 10, 0, 0)定义校验作用区域第 1~10 行、第 0 列即A2:A11首行为表头故从第 2 行开始createExplicitListConstraint创建显式列表约束选项为{Option1, Option2}最后通过addValidationData(validation)把校验规则挂到 sheet 上。6.3 使用拦截器Test public void dropdownWrite() { String fileName dropdownWrite System.currentTimeMillis() .xlsx; FesodSheet.write(fileName, DemoData.class) .registerWriteHandler(new DropdownWriteHandler()) .sheet(Dropdown Example) .doWrite(data()); }.registerWriteHandler(...)在 AbstractExcelWriterParameterBuilder.java 中定义可多次调用注册多个处理器.sheet(Dropdown Example)为结果工作簿指定 sheet 名称。6.4 写入结果数据校验覆盖 A2:A11 整段区域区域内每个单元格都提供下拉选项列表点击单元格演示中 A2 展开即出现下拉按钮与 “Option1 / Option2” 两个候选选项其余行列数据正常写入示例表头为 String Title / Date Title / Number Title数据行 2~11。七、三类能力的选型速查能力实现载体需要拦截器需要内存模式数据载体批注 CommentRowWriteHandler.afterRowDispose是必须inMemory(true)POICommentDrawing超链接 HyperlinkWriteCellDataHyperlinkData否否WriteCellData#setHyperlinkData公式 FormulaWriteCellDataFormulaData否否WriteCellData#setFormulaData模板写入.withTemplate(...)否否但模板整体读入内存模板文件下拉框 DropdownSheetWriteHandler.afterSheetCreate是否POIDataValidation八、进一步阅读写入基础用法POJO、表头、样式、合并参考 write 目录 下的 pojo.md、head.md、style.md、merge.md单元格元数据模型见 WriteCellData.java 及其同目录下的HyperlinkData、FormulaData、CommentData写入执行核心链路见 AbstractExcelWriteExecutor.java其中fillComment/fillHyperLink/fillFormula是本文所述三要素的实际落盘点拦截器接口与上下文见 write/handler 目录下的RowWriteHandler、SheetWriteHandler及 context 目录下的对应上下文类模板参数与内存模式见 ExcelWriterBuilder.java重点阅读inMemory、withTemplate三个重载的源码注释。赞分享后端【免费下载链接】fesodFast. Easy. Done. Processing spreadsheets without worrying about large files causing OOM.项目地址https://gitcode.com/gh_mirrors/fast/fesod点击查看免费下载相关推荐基于 Cell Painting 高内涵图像的细胞嵌入向量生成实战google-research cell_embedder 全解析基于 Cell Painting 高内涵图像的细胞嵌入向量生成实战google research cell_embedder 全解析 导读 本文围绕 goog后端Whisper-Large-V3-Turbo解码层精简策略如何实现8倍语音识别加速Whisper Large V3 Turbo解码层精简策略如何实现8倍语音识别加速 在语音识别技术快速发展的今天OpenAI推出的whisper large语音/音频人工智能Undici 拦截器Interceptors完全指南用 compose() 组合内置拦截器与自定义拦截器Undici 拦截器Interceptors完全指南用 compose 组合内置拦截器与自定义拦截器 Undici 是 Node.js 生态中原生实现的后端网络通信上一篇ayu-vim现代VIM配色主题的终极指南 - 3种配色风格完整解析下一篇Drizzle ORM 0.29.5 新特性实战指南CTE 写操作、自定义迁移表与 SQLite Proxy 批量查询创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考