JQuick-Excel 导入反向映射实战:让中文表头稳定落到业务字段

JQuick-Excel 导入反向映射实战:让中文表头稳定落到业务字段

tags: #JQuickExcel #JavaExcel #Excel导入 #DSL #字段映射

简介

导入 Excel 时,用户看到的是"学号""姓名""性别"这样的表头,业务代码需要的却是 no、name、sex 等字段。本文说明 IMPORT WITH 中 MAPPING 的反向映射规则,并给出可独立验证的 XML 与 Java 调用示例。

前言

很多导入实现从列号开始:第一列放学号,第二列放姓名。模板一旦调整列顺序,隐藏在循环里的下标关系就很难核对。JQuick-Excel 的导入规则以表头文本为入口,把模板契约直接写在 XML 中。

导出时,MAPPING 表示"字段到表头";导入时,含义正好相反,表示"表头到字段"。这不是书写习惯差异,而是由数据流方向决定的。先弄清这一点,字段为空、列取错值等问题会少很多。

环境与依赖

项目运行于 Java 8 或更高版本,使用 jquick-excel:3.6.0。将 XML 服务定义放在 src/main/resources/jquick-excel.xml,由 JQuickXmlFactory 按资源名加载。

xml 复制代码
<dependency>
  <groupId>io.github.paohaijiao</groupId>
  <artifactId>jquick-excel</artifactId>
  <version>3.6.0</version>
</dependency>

代码示例

下面的模板要求工作表为 Sheet1,第一行依次包含"学号、姓名、性别、年龄、出生日期"。MAPPING 左侧是工作簿里真实出现的标题,右侧是返回 JQuickRow 使用的字段键。

xml 复制代码
<?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.github.paohaijiao.xml.service.JQuickExcelExportService">
    <excel name="importExcel" returnClass="java.util.List"><![CDATA[
        IMPORT WITH
            HEADER=true,
            SHEET='Sheet1',
            MAPPING={
                "学号":"no",
                "姓名":"name",
                "性别":"sex",
                "年龄":"age",
                "出生日期":"birthday"
            },
            TRANSFORM={
                "sex":trans(${dict},${sex}),
                "birthday":dateFormat(${birthday},'yyyy-MM-dd')
            }
    ]]></excel>
</excels>

Java 侧只负责准备输入流、上下文和代理。示例中的字典方向是显示文本到内部编码,不能直接复用导出时的编码到显示文本字典。

java 复制代码
import com.github.paohaijiao.statement.JQuickRow;
import com.github.paohaijiao.xml.param.Param;

import java.util.List;

public interface JQuickExcelExportService {
    void exportExcel(@Param("field") String field, @Param("value") String value);

    List<JQuickRow> importExcel(@Param("field") String field, @Param("value") String value);
}
java 复制代码
Map<String, Object> gender = new HashMap<>();
gender.put("男", "1");
gender.put("女", "2");

JContext context = new JContext();
context.put("dict", gender);

try (InputStream input = ReverseMappingExample.class.getClassLoader()
        .getResourceAsStream("templates/students.xlsx")) {
    JQuickParseHandler parser =
            new JQuickExcelImportXmlParseFactory(context, input);
    JQuickFactory factory = new JQuickXmlFactory(parser, "jquick-excel.xml");
    JQuickExcelExportService service =
            factory.createApi(JQuickExcelExportService.class);
    List<JQuickRow> rows = service.importExcel("field", "value");
}

原理说明

导入解析器先按 SHEET 选择工作表。HEADER=true 表示第一行承担表头语义,随后 MAPPING 根据左侧文本寻找对应列,并把每一行的值写到右侧字段名中。以上例为例,标题"学号"对应的单元格值会进入 no,而不是进入"学号"这个键。

这种写法不依赖列的物理位置。只要"学号"标题仍然存在,用户把它从 A 列移动到 C 列,映射的语义仍然明确。反过来,表头从"出生日期"改为"出生年月"时,应把它视为模板契约变更,更新 XML 并重新验证,而不是期待框架按近义词猜测。

TRANSFORM 在映射后处理当前行字段。trans(${dict},${sex}) 中的 ${sex} 是右侧字段键,${dict} 来自 JContext。表头"性别"只属于 MAPPING 的左侧,不能把表头文本当作转换表达式的字段名。

注意事项

  • IMPORT WITH 的 MAPPING 左侧是 Excel 表头,右侧是目标字段;不要把导出的 {"no":"学号"} 原样复制到导入规则。
  • SHEET 是工作表名称,不是上传文件名。空格、大小写和全半角差异都应按真实模板核对。
  • HEADER=true 时,第一行必须是与映射左侧一致的标题行;封面、说明行或空行会改变这个前提。
  • 映射负责列归属,不负责业务唯一性、权限、跨行校验或持久化。此类规则应放在应用层。
  • 用一行可辨识数据构造最小模板,分别验证"学号进入 no""姓名进入 name",再增加字典和日期转换。

总结

反向映射的核心只有一件事:用户提交的表头是输入边界,业务字段是系统内部边界。把这层关系显式写成 "学号":"no",模板的变化就会成为可以评审和测试的配置改动。

实际维护中,我会把导出 "no":"学号" 与导入 "学号":"no" 成对检查。两份规则方向相反,但共同约束同一份模板,才能让导出的样表和导入入口保持一致。

相关推荐
程序 代码狂人38 分钟前
切片表与分区表的区别(数据开发面试版)
java·大数据·开发语言·数据仓库·算法
2501_944521591 小时前
Immer 跨端三方库仓颉适配全流程
python·eclipse·django
信誓旦旦的程序猿1 小时前
【Python量化实战宝典 #26】止损与回撤控制手册:移动止损、最大回撤(Python 可跑)
python·1024程序员节·股票数据api·股票数据api接口·股票api数据接口·股票量化数据api·股票量化数据接口
2501_944521591 小时前
Deepmerge 跨端三方库仓颉适配全流程
java·python·eclipse·github
Patrick在香港2 小时前
同一行 strftime,两台机器跑出两种日期
python·datetime·时区·locale·日期处理
2601_967987372 小时前
用Python+OpenCV+YOLO写个游戏脚本:从自动瞄准到自动采集的保姆级教程
python·opencv·yolo·目标检测·游戏自动化
meiying88382 小时前
快递单号批量查询Python脚本:从手动到自动化的完整实现
开发语言·python·自动化
人工智能导论实践课2 小时前
【GUI桌面开发3】PyCharm配置外部工具
ide·python·pycharm
一千柯橘2 小时前
LangChain 的实时输出处理: stream_events 和 Streaming
python·langchain·agent
贾公子2 小时前
图片 AIGC 检测接入实战——URL 与 Base64 的取舍、体积校验与「你送过去的可能不是那张图」
python·aigc