资讯动态

从 XML 到 Excel:JQuick-Excel 代理与解析器如何协作

发布时间:2026/10/18 14:37:52 来源:尧图企业网站定制
从 XML 到 ExcelJQuick-Excel 代理与解析器如何协作tags: #JQuickExcel #JavaExcel #开源 #POI #Excel工具更多示例: JQuick-Excel 官网示例 https://www.jquick.org/jquick-excel/#demo-formulas0005简介很多 Excel 导出代码最终会演化成一段很长的 Java 配置字段映射、表头、公式、样式和转换逻辑混在同一个方法里规则一改就要重新发版。JQuick-Excel 提供的 XML 入口适合把这部分“报表声明”抽离出来Java 仍负责准备数据、上下文和文件流XML 描述某个接口方法应执行的导入或导出规则。本文以仓库现有的JQuickXmlFactory、JQuickExcelExportXmlParseFactory和JQuickExcelImportXmlParseFactory为依据梳理 XML 代理与解析器的职责边界并给出可以直接改造成项目测试的导入、导出示例。前言我接手报表需求时通常先分清两件事规则是不是业务配置数据和资源是不是运行期输入。前者适合 XML后者应由 Java 明确传入。这样做并不是为了“所有内容 XML 化”而是让接口方法成为稳定调用点避免调用方知道 DSL、工作簿名或解析细节。从当前源码能够确认JQuickExcelExportXmlParseFactory接收ListJQuickRow、OutputStream也可额外接收主题编码和JContextJQuickExcelImportXmlParseFactory接收InputStream也可接收JContext。两者都实现JQuickParseHandler并创建JQuickJavaExcelElement与对应的调用处理器。JQuickXmlFactory再根据 XML 生成服务接口代理。至于代理框架内部如何解析每一个 XML 节点不宜脱离依赖源码臆测本文只讨论项目可验证的协作契约。环境与依赖项目的pom.xml已声明jquick-excel自身依赖jquick-xmlProxy、Apache POI、ANTLR 运行时和jquick-transform-function。因此实际工程中应首先引入本库对应版本而不是只复制下面的类名。示例还使用下列仓库已有类型com.github.paohaijiao.xml.factory.JQuickFactorycom.github.paohaijiao.xml.factory.JQuickXmlFactorycom.github.paohaijiao.xml.handler.JQuickParseHandlercom.github.paohaijiao.xml.ex.JQuickExcelExportXmlParseFactorycom.github.paohaijiao.xml.im.JQuickExcelImportXmlParseFactorycom.github.paohaijiao.statement.JQuickRowcom.github.paohaijiao.param.JContext把 XML 放入src/main/resources或src/test/resources并确保namespace指向接口的全限定名。当前测试资源中的根节点是excels namespace...每个excel name...对应接口的一个方法名。代码示例先定义服务接口。它不承载业务实现只定义代理需要暴露的方法参数上使用已有的Param使 XML 调用可按名称接收参数。packagedemo;importcom.github.paohaijiao.statement.JQuickRow;importcom.github.paohaijiao.xml.param.Param;importjava.util.List;publicinterfaceStudentExcelService{voidexportExcel(Param(field)Stringfield,Param(value)Stringvalue);ListJQuickRowimportExcel(Param(field)Stringfield,Param(value)Stringvalue);}创建student-excel.xml。导出和导入规则均放在 CDATA 中避免 DSL 与 XML 转义互相干扰。此处的TRANSFORM使用 README 已列出的内置函数trans和dateFormat。?xml version1.0 encodingUTF-8?!DOCTYPEexcelsPUBLIC-//PAOHAIJIAO//DTD API EXCEL 1.0//ENclasspath:paohaijiao/dtd/Jquick-excel.dtdexcelsnamespacedemo.StudentExcelServiceexcelnameexportExcelreturnClassvoid![CDATA[ EXPORT WITH SHEET学生表, HEADERtrue, MAPPING{id:学号,name:姓名,gender:性别,enrollmentDate:入学日期}, TRANSFORM{ gender:trans(${dict},${gender}), enrollmentDate:dateFormat(${enrollmentDate},yyyy-MM-dd) } ]]/excelexcelnameimportExcelreturnClassjava.util.List![CDATA[ IMPORT WITH SHEET学生表, HEADERtrue, MAPPING{学号:id,姓名:name,性别:gender,入学日期:enrollmentDate}, TRANSFORM{gender:trans(${dict},${gender})} ]]/excel/excels下面的 Java 演示以Map构造两行数据再通过JQuickRow.toRows(JObjectConverter.convert(data))转为导出解析器所需格式。这个用法来自仓库测试JQuickExcelDemo。packagedemo;importcom.github.paohaijiao.param.JContext;importcom.github.paohaijiao.statement.JQuickRow;importcom.github.paohaijiao.util.JObjectConverter;importcom.github.paohaijiao.xml.ex.JQuickExcelExportXmlParseFactory;importcom.github.paohaijiao.xml.factory.JQuickFactory;importcom.github.paohaijiao.xml.factory.JQuickXmlFactory;importcom.github.paohaijiao.xml.handler.JQuickParseHandler;importjava.io.FileOutputStream;importjava.io.OutputStream;importjava.util.*;publicclassXmlExportDemo{publicstaticvoidmain(String[]args)throwsException{MapString,ObjectrownewLinkedHashMap();row.put(id,1001);row.put(name,张三);row.put(gender,1);row.put(enrollmentDate,newDate());ListMapString,ObjectdataCollections.singletonList(row);MapString,ObjectdictnewHashMap();dict.put(1,男);JContextcontextnewJContext();context.put(dict,dict);ListJQuickRowrowsJQuickRow.toRows(JObjectConverter.convert(data));try(OutputStreamoutputnewFileOutputStream(students.xlsx)){JQuickParseHandlerparsernewJQuickExcelExportXmlParseFactory(jade,context,rows,output);JQuickFactoryfactorynewJQuickXmlFactory(parser,student-excel.xml);StudentExcelServiceservicefactory.createApi(StudentExcelService.class);service.exportExcel(field,value);}}}导入只替换解析器和流方向。JContext的字典要按源单元格值到目标值的方向建立例如 Excel 写“男”导入结果要为“1”时使用男 - 1。try(InputStreaminputnewFileInputStream(students.xlsx)){MapString,ObjectdictnewHashMap();dict.put(男,1);JContextcontextnewJContext();context.put(dict,dict);JQuickParseHandlerparsernewJQuickExcelImportXmlParseFactory(context,input);JQuickFactoryfactorynewJQuickXmlFactory(parser,student-excel.xml);StudentExcelServiceservicefactory.createApi(StudentExcelService.class);ListJQuickRowrowsservice.importExcel(field,value);System.out.println(rows.size());}原理说明我把这条链路理解为四个稳定层次。第一层是服务接口调用方只依赖StudentExcelService并不直接操作工作簿。第二层是 XMLnamespace锁定接口excel/name锁定方法CDATA 中保存EXPORT WITH或IMPORT WITH规则。第三层是解析器工厂导出解析器持有行数据、输出流、可选主题与上下文导入解析器持有输入流和上下文。第四层是JQuickXmlFactory创建的 API 代理方法调用被交给与 XML 规则对应的处理流程。这意味着 Java 和 XML 的分工很清楚。Java 负责确定文件来自哪里、输出到哪里、当前数据是什么、字典等运行时变量为何值XML 负责决定工作表、表头、映射、转换和样式。JContext是两边的桥梁但它不替代接口参数。对于真正影响调用语义的输入仍应通过接口方法参数表达对于规则求值使用的字典、租户配置或日期格式可放入上下文。从当前解析器类还能看到几个可用构造方式。导出可只传rows与OutputStream也可传主题编码或传JContext或同时传两者。导入可只传InputStream也可加JContext。这些重载足以覆盖简单文件转换和带字典、带主题的场景不必为此自行封装另一套代理入口。注意事项第一XML 的namespace、excel/name与 Java 接口必须一致。接口改名而 XML 未同步时代理无法按预期定位规则。第二资源文件必须位于类路径new JQuickXmlFactory(parser, student-excel.xml)传的是资源名不是任意磁盘绝对路径。第三导出解析器构造时会校验行数据和输出流非空导入解析器会校验输入流非空调用方应使用 try-with-resources 管理文件流。第四JContext中的映射方向取决于导入还是导出不能复用同一份字典就假设结果正确。第五README 的历史代码片段中存在与当前仓库不同的包路径实践中应优先采用当前源码测试已使用的com.github.paohaijiao.xml.factory、xml.ex、xml.im包名。第六接口里的field、value仅是现有测试使用的示例参数不应据此推断所有 XML 规则都会使用它们不用的参数可保留在示例接口之外按自己的 XML 规则设计。运行步骤与工程边界我建议先在src/test/resources放入 XML再用两行LinkedHashMap数据完成一次本地导出。运行前确认 XML 已被构建到 classpathnamespace是接口完整类名excel/name与调用方法同名。导出时使用JQuickRow.toRows(JObjectConverter.convert(data))得到行数据创建JQuickExcelExportXmlParseFactory然后通过JQuickXmlFactory创建 API文件生成后用 Excel 打开检查工作表、表头、映射和转换结果。导入测试则使用同一份已生成文件或受控样例反转字典方向创建JQuickExcelImportXmlParseFactory后断言返回行数和字段值。这个最小闭环比直接把复杂模板接入生产更容易定位问题。从源码看导出工厂的四参构造器会拒绝空rows和空OutputStream并只在传入上下文非空时复制其内容导入的单参构造器要求输入流非空双参构造器还要求上下文非空。我的应用层会在创建工厂前完成这些前置判断而不会把空集合、已关闭流或空上传流交给框架。空数据是否允许生成只有表头的文件是报表接口的业务决策若需要该行为应通过实际版本测试确认而不是从构造器不为空推断输出效果。资源和对象的生命周期也要清楚。XML 是可随应用发布的静态规则接口是编译期契约JContext、ListJQuickRow、输入流和输出流则属于单次操作。Web 场景中不要把解析器、代理或流缓存为单例字段。批任务中也应让每个文件拥有独立的流与上下文处理完成及时关闭流。主题参数只应传入 README 已列出的主题编码并在生成文件中检查局部STYLE与主题效果是否符合预期。当代理调用失败时我会依次排查资源名、XML 的namespace、excel/name、接口返回类型、DSL 语法和运行期上下文。不要把 XML 资源路径写成开发机绝对路径也不要假定接口参数会自动参与任何规则只有 XML 实际引用的参数和上下文值才有意义。字典转换尤其要用双向测试覆盖导出验证编码到显示值导入验证显示值到编码避免用同一张映射表制造看似成功但值方向错误的结果。总结XML 代理的价值不在于隐藏所有 Excel 细节而在于把稳定调用契约与可变报表规则分开。JQuickXmlFactory负责从 XML 创建接口代理导出和导入解析器分别提供数据流、文件流、上下文及可选主题接口方法是应用层唯一需要调用的入口。我建议先用一份小 XML 和一个两行数据的测试打通这条链路再逐步加入TRANSFORM、公式、样式和图表规则。这样出问题时能快速判断是资源定位、接口匹配、上下文数据还是 DSL 规则导致的也能让报表配置的迭代保持可控。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑