若是有类似需求,可以看看这篇文章。起因是之前的一个需求,要求一次请求访问生成5种样式不同的PDF文件,并打包压缩,接着发送到指定邮箱。一开始我考虑的是PdfBox,简单用了一下,发现实在不方便,需要的样式不是靠调偏移量可以正常调过来的。后面发现了这个 openhtmltopdf 开源库,我开始编写原生HTML及CSS,用 openhtmltopdf 来转换为PDF(适合样式复杂的PDF)。
本文只描述简易用法,更多请查看 指南。
首先导入Maven依赖(可使用Jsoup,用于解析Dom):
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.15.4</version>
</dependency>
<dependency>
<groupId>com.openhtmltopdf</groupId>
<artifactId>openhtmltopdf-core</artifactId>
<version>1.0.10</version>
</dependency>
<dependency>
<groupId>com.openhtmltopdf</groupId>
<artifactId>openhtmltopdf-pdfbox</artifactId>
<version>1.0.10</version>
</dependency>
String html = "......";
Document document = Jsoup.parse(html);;
document.outputSettings().syntax(Document.OutputSettings.Syntax.html);
这个主要针对于你有图片,或把CSS摘出来放在外面的情况,需要设置资源目录。
当你在HTML中引用CSS、图片等资源时,需指定
URL格式
的目录路径。
且指定的路径必须是 HTML 引用资源的路径的父目录。
我们假设资源目录设置为 file:///D:/JavaProjects/spring-new-demo/src/main/resources
,这个URL指向着 resources
这个目录,而假设在 resources
目录下,存在着以下的目录结构。
# 目录结构
# resources/
# print/
# |-- css/
# |-- test.css
# |-- images/
# |-- test.jpg
那么在HTML中的引用就该这样写:
<!-- 引入CSS -->
<link rel="stylesheet" href="print/css/test.css">
<!-- 引入图片 -->
<img src="print/images/test.jpg" alt="">
资源目录 /resources
为 print/css/
、print/images/
目录的父级目录,所以按照 HTML 中定义引入:print/css/test.css
,表示引用 /resources/print/css/test.css
文件。
Jar包中,URL格式路径是不一样的,你需要以这种格式作为资源目录:
jar:file:/....../spring-new-demo.jar!/BOOT-INF/classes!/
因为打完包后,/print/
目录会放在/BOOT-INF/classes/
下
获取Jar包中的资源目录路径:
继续刚才的目录结构,先找到Jar包内某文件的URL形式,再通过截取获取Jar包内
resources
目录的URL路径。
private static String getPath(String templateName) {
String resultPath;
try {
String templateLoaderPath = "classpath:/print/css/";
// classpath:/print/css/
templateLoaderPath = templateLoaderPath.replace(ResourceUtils.CLASSPATH_URL_PREFIX + "/", ResourceUtils.CLASSPATH_URL_PREFIX);
URL url = ResourceUtils.getURL(templateLoaderPath + "test.css");
String path = url.toExternalForm();
String[] pathArray = path.split("/");
pathArray = ArrayUtil.sub(pathArray, 0, pathArray.length - 3);
resultPath = ArrayUtil.join(pathArray, "/") + "/";
} catch (FileNotFoundException e) {
}
return resultPath;
}
注意
如果不设置字体,用默认字体的话,HTML内的中文会变成###(建议把字体文件放在Jar包外)。
需要准备一个中文字体,例如宋体,建议ttf格式。
转换比较简单,只要准备好前面的东西,可一键生成。
注意
需注意的是,生成出的PDF效果可能会与HTML展示的效果有细微差距,可能需要自己慢慢调节。
// 解析HTML
Document document = Jsoup.parse(html);
document.outputSettings().syntax(Document.OutputSettings.Syntax.html);
// Pdf文件
String savePath = "....";
File pdfFile = new File(savePath);
// 字体资源
String fontPath = "....";
File fontFile = new File(fontPath);
try (OutputStream os = FileUtil.getOutputStream(pdfFile)) {
PdfRendererBuilder builder = new PdfRendererBuilder();
// 快速模式
builder.useFastMode();
builder.toStream(os);
// 资源路径
builder.withW3cDocument(new W3CDom().fromJsoup(document), resourcesPath);
// 使用字体
builder.useFont(fontFile, fontFamily);
// 执行
builder.run();
}