jquick-pdf 文本元素实战:段落、行内文本、制表符用法详解
引入
账单、回执和通知单几乎全是文字,却最容易出现排版返工:客户名称要加粗,金额要变色,说明要换行,账户标签还要整齐对齐。手写底层 PDF 绘制需要自行计算文字宽度,用连续空格对齐又会受字体和渲染器影响。jquick-pdf 用 <p>、<span>、<tab> 和 <br> 把这四类意图表达在模板里。
核心讲解
四个元素的语义差异
<p>:独立段落,属于块级元素,负责垂直方向的排布,段与段之间会产生间距。<span>:段落中的行内片段,不产生段落间距,在当前位置继承并覆盖局部样式。<tab>:水平间隔节点,插入一段可控宽度的留白,用于标签与取值之间的对齐。<br>:行内换行,结束当前行但不结束段落。
固定文本必须使用单引号,例如 '合计金额';动态值使用 ${variable};已注册资源使用 &{name}。模板以 <pdf> 或 <html> 为根元素,常用形式是 <pdf><body>...</body></pdf>。这些标签属于文档模板层,语义不等同于浏览器中的全部 HTML 行为。
解析与渲染流程
解析器先识别段落与子节点,文本渲染器再把固定文本、变量和 span 样式合并到布局上下文;p 负责垂直排布,span 覆盖局部样式,tab 参与水平布局,br 结束当前行。
对齐与长文本换行
块级元素上的 textAlignment 控制整段文本的水平对齐,characterSpacing 调整字距;段落内的长文本由布局引擎按可用宽度自动折行,无需手动换行。连续空格只影响当前行的视觉宽度,不构成稳定布局;地址、备注等自然语言字段应允许自动换行,不能为了单行展示而硬塞 tab 或固定宽度。
依赖与示例资源
文本相关能力只需 jquick-pdfx。示例模板位于 src/test/resources/sample/text/paragraph.txt、span.txt、tab.txt,还可以参考 br.txt。需要卡片式背景时用 <div> 包住多个段落,而不是用 span 模拟容器。
关键细节
样式属性
文字常用 fontSize、fontColor、bold、italic、underline、textAlignment 和 characterSpacing;间距常用 margin 与 padding 相关属性,背景和边框可用于 p 或外层 div。tab 示例使用 width:48px 指定间距,也可以使用默认宽度。属性名支持驼峰与连字符互为别名,但同一份模板最好统一风格。
行内与块级混用的注意事项
- 独立业务字段使用 p,例如客户、周期和付款状态;只有局部强调时才使用 span,否则多个 span 连在一起可能不会产生预期的段落间距。
- 同一行存在多个重点片段时,保持固定的文本顺序,并避免在一个 span 内混入过长的动态内容。
- 动态值可能因中文、英文和数字混排而产生不同宽度,需要列对齐时使用 table 更稳。
- 用 br 处理同一段说明中的主动换行,不要用大量 br 代替多个 p。
数据与安全边界
变量值可能包含特殊字符或换行,业务层应先做格式化和长度限制,空值转为空字符串,避免 PDF 中出现 null 字样。中文字体要在目标容器中验证;金额、日期和状态颜色应由业务规范统一。模板从数据库或配置中心读取时,禁止让用户任意指定本地资源路径;生成失败时记录账单编号和模板版本即可,不要记录完整敏感内容。
性能
文本模板通常不是瓶颈,真正影响性能的是大批量页面、字体加载和超长内容。固定模板使用 classpath 资源,批量任务控制线程数,提前裁剪异常长字段;把长通知拆成合理段落可降低布局回溯成本。
实战说明
依赖
xml
<dependency>
<!-- 文本模板与 PDF 渲染核心 -->
<groupId>io.github.paohaijiao</groupId>
<artifactId>jquick-pdfx</artifactId>
<version>4.0.0</version>
</dependency>
项目运行在 JDK 8+。建议先复制最小模板运行,再逐一添加样式和变量。
BillingNoticePdfDemo
java
import com.github.paohaijiao.executor.JQuickPdfFactory;
import java.nio.file.Files;
import java.nio.file.Paths;
public class BillingNoticePdfDemo {
public static void main(String[] args) throws Exception {
String template = ""
+ "<pdf><body>"
+ "<h1 style=\"fontSize:22;fontColor:#1d4ed8\">'客户账单通知单'</h1>"
+ "<p>'尊敬的 '<span style=\"fontColor:#0f766e;bold:true;width:600px\">${customer}</span><span style=\"margin-left:500px;\">' ,您好:'</span></p>"
+ "<p>'账单周期:'<span style=\"bold:true\">${period}</span></p>"
+ "<p>'本期应付金额:¥'<span style=\"fontColor:#dc2626;fontSize:16;bold:true\">${amount}</span></p>"
+ "<p>'付款状态:'<span style=\"fontColor:#dc2626;bold:true\">${status}</span></p>"
+ "<p>'收款账户:'<tab style=\"width:48px\"></tab>${account}</p>"
+ "<p>'开户银行:'<tab style=\"width:48px\"></tab>${bank}</p>"
+ "<p>'付款说明:请保留付款回单。'<br>'如需发票,请联系客户经理。'</p>"
+ "</body></pdf>";
System.out.println(template);
// 绑定账单业务数据
byte[] bytes = JQuickPdfFactory.create()
.bind("customer", "杭州星河信息技术有限公司 ")
.bind("period", "2026 年 9 月")
.bind("amount", "18,560.00")
.bind("status", "待付款(已逾期)")
.bind("account", "北京云数科技有限公司")
.bind("bank", "招商银行北京中关村支行")
.executeContent(template);
// 写入 PDF 文件
Files.write(Paths.get("d://test//billing-notice.pdf"), bytes);
}
}

金额高亮与状态着色都由 span 的 fontColor、fontSize 和 bold 组合实现,不需要在 Java 侧拼装富文本对象;颜色语义必须与业务规范一致。
调用顺序与数据准备
文本模板的调用顺序固定:先构造模板,再准备展示值,最后执行渲染。bind 接收字符串键和任意对象,占位符名称要保持一致,字段较多时可用 bindAll(Map<String,Object>) 一次传入;文本较长时可放入资源文件并调用 executeResource。p、span、tab 和 br 的能力通过模板标签表达,不需要额外创建 Paragraph 或 Text 对象。每增加一个动态字段,都应同步增加一组空值和长文本测试数据。
组合方式与场景选型
以订单通知为例,可先把数据整理成"标签、值、语义样式"三部分:订单号和客户名用普通 p,逾期状态用 span 标红,付款说明用 p 加 br,收款账户用 tab。页面有标题、说明和少量字段时以 p 为主;重点数据放 span;标签间距用 tab;多行说明用 br;商品明细等多列数据必须换成 table。
这套组合适用于账单通知、订单确认、发货提醒、售后回执、审批结论、人事证明和客服函件。与手写方案相比,iText 需要创建段落与文本片段并设置字体,PdfBox 更常需要自行测量定位;jquick-pdf 把这些意图放进模板,代码更聚焦于数据绑定。浏览器 HTML 支持更多 CSS,但兼容边界不同:复杂富文本或底层 PDF 对象控制应另行选型。
总结
文本排版的关键结论是:独立信息用 p,局部强调用 span,稳定留白用 tab,段落内换行用 br,真正需要列对齐时使用 table。金额高亮、状态着色、标签对齐和说明换行都可以用这四个元素组合完成。
需要留意的边界有三点:连续空格的宽度随字体变化,不能当作布局手段;变量值可能包含特殊字符或换行,必须先格式化并限制长度;这套写法只覆盖规则文本,遇到多列明细、复杂富文本或底层 PDF 对象控制时,应及时切换到表格结构或另行选型。可以继续组合 <div> 做信息卡片、<table> 做明细、<list> 做注意事项。版本基线:jquick-pdfx 4.0.0、JDK 8+;更多示例见 GitHub 仓库。