JQuick-Excel 实战:用 STYLE 配置单元格与区域样式
tags: Java, Excel, JQuick-Excel, STYLE, 单元格样式, XML DSL
简介
导出 Excel 的数据正确,不代表报表已经具备可读性。表头需要被识别,重点列需要有一致的视觉层次,整张工作表也需要保持统一风格。JQuick-Excel 在 EXPORT WITH 中提供 STYLE,README-CN 明确其可面向行、列、单元格和范围设置样式。项目测试资源则给出了最小且已确认的样式 DSL:ROW 1 配合 fontName、fontHeightInPoints、italic、color、bold。
本文仅使用 README-CN 和 src/test/resources/jquick-excel.xml 已出现的事实。单元格或范围的目标采用 README-CN 已列出的 C1、A1:B5、ROW 1、ROW 1..10、COL A、COL A..D 语法;属性示例以 fontName、fontHeightInPoints、italic、color、bold 为核心。本文不会把未证实的模板占位样式、动态条件或未知 Java API 写成框架能力。
前言
Excel 样式配置的关键不在于堆叠尽可能多的属性,而在于让坐标和报表布局对应。字段经 MAPPING 输出后,Excel 才有实际的列位置;HEADER=true 生成或处理表头后,工作表才有明确的数据起始行。任何 STYLE 规则最终都面对工作表坐标,而不是业务对象里的字段含义。因此在写 A1:D1 前,应先确定表头究竟在哪一行、映射了几列、是否有额外标题或说明行。
README-CN 说明 STYLE 可用于"行、列、单元格和范围样式",并明确给出行、列、单元格和矩形范围语法。它适合把稳定的视觉约定从 Java 数据准备代码中抽离出来。例如第一行整体作为表头时,使用 ROW 1 表达整行公共样式;当某一个固定单元格确有例外时,使用 C1;当一片连续区域需要相同效果时,使用 A1:B5。规则写得越贴近工作表结构,后续调整就越容易审查。
样式与显示格式也必须分开。README-CN 将 FORMAT 单独定义为 Excel 显示格式,示例为 FORMAT={"amount":"currency"} 和 FORMAT={"date":"yyyy-MM-dd"}。日期与数字的字段级显示应优先通过 FORMAT 表达;STYLE 更适合表达字体和坐标相关的视觉规则。这样阅读一份 DSL 时,能明确看到数据映射、显示格式、值转换和样式分别在哪里定义。
环境与依赖
本文使用 Java 8+ 与 JQuick-Excel 3.6.0。README-CN 已确认该依赖支持 xls、xlsx,并提供以下 Maven 坐标。
xml
<dependency>
<groupId>io.github.paohaijiao</groupId>
<artifactId>jquick-excel</artifactId>
<version>3.6.0</version>
</dependency>
XML 服务定义放在类路径中,namespace 绑定服务接口,<excel> 的 name 与接口方法对应。导出规则在 CDATA 中使用 EXPORT WITH 声明工作表、表头、映射和样式。项目测试 XML 已给出如下已确认写法,本文的所有样式讨论以它为基础。
xml
<style-example><![CDATA[
STYLE={
ROW 1: {
fontName: Arial,
fontHeightInPoints: 12,
italic: true,
color: yellow,
bold: true
}
}
]]></style-example>
这段代码不是独立 XML 根元素,而是将测试资源中的 DSL 结构抽出用于阅读。实际项目中,STYLE 位于 <excel> 的 EXPORT WITH 规则内。属性出现于测试 XML,说明当前任务允许以它们为事实基础;是否在所有正式报表中使用黄色、斜体或 12 磅字体,则必须由报表视觉要求决定。
代码示例
下面以库存报表为例。MAPPING 决定输出列顺序,STYLE 使用 ROW 1 为表头设置已确认的字体属性。为了说明单元格和范围定位方式,规则还使用 README-CN 明确列出的 A1:D1 和 A2:D100 矩形范围、C2 单元格。字体属性只使用测试 XML 已出现的五项。
xml
<excel name="exportInventory" returnClass="void"><![CDATA[
EXPORT WITH
SHEET="库存报表",
HEADER=true,
MAPPING={
"sku":"SKU",
"name":"商品名称",
"quantity":"库存数量",
"remark":"备注"
},
STYLE={
ROW 1:{
fontName: Arial,
fontHeightInPoints: 12,
italic: true,
color: yellow,
bold: true
},
A1:D1:{
fontName: Arial,
fontHeightInPoints: 12,
bold: true
},
A2:D100:{
fontName: Arial,
fontHeightInPoints: 12
},
C2:{
bold: true,
color: yellow
}
}
]]></excel>
上例的目的不是规定库存报表必须使用这些外观,而是说明四种已确认目标的使用边界。ROW 1 面向整行,适合表头共有的字体规则;A1:D1 面向一个矩形区域,适合已知列数的标题区域;A2:D100 面向正文中的固定矩形;C2 只定位一个单元格,适合确实稳定的局部例外。不同目标的选择取决于共同效果覆盖的空间范围。
Java 调用可沿用 README-CN 的 XML 导出示例:业务数据先转换为 JQuickRow,输出流与行数据交给 JQuickExcelExportXmlParseFactory,再由 JQuickXmlFactory 创建服务代理。样式已经在 XML 中描述,Java 不需要为这项基础需求逐格设置字体。
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 java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;
List<Map<String, Object>> inventory = loadInventory();
List<JQuickRow> rows = JQuickRow.toRows(JObjectConverter.convert(inventory));
try (OutputStream output = new FileOutputStream("inventory.xlsx")) {
JQuickParseHandler parser = new JQuickExcelExportXmlParseFactory(rows, output);
JQuickFactory factory = new JQuickXmlFactory(parser, "jquick-excel.xml");
InventoryExcelService service = factory.createApi(InventoryExcelService.class);
service.exportInventory("field", "value");
}
若报表还包含日期、金额等字段,可在同一个 EXPORT WITH 中添加 FORMAT。这不会改变 STYLE 的定位逻辑:字段级格式以字段键为中心,样式以工作表坐标为中心。下例在不增加未确认样式属性的前提下,展示二者并列。
xml
<excel name="exportItems" returnClass="void"><![CDATA[
EXPORT WITH
SHEET="商品表",
HEADER=true,
MAPPING={
"id":"主键",
"name":"名称",
"enrollmentDate":"日期"
},
FORMAT={"enrollmentDate":"yyyy-MM-dd"},
STYLE={
ROW 1:{
fontName: Arial,
fontHeightInPoints: 12,
italic: true,
color: yellow,
bold: true
}
}
]]></excel>
原理说明
STYLE 的左侧是样式目标,右侧是属性集合。README-CN 明确样式目标可为行、列、单元格或范围;范围语法包括 ROW 5、ROW 1..10、COL A、COL A..D、C1、A1:B5。它们都是工作表坐标。坐标与 MAPPING 之间没有自动的业务名称绑定,因此先调整映射列顺序、再复查样式坐标,是维护导出规则的基本顺序。
行、列、单元格和范围并不是互相替代的写法。行规则适合整行共同的外观,测试 XML 的 ROW 1 就是典型表头场景。列规则适合某一整列共有的需求。单元格规则适合一个稳定坐标的明确例外。矩形范围规则适合连续数据块。用面积最合适的目标表达共同效果,可以减少重复,同时减少列数和行数变化时的遗漏。
项目测试资源确认的五项字体属性具有清楚的视觉职责。fontName 指定字体名称,fontHeightInPoints 指定字号,italic 表示斜体,color 表示字体颜色,bold 表示粗体。DSL 可以表达它们,不意味着应同时堆在每一个区域。正式报表应以可读性、打印和业务规范为准;测试示例只提供了可验证的配置边界。
样式规则不改变字段数据。它不会重新排序 MAPPING,不会翻译字典,也不会把日期改成固定文本。README-CN 对 TRANSFORM 的描述是每一行计算表达式,对 FORMAT 的描述是 Excel 显示格式。需要改变字段值时使用 TRANSFORM,需要设置日期或数字展示时使用 FORMAT,需要设置字体外观时使用 STYLE。这种区分减少了一个字段同时在多个位置被赋予相同职责的风险。
多个样式目标若覆盖同一单元格,应避免依赖未确认的覆盖顺序。更稳妥的做法是把整行共性放在 ROW 1,把确有必要的固定局部差异写成最小范围,并用真实导出文件查看效果。XML 的书写顺序不应被假定为业务优先级说明;规则之间越少重叠,配置越容易维护。
注意事项
第一,坐标必须跟随布局。启用 HEADER=true 且没有额外顶部行时,ROW 1 可表达表头。若以后增加标题、说明行或调整列顺序,ROW 1、A1:D1、C2 等规则都应作为同一组变更复查。
第二,范围上限是模板约定。A2:D100 只表达该矩形区域,不能被理解为数据行会自动扩展到任何长度。数据量超过设计范围时,应使用真实样本检查后续行是否仍符合预期,并按业务容量调整规则。
第三,本文仅对已确认的字体属性作示例。不要根据其他 Excel 库或其他版本的习惯,将未知属性名称直接写入当前 DSL。配置关键字、花括号、逗号和目标语法都应保持 README-CN 与测试 XML 的形式。
第四,不要把日期和数字显示规则分散进样式坐标。README-CN 已有 FORMAT 作为字段级 Excel 显示格式。将日期格式集中在 FORMAT,将字体集中在 STYLE,有助于维护者理解每项规则的意图。
第五,长文本、不同字体安装情况和不同 Excel 客户端都可能影响最终观感。样式配置修改后,应导出包含中文、英文、空值和较长文本的真实样本验证。配置能被解析,不等于用户端的阅读效果一定满足要求。
第六,README-CN 说明 JQuickExcelConfig 可配置单元格样式缓存。大数据导出时,样式规则应避免无意义地制造大量独特组合,并通过真实数据规模测试内存与耗时。本文不扩展未知的样式实现细节,只强调样式数量和数据规模应被一起验证。
单元格坐标审查与验证
单元格样式的维护应从坐标清单开始,而非从视觉印象开始。每次修改 MAPPING 时,先按映射顺序列出表头所在的第一行及各字段列号,再逐项核对引用固定坐标的规则。测试资源已经确认 ROW 1 及五项字体属性的写法,因此表头公共字体可集中在该规则中;对任何固定单元格的补充配置,都应明确它服务的是哪一个当前列位和哪一种业务例外。字段插入、删除或重排时,审查者可以依据坐标清单发现失效规则,而不必依赖肉眼猜测。
建议将布局变更和字体变更作为同一次评审的两个检查项。布局变更关注 HEADER=true 是否仍使表头处于第一行,以及 MAPPING 的列顺序是否保持预期;字体变更仅检查 fontName、fontHeightInPoints、italic、color、bold 是否符合报表要求。不能因为示例中同时出现五个属性,就把它们视为不可拆分的固定组合。例如,只需要强化表头识别时,规则可以只保留已确认的 bold:true;需要统一字体时再加入 fontName。每个属性都应有明确的展示理由,避免把测试示例的外观直接复制为业务规范。
验证应同时覆盖解析结果和生成文件。首先用现有 XML 加载路径执行一次导出,确认 DSL 的关键字、目标和属性名称没有被拼写或标点错误破坏。随后使用包含中文、英文、空值及较长表头文本的样本,在目标 Excel 客户端检查第一行是否应用了预期的字体名称、字号、斜体、颜色和粗体。最后修改一次映射顺序或增减一个字段,重新导出并检查表头样式仍覆盖全部表头单元格。该回归场景直接验证 ROW 1 对列数变化的适应性,同时能暴露固定坐标规则是否需要同步调整。
对大数据场景,样本不应只包含少量行。README-CN 已确认可通过 JQuickExcelConfig 配置单元格样式缓存,因此应在接近实际行数的导出中观察耗时和内存,而不是推断缓存一定解决所有性能问题。此次核查无需假定缓存的内部实现:只要保持字体组合稳定、避免无目的地为大量位置写出不同组合,并用真实规模文件复验即可。验证记录应注明数据行数、映射列数、是否使用 ROW 1 以及实际使用的五项属性,便于以后定位由布局还是字体规则造成的差异。
总结
单元格样式应从工作表坐标出发,而不是从字段名称出发。STYLE 的目标可以是行、列、单元格或矩形区域,选择范围时应让它准确表达视觉共性:整行表头使用 ROW 1,稳定的数据块使用矩形范围,真正固定的局部例外才使用单元格坐标。这样既能减少重复配置,也能在映射列发生变化时更快识别哪些固定坐标已失效。
当前可据测试资源确认的字体属性仅包括 fontName、fontHeightInPoints、italic、color、bold。它们可以组合,不代表每张正式报表都应照搬黄色、斜体或固定字号。样式规则应服务于表头识别、阅读和打印需求,避免在覆盖相同单元格的多条规则中依赖未经确认的优先级或书写顺序。
验证不能只看 DSL 是否解析成功。应使用含中文、英文、空值和长文本的导出样本,在实际 Excel 客户端检查坐标、字体和表头覆盖范围;新增、删除或重排 MAPPING 字段后,再确认范围规则仍指向正确列。日期与数字显示继续由 FORMAT 承担,字段计算留给 TRANSFORM。数据量增加时还应观察样式组合数量与实际导出性能,而不是只依据小样本推断结果。