欢迎光临
我们一直在努力

JQuick-Excel 工作表选择实战:SHEET 配置、名称契约与导入导出定位

JQuick-Excel 工作表选择实战:SHEET 配置、名称契约与导入导出定位

tags: #JQuickExcel #Java #Excel导入导出 #SHEET #XMLDSL

简介

本文依据 README-CN.md 和测试资源 jquick-excel.xml,说明如何在 IMPORT WITH 与 EXPORT WITH 中使用 SHEET 选择工作表,并把工作表名称、表头、映射和 XML 服务代理组织为可验证的导入导出流程。

前言

一个 Excel 工作簿经常不止一个页签。封面、说明、学生名单、汇总表可能共存于同一个 xlsx 文件。业务人员看到的是页签名称,程序处理时却必须精确指定哪一页是本次操作的目标。若没有先解决工作表定位,后续的 HEADER、MAPPING、FORMAT 即使写得正确,也可能作用在错误页上,最终得到“文件生成了但内容不对”的结果。

JQuick-Excel 在导入和导出 DSL 中提供 SHEET。README-CN.md 明确说明它可以按名称或索引选择工作表,测试 XML 已实际使用 SHEET="学生表" 和 SHEET='Sheet1'。本文以名称方式作为主线,因为它直接表达业务目标,也只在文字中说明 README 已列出的索引能力;不扩展为自动搜索、模糊匹配、多页循环、根据不存在页签自动创建等未被给定资料验证的行为。

应当把 SHEET 看作工作簿级契约,而不是普通标签。导入时,它选择输入流中读取的源页;导出时,它声明写入规则对应的目标页。页签名称要与实际模板保持一致。比如 XML 写 SHEET="学生表",验收文件中就应存在名为“学生表”的页签,不应把“students.xlsx”文件名、首行“学号”或窗口标题替代为 SHEET 值。

本文继续使用学生数据。导出规则在“学生表”页生成“学号、姓名、年龄”三列;导入规则从同名页读取这些标题。这样可以清晰观察选择页签、识别首行、映射字段这三个步骤各自的职责。

环境与依赖

README-CN.md 给出的环境前提是 Java 8+,并支持 xls、xlsx 工作簿。示例采用 Maven 依赖 3.6.0。XML 文件放置在 src/main/resources 下,运行时通过 JQuickXmlFactory 的资源名 jquick-excel.xml 读取。

<dependency>
<groupId>io.github.paohaijiao</groupId>
<artifactId>jquick-excel</artifactId>
<version>3.6.0</version>
</dependency>

使用 XML 服务代理前,需要建立几个可检查的前提。<excels namespace> 与 Java 服务接口的全限定名一致;<excel name> 与接口方法名一致;导出用的数据键与导出 MAPPING 左侧一致;导入文件的目标页存在,并且在 HEADER=true 时首行标题与导入 MAPPING 左侧一致。

本篇不会把索引形式写成未经测试资源验证的具体数字语法。README 只确认 SHEET 可按名称或索引选择,实际项目应根据所用版本、受控模板和已有测试决定规则写法。对于当前测试资源已经出现的场景,优先使用 SHEET="学生表" 或 SHEET='Sheet1' 这样的明确名称。

代码示例

XML 中的两个规则均选择“学生表”。导出声明目标页,导入声明源页。表头和字段映射紧随其后:SHEET 负责先进入正确页,HEADER 定义首行语义,MAPPING 再处理列标题和业务字段的对应。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE excels PUBLIC "-//PAOHAIJIAO//DTD API EXCEL 1.0//EN"
"classpath:paohaijiao/dtd/Jquick-excel.dtd">

<excels namespace="com.example.SheetExcelService">
<excel name="exportStudents" returnClass="void">
<![CDATA[
EXPORT WITH
SHEET="学生表",
HEADER=true,
MAPPING={
"id":"主键",
"name":"姓名",
"age":"年龄"
}
]]>

</excel>
<excel name="importStudents" returnClass="java.util.List">
<![CDATA[
IMPORT WITH
SHEET="学生表",
HEADER=true,
MAPPING={
"主键":"id",
"姓名":"name",
"年龄":"age"
}
]]>

</excel>
</excels>

接口与 XML 节点的关系应保持一对一。公开 README 的服务接口示例使用 @Param("field")、@Param("value"),导入返回 List<JQuickRow>。SHEET 本身写在 XML 中,不由业务调用处临时传入,因此一个接口可以按不同 XML 方法承载不同模板规则。

import com.github.paohaijiao.statement.JQuickRow;
import com.github.paohaijiao.xml.param.Param;

import java.util.List;

public interface SheetExcelService {
void exportStudents(@Param("field") String field, @Param("value") String value);

List<JQuickRow> importStudents(@Param("field") String field, @Param("value") String value);
}

下面是导出调用。JObjectConverter.convert 和 JQuickRow.toRows 是 README 明确展示的数据准备路径;JQuickExcelExportXmlParseFactory 接收行列表与输出流;JQuickXmlFactory 再根据 XML 生成接口代理。此处没有直接操作页签对象,工作表选择完全由 XML 中的 SHEET="学生表" 决定。

import com.github.paohaijiao.convert.JObjectConverter;
import com.github.paohaijiao.statement.JQuickRow;
import com.github.paohaijiao.xml.JQuickFactory;
import com.github.paohaijiao.xml.JQuickXmlFactory;
import com.github.paohaijiao.xml.parse.JQuickParseHandler;
import com.github.paohaijiao.xml.parse.excel.JQuickExcelExportXmlParseFactory;

import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

List<Map<String, Object>> data = new ArrayList<>();
Map<String, Object> student = new LinkedHashMap<>();
student.put("id", "1001");
student.put("name", "Alice");
student.put("age", 20);
data.add(student);

List<JQuickRow> rows = JQuickRow.toRows(JObjectConverter.convert(data));
try (OutputStream output = new FileOutputStream("students.xlsx")) {
JQuickParseHandler parser = new JQuickExcelExportXmlParseFactory(rows, output);
JQuickFactory factory = new JQuickXmlFactory(parser, "jquick-excel.xml");
SheetExcelService service = factory.createApi(SheetExcelService.class);
service.exportStudents("field", "value");
}

导入调用使用 JQuickExcelImportXmlParseFactory、JContext 与输入流。读取前应先人工或自动检查工作簿中存在“学生表”页,且首行是“主键、姓名、年龄”。如果输入实际来自测试资源里的 SHEET='Sheet1' 规则,则 XML 应相应保持 Sheet1,不要仅修改 Java 文件名。

import com.github.paohaijiao.context.JContext;
import com.github.paohaijiao.statement.JQuickRow;
import com.github.paohaijiao.xml.JQuickFactory;
import com.github.paohaijiao.xml.JQuickXmlFactory;
import com.github.paohaijiao.xml.parse.JQuickParseHandler;
import com.github.paohaijiao.xml.parse.excel.JQuickExcelImportXmlParseFactory;

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.List;

try (InputStream input = new FileInputStream("students.xlsx")) {
JContext context = new JContext();
JQuickParseHandler parser = new JQuickExcelImportXmlParseFactory(context, input);
JQuickFactory factory = new JQuickXmlFactory(parser, "jquick-excel.xml");
SheetExcelService service = factory.createApi(SheetExcelService.class);
List<JQuickRow> rows = service.importStudents("field", "value");
System.out.println(rows.size());
}

若项目需要使用 README 说明的按索引选择能力,应把“顺序稳定”作为模板交付条件。索引表达的是位置而非业务名称,插入封面页、调整页签顺序都可能改变它指向的页。本文不为这个能力虚构其它示例,而是建议为实际写法补充针对目标版本的集成测试。

原理说明

调用 factory.createApi(SheetExcelService.class) 后,JQuickXmlFactory 按 XML 的 namespace 和接口生成代理。调用 exportStudents 时,代理定位 <excel name="exportStudents">,执行其中的 EXPORT WITH;调用 importStudents 时,代理定位 IMPORT WITH。因此 SHEET 不是 Java 临时变量,而是该方法绑定的配置规则。

导出链路中,JQuickExcelExportXmlParseFactory 已持有 List<JQuickRow> 和输出流。规则中的 SHEET="学生表" 用于确定本次输出面向的工作表,HEADER=true 使映射右侧的“主键、姓名、年龄”作为首行标题,MAPPING 再按字段名从每条 JQuickRow 取值。选择页签是后续列处理的前置条件。

导入链路中,JQuickExcelImportXmlParseFactory 持有 JContext 和输入流。SHEET="学生表" 指向源工作簿中的业务页;HEADER=true 表示第一行需要按标题处理;MAPPING 用“主键、姓名、年龄”找到对应列,并把后续单元格值写入 id、name、age。选中错误页时,导入有可能读到封面或说明行,表头映射也无法代表业务数据。

名称选择的价值在于可读性。审查 XML 时,业务人员可直接识别“学生表”是否是当前模板页签;模板改名时,变更也会落到可审查的配置中。索引选择的价值是对顺序明确、名称不稳定的模板建立位置契约,但它需要更严格地维护工作簿顺序。README 认可两种选择方式,并没有说明自动适应页签改名或顺序变化。

SHEET 不取代表头配置。页签名称与第一行标题属于不同层次:学生表 是工作表标识,“姓名”是单元格内容。一个规则中通常要同时审查 SHEET、HEADER、MAPPING。同理,SHEET 也不取代字段准备。导出数据键是否为 id、name、age,由 Java 数据与映射左侧共同决定。

在多模板项目中,推荐为每种模板建立清晰的 <excel name>,让每个方法的 SHEET 固定。这样调用方按业务意图选择服务方法,XML 负责页签和列规则。本文不据此推导单次调用处理多工作表或自动合并工作表的能力,因为给定 README 与测试 XML 未展示这些行为。

注意事项

第一,SHEET 值必须是实际工作簿页签名,不是文件名,也不是表头标题。students.xlsx、姓名 和“学生表”分别处在文件、单元格、工作表三个层次,不能互相替换。

第二,优先检查输入模板。导入前打开或自动校验目标工作簿,确认存在 XML 声明的页签。用户上传文件常含封面或说明页,若业务数据不在第一张页,不要因为文件能打开就假设应读取默认页。

第三,名称变更需要同步 XML。页签由“学生表”改为“学生名单”后,导出和导入规则都应评审并更新。README 和测试资源没有声明名称的模糊匹配或自动别名,因此不要期待它会自行修正。

第四,若使用按索引选择,必须把工作簿顺序作为受控条件。增加、删除或移动工作表都可能改变索引含义。为避免索引漂移,应对真实模板执行集成测试,并保持 DSL 写法与当前项目版本已验证语法一致。

第五,选对页签仍不足以保证导入正确。使用 HEADER=true 时,还要确认该页第一行与 MAPPING 左侧标题完全匹配。选错页时尤其容易出现说明文字被当作表头的情况。

第六,XML 加载链路同样重要。jquick-excel.xml 要进入类路径,namespace 对应接口全限定名,excel name 对应接口方法名。否则即使 SHEET 文本正确,代理也无法路由到预期规则。

第七,验收要检查页签而不仅是数据行。导出后打开文件并确认是否存在“学生表”、首行是否正确、数据是否位于该页。导入后确认返回行来自目标页,并以 id、name、age 验证字段。对于有封面页的样例,专门准备一份文件可以更有效地检验页签选择。

总结

SHEET 决定规则作用于工作簿中的哪一个页签,是导入读取与导出写入的起点。名称方式直接表达模板中的业务页,索引方式则依赖稳定的工作表顺序;无论采用哪种形式,页签名或位置都应作为模板契约被明确维护。

页签定位不能替代表头和字段映射。实际验收应确认数据确实落在目标页,再核对首行标题与返回字段,尤其要覆盖带封面或说明页的工作簿。页签调整、改名或重排后,应同步更新相关 XML 规则并复测导入导出结果。

赞(0)
未经允许不得转载:171主机测评 » JQuick-Excel 工作表选择实战:SHEET 配置、名称契约与导入导出定位
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址