关注我的公众号:【编程朝花夕拾】,可获取首发内容。

01 引言
你是否因为Html
转PDF
发愁?又是否因为中文乱码而心烦意乱?又是否因为格式导致PDF
排版错乱而苦恼?......
在企业里,我们经常会遇到下载PDF
报告的场景,前端展示还好,可以使用pdf.js
类似的框架处理,但是很多时候,需要服务端自己渲染数据然后,上传或者邮件发送。好好的页面,转成PDF
直接错乱了,只能一点点的调试,才能完成。过程费时费力。
这不,前两天正好遇到Html
转PDF
的需求,调整了许久的样式才完成PDF
的完美转化。
02 框架选型
将Html
转化成PDF
的框架有很多,小编也试了好几种,将觉得好用的分享给大家。
2.1 io.woo.htmltopdf
Maven
xml
<dependency>
<groupId>io.woo</groupId>
<artifactId>htmltopdf</artifactId>
<version>1.0.4</version>
</dependency>
<!-- Thanks for using https://jar-download.com -->
官网地址:jar-download.com

GitHub
地址:github.com/wooio/htmlt...

2.2 openhtmltopdf
Maven
xml
<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>

GitHub
地址:github.com/danfickle/o...
2.3 Flying Saucer
Maven
xml
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf</artifactId>
<version>10.0.0</version>
</dependency>

GitHub
地址:github.com/flyingsauce...
03 Springboot集成thymeleaf
3.1 Maven依赖
这里暂时忽略Html
转PDF
的依赖,后面按需引入。
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 模板引擎 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- html 2 pdf 工具 -->
3.2 页面
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>评估报告</title>
</head>
<body>
<div class="total-container">
<div class="container" th:each="item:${list}">
<input type="hidden" th:value="${item.licenseCode}" name="licenseCode" />
<div class="img-container">
<img th:src="${item.image1}" />
<img th:src="${item.image2}" />
</div>
<div class="title" th:text="${item.vehicleName}"></div>
<div>
<ul>
<li>
<label>品牌:</label>
<span th:text="${item.brandName}"></span>
</li>
<li>
<label>车系:</label>
<span th:text="${item.seriesName}"></span>
</li>
<li>
<label>年款:</label>
<span th:text="${item.modelYear}"></span>
</li>
<li>
<label>上牌年月:</label>
<span th:text="${item.licenseYear}"></span>
</li>
<li>
<label>里程(公里):</label>
<span th:text="${item.displayMileage}"></span>
</li>
<li>
<label>成交日期:</label>
<span th:text="${item.dealDate}"></span>
</li>
<li style="border-bottom: none;">
<label>成交价(元):</label>
<span th:text="${item.dealPrice}"></span>
</li>
</ul>
</div>
</div>
</div>
</body>
</html>
这里描述了车辆的信息
3.3 数据渲染
java
@RequestMapping("index")
public String index(Model model) {
List<Map<String, Object>> list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
Map<String, Object> item = new HashMap<>();
item.put("image1", "http://img.example.com/a.jpg");
item.put("image2", "http://img.example.com/b.jp");
item.put("vehicleName", "路虎Defender[卫士](进口)2023款Defender130 48V[卫士 130 48V] 3.0T手自-体P400 HSE");
item.put("brandName", "路虎");
item.put("seriesName", "Defender[卫士]");
item.put("modelYear", "2023款");
item.put("licenseYear", SDF.format(new Date()));
item.put("displayMileage", DF.format(new BigDecimal("9657")));
item.put("dealDate", SDF.format(new Date()));
item.put("dealPrice", DF.format(new BigDecimal("1000000")));
list.add(item);
}
model.addAttribute("list", list);
return "index";
}
3.4 渲染效果

左右没有留白。
04 Html转PDF
上面已经完成Html
的渲染和展示。我们只需要拿到Html
并通过工具,转化成PDF
即可。
Html
转PDF
不需要通过浏览器渲染,需要服务端直接渲染并拿到渲染之后的Html
。渲染的代码块:
java
Map<String, Object> map = new HashMap<>();
map.put("list", list);
Context context = new Context(Locale.getDefault(), map);
String html = templateEngine.process("index", context);
System.out.println(html);
4.1 io.woo.htmltopdf
核心方法:
java
InputStream convert = HtmlToPdf.create()
.object(HtmlToPdfObject.
forHtml(htmlContent)
.defaultEncoding("utf-8"))
.convert();
IOUtils.copyLarge(convert, response.getOutputStream());
效果

我们会发现转成PDF
之后,左右会自动留白。现在的问题是,图片需要调整一下,调整到左右留白差不多,这个是难点。
应该怎么去调整呢?
因为生成的PDF
默认都是基于A4
的尺寸:21cm*29.7cm
。所以我们直接将宽度设置为21cm
。
css
.container{
width: 21cm;
/*设置边框方便查看*/
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
}
转成PDF之后右边距还是有较大的空隙的:

我们继续加大宽度,最终结果:宽度设置23cm
比较合适。此时,就可在页面上愉快的调整图片或者其他与元素了。
4.2 openhtmltopdf
核心方法
java
PdfRendererBuilder builder = new PdfRendererBuilder();
builder.withHtmlContent(htmlContent, null);
builder.toStream(response.getOutputStream());
// 配置字体支持中文
builder.useFont(new File("C:\\Windows\\Fonts\\simhei.ttf"), "SimHei");
builder.run();

注意事项
-
需要设置支持中的字体,且页面的
font-family
需要明确指出cssfont-family: "SimHei";
-
页面元素必须要有闭合标签,否则报错
调整
调整依然是难点。经过测试,该框架的的PDF
和A4
纸的大小基本一致。而内容则是去除留白的长度。
经过测量:PDF长度794px,两边留白56px,所以页面长度:794-56-56 = 682px
调正页面长度:
css
.container{
font-family: "SimHei";
width: 682px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
}
效果非常完美:

4.3 Flying Saucer
核心方法
java
ITextRenderer renderer = new ITextRenderer();
renderer.getFontResolver().addFont("C:\\Windows\\Fonts\\simh ei.ttf", BaseFont.IDENTITY_H,BaseFont.NOT_EMBEDDED);
renderer.setDocumentFromString(htmlContent);
renderer.layout();
renderer.createPDF(response.getOutputStream());
这里同样要设置支持中文,和openhtmltopdf
配置类似。
调整方式同4.2
。openhtmltopdf
本身就是基于Flying Saucer
,所以这里就不在演示,两个同宗同源。
05 小结
每一款软件都是其特定标准,调整的顺序也不一样。无论如何,解决问题的思路是一致的。相比较io.woo.htmltopdf
可能更加方便,本身就支持中文,而其他两个则需要单独配置才能支持中文。你们更喜欢哪一种呢?