跳转到内容

JQuick-Pdf

JQuick-Pdf 是 JQuick 生态中的 PDF 工具包,面向 Java 端的 生成、渲染与导出:写一份类似 HTML + 内联 CSS 的模板,绑定数据,即可拿到 PDF —— 可以是 byte[]、流或文件。

模板由 ANTLR4 语法解析,并通过 Apache PDFBox 直接绘制到页面上,整条链路 没有浏览器、没有 Headless Chrome、没有本地库,非常适合嵌入服务端、定时任务或桌面应用。

模块 坐标 说明
jquick-pdfx io.github.paohaijiao:jquick-pdfx 解析器、渲染器、布局引擎与入口 JQuickPdfFactory,多数场景只需引入它
jquick-pdf-css io.github.paohaijiao:jquick-pdf-css CSS 模型:样式属性、单位与颜色
jquick-pdf-svg io.github.paohaijiao:jquick-pdf-svg SVG / ECharts 风格图表生成(30+ 图表类型)
jquick-pdf-data io.github.paohaijiao:jquick-pdf-data 图表配置模型(JOption、JChart、JTitle、JLegend 等)
jquick-pdf-font io.github.paohaijiao:jquick-pdf-font 内置中文字体资源,中文渲染零配置
  • 纯 Java,无外部引擎:不需要 WebKit、Chrome 或任何操作系统级依赖,一个 JVM 进程即可完成渲染。
  • HTML/CSS 风格模板:14 种元素,每个元素都支持 style="..." 内联样式。
  • 两种命名约定:minHeight(驼峰)与 min-height(标准 CSS)等价,可在同一声明中混用。
  • 数据绑定:${variable} 绑定普通值,&{resource} 引用已注册资源(图表、子模板、树形结构)。
  • 30+ 图表类型:柱状图、折线图、饼图、雷达图、散点图、箱线图、热力图、K 线、漏斗图、仪表盘、甘特图、词云、地图、旭日图、矩形树图、拓扑图等,全部为矢量绘制。
  • 完整文档能力:自动分页、目录(TOC)、页眉页脚、页码、水印、PDF 加密。
  • 中文友好:内置 CJK 字体,中文内容开箱即用。
  • 模块化产物:只依赖解析与渲染核心,图表、CSS、字体按需追加。
  • Java 8 兼容:发布产物面向 Java 8 字节码。
<dependency>
<groupId>io.github.paohaijiao</groupId>
<artifactId>jquick-pdfx</artifactId>
<version>4.1.0</version>
</dependency>

图表能力为可选依赖:

<dependency>
<groupId>io.github.paohaijiao</groupId>
<artifactId>jquick-pdf-svg</artifactId>
<version>4.1.0</version>
</dependency>
import com.github.paohaijiao.executor.JQuickPdfFactory;
import java.nio.file.Files;
import java.nio.file.Paths;
public class HelloDemo {
public static void main(String[] args) throws Exception {
String template = ""
+ "<pdf>"
+ " <body>"
+ " <h1 style=\"fontSize:24;fontColor:blue\">'Hello jquick-pdf'</h1>"
+ " <p>'Customer: '${customer}</p>"
+ " </body>"
+ "</pdf>";
// 绑定数据并渲染为 PDF 字节数组 / bind data and render to PDF bytes
byte[] pdf = JQuickPdfFactory.create()
.bind("customer", "Martin")
.executeContent(template);
Files.write(Paths.get("hello.pdf"), pdf);
}
}

以下方法均返回 byte[]:

方法 模板来源
executeContent(String) 内存中的模板文本
executeResource(String) classpath 资源,例如 "report.txt"
executeFile(String) 磁盘文件,例如 "D:/templates/report.txt"

模板从 classpath 读取,支持 flex 布局、表格、列表与内联 SVG 图表:

import com.github.paohaijiao.adaptor.JAdaptor;
import com.github.paohaijiao.config.JPdfConfig;
import com.github.paohaijiao.executor.JQuickPdfFactory;
import com.github.paohaijiao.resouce.JReader;
import com.github.paohaijiao.resouce.impl.JReSourceFileReader;
import java.io.FileOutputStream;
public class CreditReportDemo {
public static void main(String[] args) throws Exception {
// 开启 flex 布局:雷达图与右侧指标面板并排显示
JPdfConfig config = new JPdfConfig();
config.getLayoutConfig().setFlexLayout(true);
JReader fileReader = new JReSourceFileReader("report.txt"); // 文档模板
JAdaptor adaptor = new JAdaptor(fileReader);
JReader svgReader = new JReSourceFileReader("radar.txt"); // 内联 SVG 图表
JAdaptor svgAdaptor = new JAdaptor(svgReader);
JQuickPdfFactory factory = new JQuickPdfFactory(config);
factory.bind("svg", svgAdaptor.getRuleContent()); // 绑定 ${svg} 占位符
byte[] bytes = factory.executeContent(adaptor.getRuleContent());
try (FileOutputStream out = new FileOutputStream("credit-report.pdf")) {
out.write(bytes);
}
}
}

对应的模板片段(节选自 report.txt):

<pdf>
<body>
<div style="textAlignment:center; marginBottom:5px; background:#3E6B9D; color:white; borderRadius:4px">
<h1 style="textAlignment:center;color:white; fontSize:20">'企业信用评级报告'</h1>
<p style="textAlignment:center;color:rgba(255,255,255,0.9); fontSize:11">'报告编号: CR-2023-08975'</p>
</div>
<table style="width:600px; fontSize:10">
<tr>
<td style="backgroundColor:#f8f9fa;padding:5px;width:150px;">'统一信用代码'</td>
<td style="backgroundColor:#f8f9fa;padding:5px;width:150px;">'91110108MA01XX1234'</td>
</tr>
</table>
<list style="list-style-type:none; paddingLeft:0; fontSize:11">
<li style="marginBottom:8px; padding:10px; backgroundColor:#f8f9fa; borderLeft:4px solid #4CAF50">
'营收增长率: 连续三年保持 40% 以上增长'
</li>
</list>
<div style="display:flex; justifyContent:space-between; marginTop:10px">
<svg style="width:400px;height:400px">${svg}</svg>
<div style="width:300px">
<h3 style="fontSize:12">'评级指标说明'</h3>
</div>
</div>
</body>
</pdf>

图表通过 JOption 配置,配置思路与 ECharts 一致,渲染结果是矢量图形,可直接写入 .svg 文件或嵌入文档。

import com.github.paohaijiao.axis.JCategoryAxis;
import com.github.paohaijiao.axis.JValueAxis;
import com.github.paohaijiao.bar.JBarChartsRenderer;
import com.github.paohaijiao.code.JTrigger;
import com.github.paohaijiao.series.JBar;
JOption option = new JOption();
option.title().text("销售数据").subtext("2023 年度");
option.tooltip().trigger(JTrigger.axis);
JCategoryAxis xAxis = new JCategoryAxis();
xAxis.data("衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子");
option.xAxis(xAxis);
option.yAxis(new JValueAxis());
JBar bar = new JBar();
bar.name("销量").data(5, 20, 36, 10, 10, 20);
option.series(bar);
// 渲染为 SVG 文件,或渲染为字符串后嵌入模板
JBarChartsRenderer renderer = new JBarChartsRenderer();
renderer.render(option, "barchart.svg");
String svg = renderer.renderToString(option);
元素 用途
<h1> … <h6> 六级标题
<p> / <span> / <br> / <tab> 段落、行内文本、换行与制表
<div> 块容器:背景、边框、内边距、尺寸、旋转、flex
<list> / <li> 列表容器与列表项
<table> / <tr> / <th> / <td> 表格与单元格样式
<image src="..." alt="..."> 位图图片
<svg> 矢量图,配合 ${svg} / &{svg}
<tree> 树形结构
<button> / <checkbox> / <comboBoxField> / <textArea> 交互式表单控件
<areaBreak> / <htmlPageBreak> / <lineSeparator> 强制分页 / HTML 风格分页 / 分隔线
<template> 可复用模板片段

样式写在任意元素的 style="..." 上,minHeight(驼峰)与 min-height(标准 CSS)等价,可混用;单位支持 px(96 DPI,1px = 0.75pt)、pt、mm、cm、in;颜色支持颜色名、#RRGGBB、rgb() / rgba() 与 linear-gradient(...)。