
JQuick-Excel JQuickRow 数据准备实战JObjectConverter、JQuickRow.toRows 与 XML 导出链路tags: #JQuickExcel #Java #JQuickRow #JObjectConverter #Excel导出简介本文将说明如何将ListMapString, Object按JObjectConverter.convert(data)和JQuickRow.toRows(...)的公开路径准备为导出行并交给JQuickExcelExportXmlParseFactory与JQuickXmlFactory执行 XML 规则。前言Excel 导出通常从业务查询结果开始而不是从单元格坐标开始。订单服务可能得到订单对象学生服务可能得到学生记录报表服务可能得到 Map 列表。无论数据起点是什么XML 规则最终需要能依据字段名读取每行值。JQuick-Excel 的 README 给出了一条明确的准备方式先组织ListMapString, Object然后执行JObjectConverter.convert(data)最后调用JQuickRow.toRows(...)获得ListJQuickRow。这条链路值得单独说明因为它划分了职责。Java 负责从业务层取得数据、确定字段和值XML 负责SHEET、HEADER、MAPPING、FORMAT、TRANSFORM等工作簿规则JQuickExcelExportXmlParseFactory接收行数据和输出流JQuickXmlFactory加载 XML 并创建接口代理。把这些边界分清后字段变更、标题变更、格式变更不会都堆到一个 POI 循环中。本文只使用 README 已出现的 Map 列表、JObjectConverter.convert、JQuickRow.toRows和 XML 导出代理写法。不会声称JQuickRow的私有存储结构不会编造任意对象、嵌套属性、反射字段或空值的自动策略。若业务层使用实体对象应先在项目自己的业务代码中明确整理为文中所用的数据字段再沿公开示例转换。以学生导出为例Java 准备id、name、ageXML 将它们映射成“主键、姓名、年龄”。重点不在 Map 的插入顺序而在数据键与导出 MAPPING 左侧字段一致。列展示顺序由 XML 显式定义因此模板审查不依赖集合迭代的偶然结果。环境与依赖README-CN.md 指出 JQuick-Excel 的运行环境是 Java 8支持xls和xlsx。本文采用 README 中的 Maven 坐标和版本。jquick-excel.xml应位于src/main/resources供JQuickXmlFactory按资源名加载。dependencygroupIdio.github.paohaijiao/groupIdartifactIdjquick-excel/artifactIdversion3.6.0/version/dependency准备数据前应先确认 XML 规则。本文 XML 的导出映射左侧是id、name、age所以 Java Map 必须提供同名键。输出流指向可写文件例如students.xlsx。服务接口的全限定名必须等于 XMLnamespace接口的导出方法名必须等于excel name。这些前提能让排错更直接如果标题不对检查 XML 的 MAPPING 右侧如果某列数据为空检查 Java Map 键和 MAPPING 左侧如果规则完全没有执行检查资源、namespace 和方法名如果输出文件不能写入再检查输出流及其生命周期。代码示例先定义 XML。测试资源使用EXPORT WITH、SHEET学生表、HEADERtrue和MAPPING。本文沿用相同 DSL 结构仅使用三列以突出数据准备。注意 XML 的字段名是id、name、age标题分别是“主键、姓名、年龄”。?xml version1.0 encodingUTF-8?!DOCTYPEexcelsPUBLIC-//PAOHAIJIAO//DTD API EXCEL 1.0//ENclasspath:paohaijiao/dtd/Jquick-excel.dtdexcelsnamespacecom.example.RowExcelServiceexcelnameexportStudentsreturnClassvoid![CDATA[ EXPORT WITH SHEET学生表, HEADERtrue, MAPPING{ id:主键, name:姓名, age:年龄 } ]]/excel/excels接口采用 README 中展示的代理调用形态。它不接收ListJQuickRow作为方法参数因为 README 示例将行数据在创建导出解析器时传入接口参数仍是 XML 示例里的field、value。importcom.github.paohaijiao.xml.param.Param;publicinterfaceRowExcelService{voidexportStudents(Param(field)Stringfield,Param(value)Stringvalue);}下面是完整的数据准备和导出调用。第一段通过ArrayList放入多条记录每一条都使用 Map 表示字段和值。第二段是关键JObjectConverter.convert(students)的结果交给JQuickRow.toRows(...)得到ListJQuickRow。第三段把行列表和输出流传入JQuickExcelExportXmlParseFactory再通过JQuickXmlFactory获取服务代理并调用 XML 方法。importcom.github.paohaijiao.convert.JObjectConverter;importcom.github.paohaijiao.statement.JQuickRow;importcom.github.paohaijiao.xml.JQuickFactory;importcom.github.paohaijiao.xml.JQuickXmlFactory;importcom.github.paohaijiao.xml.parse.JQuickParseHandler;importcom.github.paohaijiao.xml.parse.excel.JQuickExcelExportXmlParseFactory;importjava.io.FileOutputStream;importjava.io.OutputStream;importjava.util.ArrayList;importjava.util.LinkedHashMap;importjava.util.List;importjava.util.Map;ListMapString,ObjectstudentsnewArrayList();MapString,ObjectfirstnewLinkedHashMap();first.put(id,1001);first.put(name,Alice);first.put(age,20);students.add(first);MapString,ObjectsecondnewLinkedHashMap();second.put(id,1002);second.put(name,Bob);second.put(age,21);students.add(second);ListJQuickRowrowsJQuickRow.toRows(JObjectConverter.convert(students));try(OutputStreamoutputnewFileOutputStream(students.xlsx)){JQuickParseHandlerparsernewJQuickExcelExportXmlParseFactory(rows,output);JQuickFactoryfactorynewJQuickXmlFactory(parser,jquick-excel.xml);RowExcelServiceservicefactory.createApi(RowExcelService.class);service.exportStudents(field,value);}当需要导出测试资源中出现的更多字段时仍然遵循同一规则。测试 XML 的 MAPPING 左侧包含id、name、gender、age、enrollmentDate、className、ignoreField则对应的 Java 数据应提供这些同名键。是否使用TRANSFORM转换gender、age或enrollmentDate由 XML 规则决定不能替代基础字段准备。MapString,ObjectstudentnewLinkedHashMap();student.put(id,1001);student.put(name,Alice);student.put(gender,1);student.put(age,20);student.put(enrollmentDate,newjava.util.Date());student.put(className,Class A);student.put(ignoreField,false);上例仅展示与测试 XML 左侧对应的键名不在这里断言每种 Java 值会采用何种内部转换规则。对于日期显示、字典翻译或算术转换应以 XML 中已写明的 FORMAT 或 TRANSFORM 规则和真实集成测试为准。原理说明JObjectConverter.convert(data)与JQuickRow.toRows(...)是 README 导出示例明确给出的两步转换。本文无需猜测转换中间对象的私有实现只需遵循公开调用顺序业务数据先被转换再被包装为导出解析器需要的ListJQuickRow。这使 XML 层可以基于字段名访问当前行。导出执行时JQuickExcelExportXmlParseFactory已经持有rows与output。JQuickXmlFactory读取 XML 后createApi(RowExcelService.class)返回代理调用exportStudents会路由到excel nameexportStudents的EXPORT WITH。规则中的MAPPING从每个 JQuickRow 读取左侧字段例如id并将右侧“主键”作为对应 Excel 列标题。HEADERtrue使这些标题位于首行。因此数据准备的核心是字段契约而非列号。Java 中first.put(name, Alice)与 XML 的name:姓名对应导出后“姓名”列写入 Alice。若 Java 写成first.put(姓名, Alice)而 XML 仍然期待name本文所依据的公开规则没有说明会自动反向识别该键。应先统一数据键或修改 XML 左侧。LinkedHashMap在示例中有助于读者观察构造过程但列顺序不应依赖它。XML 的 MAPPING 顺序才是对外工作簿结构的声明。这样当业务服务的 Map 来源变化、查询字段排序变化时只要字段名不变模板列顺序仍保持由配置控制。数据准备也与显示格式分离。金额、日期、比例等值应尽量保留业务可用的类型README 说明FORMAT负责最终 Excel 显示而TRANSFORM负责在行上下文中计算转换值。本文的转换链路只负责将字段和值送入导出规则不应为了展示而预先把所有数据拼接成字符串。XML 服务代理将业务调用和工作簿规则隔开。调用方不需要直接处理工作表、首行或单元格坐标它只需准备行和输出流并调用定义好的服务方法。反过来XML 改变标题、工作表或格式时应评审这些变更是否仍与 Java 数据字段相符。注意事项第一使用 README 的公开顺序准备数据JObjectConverter.convert(students)后调用JQuickRow.toRows(...)。不要把未经转换的 Map 列表直接传给JQuickExcelExportXmlParseFactory因为本文仅验证了 README 展示的ListJQuickRow构造链路。第二Map 键必须对齐导出 MAPPING 左侧。XML 写id:主键时Java 应提供idXML 写enrollmentDate:入学时间时Java 应提供enrollmentDate。右侧中文标题不应被当作数据键。第三列顺序应由 XML MAPPING 管理。即使示例选择LinkedHashMap也不要将 Java Map 的插入顺序当成工作簿结构契约。新增、调整或删除列时应先修改 XML 并同步确认数据键。第四输出流需在服务方法结束前保持打开。示例的 try-with-resources 范围包含创建解析器、创建代理和调用exportStudents。如果流提前关闭代理没有可用的写入目标。第五XML 资源与接口绑定必须准确。jquick-excel.xml放入类路径namespace 使用com.example.RowExcelServiceexcel name 使用exportStudents接口也应有同名方法。不要把数据准备问题和代理绑定问题混在一起排查。第六字段值转换与字段准备分开。测试 XML 中可见TRANSFORM对性别、年龄、入学时间的表达式README 中也说明 FORMAT 用于显示格式。基础 Map 只需按业务字段提供值具体转换应在已验证的 XML 规则范围内处理。第七验收不仅检查是否产生文件。打开students.xlsx确认“学生表”首行是“主键、姓名、年龄”后续两行分别含 1001/Alice/20 和 1002/Bob/21。若某列标题存在但数据为空优先检查同名 Map 键是否遗漏或拼写不同。总结导出数据可沿公开链路由ListMapString, Object经过JObjectConverter.convert与JQuickRow.toRows准备为解析器需要的行集合。Java 侧负责提供业务字段和值XML 则负责列标题、顺序和工作表规则二者以映射左侧字段名建立稳定连接。定位问题时应分别核对数据键、XML 方法绑定和输出流生命周期。文件生成并不代表每列已正确取值仍需检查标题与实际数据行当字段为空或列错位时优先从 Map 键与MAPPING的一致性开始排查。