环境:SpringBoot3.2.8
1. 简介
OpenHtmlToPdf是一个开源的Java库,专为将HTML内容转换为PDF文档而设计。它支持大部分CSS样式和部分HTML5特性,使得从网页或HTML模板生成高质量的PDF文件变得简单高效。OpenHtmlToPdf不仅提供了基础的HTML到PDF的转换功能,还允许用户通过丰富的配置选项来自定义PDF文档的样式和输出设置。该组件的引入,极大地简化了项目中生成PDF文档的工作流程,无论是用于生成报告、合同、还是电子书等场景,都能轻松应对。
接下来我们将在SpringBoot项目中,通过Freemarker模板引擎渲染HTML模板,并利用OpenHtmlToPdf库将渲染后的HTML内容转换为PDF文档,最后通过HTTP响应将PDF文件提供给用户下载。
2. 实战案例
2.1 引入依赖
<!-- 该库进行HTML的解析 -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.18.1</version>
</dependency>
<!-- 将HTML内容转换为PDF文档 -->
<dependency>
<groupId>com.openhtmltopdf</groupId>
<artifactId>openhtmltopdf-core</artifactId>
<version>${openhtmltopdf.version}</version>
</dependency>
<dependency>
<groupId>com.openhtmltopdf</groupId>
<artifactId>openhtmltopdf-pdfbox</artifactId>
<version>${openhtmltopdf.version}</version>
</dependency>
接下来是准备需要的资源
2.2 资源准备
要支持中文,需要进行字体的准备,我这里使用的BabelStoneHan.ttf
图片
我们要通过freemarker模板技术生成HTML文档,还需要准备ftl模板,内容如下:
<html>
<head>
<meta charset="UTF-8">
<title>用户列表</title>
<style>
body {font-family: "BabelStoneHan",sans-serif;}
table {width: 100%;border-collapse: collapse;}
th,td {border: 1px solid black;padding: 8px;text-align: left;}
th {background-color: #f2f2f2;}
</style>
</head>
<body>
<div class="title-container">
<h2>XXXOOO全部用户列表信息</h2>
</div>
<div class="content-container">
<table>
<tr>
<th>编号</th>
<th>姓名</th>
<th>性别</th>
<th>身份证</th>
<th>年龄</th>
<th>邮箱</th>
<th>头像</th>
</tr>
<#list users as user>
<tr>
<td>${user.id}</td>
<td>${user.name}</td>
<td>${user.sex}</td>
<td>${user.idNo}</td>
<td>${user.age}</td>
<td>${user.email}</td>
<td><img src="https://img0.baidu.com/it/u=3366443890,3137275928&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500" alt="Avatar" style="width:50px;"></td>
</tr>
</#list>
</table>
</div>
</body>
</html>
模板保存路径如下
图片
基础资源都准备好后,接下来就是进入代码编写了
2.3 基础配置&准备数据
对freemarker进行基本的配置,如:编码,模板路径等。
@Bean
Configuration config(ResourceLoader loader) {
freemarker.template.Configuration cfg = null ;
try {
cfg = new Configuration(Configuration.VERSION_2_3_33);
// 设置模板路径
File baseDir = loader.getResource("classpath:/templates/").getFile() ;
TemplateLoader templateLoader = new FileTemplateLoader(baseDir) ;
cfg.setTemplateLoader(templateLoader) ;
// 设置编码
cfg.setDefaultEncoding("UTF-8") ;
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER) ;
} catch (IOException e) {
e.printStackTrace() ;
}
return cfg ;
}
以后要具体使用模板都会通过这里的Configuration获取。
准备数据,这里为了足够的简单,并不去DB查询数据。
private static final List<User> DATAS = new ArrayList<>() ;
static {
for (int i = 0; i < 10; i++) {
DATAS.add(new User(
i + 0L,
"姓名 - " + i,
new Random().nextInt(3) % 2 == 0 ? "男" : "女",
"身份证 - " + i,
new Random().nextInt(100),
i + "@qq.com",
"avatar.png") // 头像实际在模板中写死了
) ;
}
}
以上工作做完后接下来就可以进行PDF的生成了。我这里会直接通过一个Controller接口生成&下载PDF文档。
2.4 生成PDF
@RestController
@RequestMapping("/users")
public class UserController {
private final Configuration cfg ;
public UserController(Configuration cfg) {
this.cfg = cfg ;
}
// 生成PDF
@GetMapping("/gen")
public Object gen(HttpServletResponse response) {
// 设置文件下载Header
String fileName = new String("用户列表.pdf".getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1) ;
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
response.setContentType("application/octet-stream") ;
try {
// 获取模板
Template template = this.cfg.getTemplate("users.ftl") ;
// 准备模板需要的数据
Map<String, Object> root = new HashMap<>() ;
root.put("users", DATAS) ;
// 生成HTML内容到内存中
ByteArrayOutputStream baos = new ByteArrayOutputStream() ;
Writer out = new OutputStreamWriter(baos) ;
template.process(root, out) ;
// 将上面生成的HTML内容进行解析
Document document = Jsoup.parse(baos.toString(StandardCharsets.UTF_8), "UTF-8") ;
// 设置HTML语法
document.outputSettings().syntax(Document.OutputSettings.Syntax.html) ;
// 构建PDF文档,最后将上面的Document进行输出
PdfRendererBuilder builder = new PdfRendererBuilder();
// 使用字体,字体名要与模板中CSS样式中指定的字体名相同
builder.useFont(new ClassPathResource("/fonts/BabelStoneHan.ttf").getFile(), "BabelStoneHan", 1, BaseRendererBuilder.FontStyle.NORMAL, true);
builder.toStream(response.getOutputStream()) ;
builder.useFastMode() ;
builder.withW3cDocument(new W3CDom().fromJsoup(document), new ClassPathResource("/templates/").getPath());
builder.run() ;
} catch (Exception e) {
e.printStackTrace() ;
}
return "生成成功" ;
}
}
测试访问/users/gen接口。
图片
PDF文档正常生成了。
总结:OpenHtmlToPdf 是一个功能强大的开源Java库,专为将HTML内容转换为高质量的PDF文档而设计。它以其出色的HTML和CSS兼容性、灵活的配置选项以及易于集成的特点而广泛的认可和应用。