云计算百科
云计算领域专业知识百科平台

JQuick-Excel toUpper 转换实战:在 TRANSFORM 中统一编码大小写

JQuick-Excel toUpper 转换实战:在 TRANSFORM 中统一编码大小写

tags: #JQuickExcel #Java #Excel导出 #DSL

简介

客户编码、地区代码、物料编号和渠道标识经常要求统一以大写形式出现在交付工作簿中。JQuick-Excel 已确认提供内置 toUpper 转换函数,本文只依据 README-CN.md 与测试 XML 中的 DSL,说明如何用 TRANSFORM={"customerCode":toUpper(${customerCode})} 在写入前转换当前行字段。文章同时解释字段表达式、映射、显示格式和业务校验各自的边界,避免把一个简单的展示规则写成不可维护的调用方循环。

前言

Excel 模板中的文本规范很容易被低估。一个导出入口只有一列编码时,开发者往往会在 Java 中先遍历集合,把每条记录转成大写;第二个、第三个入口出现后,处理逻辑便散落到多个服务中,无法从模板本身判断是否统一。更稳妥的方式是把逐行的转换声明在 XML,让业务代码只准备数据和输出流。

明确说明,TRANSFORM 为每一行计算表达式,${field} 读取当前行字段。这里的 ${customerCode} 因而不是 Excel 的列字母,不是 Java 的局部变量,也不是表头文字“客户编码”;它是当前 JQuickRow 中名为 customerCode 的值。函数 toUpper 接到该值后生成转换结果,结果被用于本次写入。

还需要区分 JQuick-Excel 的转换函数和 Excel 公式。toUpper(${customerCode}) 是导出过程中的行值转换,写入工作簿后单元格中保存的是转换结果;它不是 FORMULAS 中的 Excel UPPER 公式。前者适合稳定交付文本,后者适合希望用户继续在 Excel 中修改并重新计算的场景。两者服务的生命周期不同,不能仅因名字相似而互换。

环境与依赖

本文使用 JDK 8 或更高版本、Maven,以及可写的 xls 或 xlsx 输出位置。依赖坐标固定为以下版本:

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

将 XML 放到类路径可读取的位置,例如 src/main/resources/jquick-excel.xml。<excels> 的 namespace 必须对应 Java 服务接口的全限定名,<excel name> 必须对应代理方法名。导出时,README 所示调用链是先将业务数据转换为 JQuickRow,再用 JQuickExcelExportXmlParseFactory 持有行数据和输出流,最后由 JQuickXmlFactory 创建服务代理。

本文不引入 README 中提到的扩展函数,也不假设其他转换函数可用。大小写处理仅使用已确认的 toUpper,因此读者可以直接在当前 Maven 坐标和基础 DSL 下理解示例。若项目另行加入扩展依赖,应把扩展函数的可用性与本文的内置函数区分开来。

代码示例

导出映射的方向是“字段到表头”。customerCode 是当前行字段,“客户编码”是用户在工作簿中看到的标题。转换键与表达式字段名均使用 customerCode。

<?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.CustomerExportService">
<excel name="exportCustomers" returnClass="void"><![CDATA[
EXPORT WITH
SHEET="客户",
HEADER=true,
MAPPING={"customerCode":"客户编码","name":"客户名称"},
TRANSFORM={"customerCode":toUpper(${customerCode})}
]]>
</excel>
</excels>

Java 侧继续只负责准备原始行和输出流。输入值可以是小写或混合大小写,规则在写入阶段统一处理。

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 com.github.paohaijiao.xml.param.Param;

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

public interface CustomerExportService {
void exportCustomers(@Param("field") String field, @Param("value") String value);
}

Map<String, Object> customer = new LinkedHashMap<>();
customer.put("customerCode", "cn-hz-001");
customer.put("name", "Alice");
List<JQuickRow> rows = JQuickRow.toRows(
JObjectConverter.convert(Collections.singletonList(customer)));
try (OutputStream output = new FileOutputStream("customers.xlsx")) {
JQuickParseHandler parser = new JQuickExcelExportXmlParseFactory(rows, output);
JQuickFactory factory = new JQuickXmlFactory(parser, "jquick-excel.xml");
factory.createApi(CustomerExportService.class).exportCustomers("field", "value");
}

这个样例的预期结果是,“客户编码”列显示 CN-HZ-001,“客户名称”列仍显示 Alice。字段没有因为写入转换而变成另一个映射字段,未参与 TRANSFORM 的字段也不应被修改。建议至少准备 lower-01、Mixed-01、UPPER-01 三行,逐行检查结果,而不是只验证第一条数据。

原理说明

规则执行时,MAPPING 先定义字段与表头的关系,TRANSFORM 再对指定字段的当前行值计算表达式。对于每条行数据,${customerCode} 从当前行取出值,toUpper 对该值执行大写转换,最终结果写入该字段所在的目标列。这里的“当前行”是非常重要的限定:表达式不会跨行搜索,也不会按标题名称推断字段。

这种分工使模板职责可见。XML 中的 MAPPING 回答“写到哪一列、列标题叫什么”,TRANSFORM 回答“写入前的值如何变化”。业务对象如何从数据库读取、是否按权限过滤、客户编码是否唯一,则仍由 Java 应用层决定。不要试图用大小写函数替代数据清洗、权限控制或跨记录校验。

README 还明确指出 FORMAT 独立负责 Excel 单元格显示格式。这意味着 TRANSFORM 与 FORMAT 不可互相代替。对于客户编码,统一字母大小写属于值转换;对日期和金额,指定日期样式、货币样式属于显示格式。把编码大写规则写进 FORMAT 不会得到正确的语义,把日期显示规则伪装成文本转换也会让后续排序和计算的预期变得不清楚。

实际维护时,应把 Java Map 的键、MAPPING 左侧键、TRANSFORM 的键和 ${…} 内的字段名一起检查。它们在这个例子中都指向 customerCode。只改其中一处,常见结果是生成空列、未发生转换或看起来成功但作用在错误字段。表头“客户编码”则属于映射右侧,不能放进表达式读取。

注意事项

第一,确认业务是否真的允许大小写归一。大多数技术编码将大小写仅视为展示差异,但部分外部系统、签名串或区分大小写的标识不能被导出层擅自改变。导出模板可统一展示,不代表应用中的原始数据必须被原地修改。本文示例只说明写入前的转换,不主张回写原数据。

第二,toUpper 不是完整的数据质量规则。空值、前后空白、非法前缀、长度限制、跨行重复分别属于不同问题。若是导入场景,基础单元格校验应使用 README 已确认的 VALIDATION 规则和范围;唯一性、权限、数据库存在性则由应用层处理。不要假定大小写转换会自动填补空值或报告业务错误。

第三,验收应包含正常样本和边界样本。正常样本检查小写、混合大小写和大写输入是否都得到统一结果;边界样本检查数字、连字符、下划线等非字母字符是否保持不变。还应检查未转换的姓名列是否保持原样,以证明规则只命中指定字段。若结果没有变化,依次检查 XML 是否被加载、方法名与节点名是否一致、输入 Map 是否包含字段、表达式字段名是否拼写正确。

第四,模板演进时不要根据列号猜测。即使列顺序变化,字段映射仍由 MAPPING 表达;如果同时使用样式、公式或范围规则,则需要重新核对这些规则依赖的坐标。转换表达式本身读取字段而不依赖列字母,但最终工作簿的其他配置可能依赖位置。用一份最小回归模板检查标题、字段和值,比只看日志更可靠。

第五,输出流必须在代理调用完成前保持打开。try-with-resources 能清楚表达流的所有权:创建解析器、创建代理、执行导出都在同一资源块内完成。大数据配置、样式缓存和流式导出解决的是资源管理问题,不会修复字段名或表达式错误,因此应先用小样本验证语义,再讨论性能参数。

补充实践

在多个导出规则共享编码规范时,应在每个需要统一展示的规则中明确列出对应字段,而不是依赖调用方已经预处理数据。这样阅读某个 XML 节点就能看出输出是否会大写,也能避免同一业务字段在不同报表中出现不一致的写法。若一个报表只需要规范客户编码,另一个报表还需要规范地区代码,应分别写出 customerCode 与 regionCode 的转换键,避免把无关的名称字段也纳入处理。

字段名是这类规则最容易出错的部分。以导出为例,Java 数据中的键、MAPPING 左侧键、TRANSFORM 的目标键以及 ${…} 里的字段引用应在同一概念上保持一致。表头是给工作簿读者看的名称,属于 MAPPING 右侧;它不参与当前行表达式读取。将“客户编码”写进 ${…},并不是读取表头所在列,而是尝试读取一个名为“客户编码”的当前行字段。这种错误在配置审查中很难由肉眼发现,因此应将字段清单与模板标题清单分开维护。

导入时同样可以使用 TRANSFORM={"name":toUpper(${name})} 这类写法,区别仅在于字段先由导入映射产生。测试资源表明 TRANSFORM 可出现在导入与导出规则中;toUpper、dateFormat、trans 均是已确认的内置转换。无论方向如何,${field} 都读取当前处理行的字段,不读取前一行、后一行,也不读取 Excel 公式结果。需要进行跨记录比较或查找外部数据时,应在取得导入结果后由应用层处理。

回归检查不必依赖大量样本。可以准备小写、混合大小写、纯数字和含连接符的编码,确认字母转换符合预期,而非字母部分保持原样;同时准备未配置 TRANSFORM 的列,确认规则没有扩散到其他字段。再将表头顺序调整一次,确认字段映射仍正确。这样分别覆盖了字段读取、值转换和映射关系三个边界。若模板还有格式、公式或样式规则,应额外检查它们的坐标是否仍匹配新列位置,因为 TRANSFORM 本身按字段读取,但其他 DSL 功能可能按坐标定位。

延伸检查

编码规范经常会随着模板版本扩展到更多字段,但扩展前应先判断字段是否确实属于同一种标识。订单号、地区编码、产品代码通常可以有明确的大写展示要求;姓名、地址、自由备注却不应因为同处一行数据而被一并转换。XML 中每增加一条 TRANSFORM 项,都是对输出数据的一个可见承诺。配置应只包含确定需要的字段,避免把“统一格式”演变成不可逆的广泛文本处理。

还应把导出后的工作簿和内存中的原始业务数据分开理解。本文说明的是写入前对当前行值的表达式转换,并没有说明或要求修改数据源。应用层若还需要用原始编码与外部系统交互,应保留原始字段语义;导出规则仅决定该份工作簿如何呈现。这样既能满足交付格式,也不会让展示层规则影响后续业务调用。对于是否应在领域模型中统一编码,则应由业务契约决定,不能从 toUpper 的存在反推。

配置变更也应有可复现的验收记录。至少应记录使用的工作表名、表头、输入字段键和预期输出文本,并将小样本作为模板回归的一部分。出现差异时,先对比字段名与 XML,再对比实际输出单元格,不要只以 Java 调用未抛出异常作为成功标准。转换规则的正确性最终体现在目标列中是否得到预期值,以及其他未命中列是否保持原有值。

配置审查要点

审查这类模板时,可以从一个字段的完整链路开始核对:行数据是否提供 customerCode,MAPPING 是否将该字段放到预期表头,TRANSFORM 是否以同一字段为目标,并且表达式是否引用 ${customerCode}。这四处语义一致时,转换的输入、输出位置和展示标题才是可追踪的。仅看到 toUpper 函数存在,不能证明它已经命中正确列。

同一份模板中若出现多个编码字段,应按字段逐项声明和验收。例如客户编码与地区代码的大小写规则可以同时存在,但每一项都应有自己的当前行引用和目标列。不要把某一列的验证结果外推为所有列都已经规范化;TRANSFORM 的配置项只描述被明确列出的字段。该限制使规则范围清楚,也便于在报表需求变化时定位影响。

还应把大小写规范与字符内容的其他约束分开记录。toUpper 的可验证结果是字母转换为大写;它不负责决定编码是否属于允许集合,也不负责将不同业务前缀归并为同一值。导出验收中可以同时观察原始输入和工作簿目标单元格,从而确认规则只改变预期的字符表现,没有把展示转换误当作数据治理。

总结

toUpper 可在 TRANSFORM 中针对当前行的指定字段生成大写结果,适用于已有明确规范的编码展示。表达式字段、转换键和 MAPPING 左侧应指向同一业务名称,表头只承担展示职责;未列入规则的字段不应因同处一行而被改变。

大小写转换不等于数据清洗或业务校验。验收应覆盖小写、混合大小写和含非字母字符的编码,并确认其他列保持原值。编码是否允许归一、是否需要保留原始值以及跨记录约束,仍应由调用方和应用层的业务契约决定。

赞(0)
未经允许不得转载:网硕互联帮助中心 » JQuick-Excel toUpper 转换实战:在 TRANSFORM 中统一编码大小写
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!