完美!SpringBoot + HTML模板高效生成PDF文檔
環(huán)境:SpringBoot3.2.8
1. 簡介
OpenHtmlToPdf是一個(gè)開源的Java庫,專為將HTML內(nèi)容轉(zhuǎn)換為PDF文檔而設(shè)計(jì)。它支持大部分CSS樣式和部分HTML5特性,使得從網(wǎng)頁或HTML模板生成高質(zhì)量的PDF文件變得簡單高效。OpenHtmlToPdf不僅提供了基礎(chǔ)的HTML到PDF的轉(zhuǎn)換功能,還允許用戶通過豐富的配置選項(xiàng)來自定義PDF文檔的樣式和輸出設(shè)置。該組件的引入,極大地簡化了項(xiàng)目中生成PDF文檔的工作流程,無論是用于生成報(bào)告、合同、還是電子書等場景,都能輕松應(yīng)對(duì)。
接下來我們將在SpringBoot項(xiàng)目中,通過Freemarker模板引擎渲染HTML模板,并利用OpenHtmlToPdf庫將渲染后的HTML內(nèi)容轉(zhuǎn)換為PDF文檔,最后通過HTTP響應(yīng)將PDF文件提供給用戶下載。
2. 實(shí)戰(zhàn)案例
2.1 引入依賴
<!-- 該庫進(jìn)行HTML的解析 -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.18.1</version>
</dependency>
<!-- 將HTML內(nèi)容轉(zhuǎn)換為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>
接下來是準(zhǔn)備需要的資源
2.2 資源準(zhǔn)備
要支持中文,需要進(jìn)行字體的準(zhǔn)備,我這里使用的BabelStoneHan.ttf
圖片
我們要通過freemarker模板技術(shù)生成HTML文檔,還需要準(zhǔn)備ftl模板,內(nèi)容如下:
<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>編號(hào)</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>
模板保存路徑如下
圖片
基礎(chǔ)資源都準(zhǔn)備好后,接下來就是進(jìn)入代碼編寫了
2.3 基礎(chǔ)配置&準(zhǔn)備數(shù)據(jù)
對(duì)freemarker進(jìn)行基本的配置,如:編碼,模板路徑等。
@Bean
Configuration config(ResourceLoader loader) {
freemarker.template.Configuration cfg = null ;
try {
cfg = new Configuration(Configuration.VERSION_2_3_33);
// 設(shè)置模板路徑
File baseDir = loader.getResource("classpath:/templates/").getFile() ;
TemplateLoader templateLoader = new FileTemplateLoader(baseDir) ;
cfg.setTemplateLoader(templateLoader) ;
// 設(shè)置編碼
cfg.setDefaultEncoding("UTF-8") ;
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER) ;
} catch (IOException e) {
e.printStackTrace() ;
}
return cfg ;
}
以后要具體使用模板都會(huì)通過這里的Configuration獲取。
準(zhǔn)備數(shù)據(jù),這里為了足夠的簡單,并不去DB查詢數(shù)據(jù)。
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") // 頭像實(shí)際在模板中寫死了
) ;
}
}
以上工作做完后接下來就可以進(jìn)行PDF的生成了。我這里會(huì)直接通過一個(gè)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) {
// 設(shè)置文件下載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") ;
// 準(zhǔn)備模板需要的數(shù)據(jù)
Map<String, Object> root = new HashMap<>() ;
root.put("users", DATAS) ;
// 生成HTML內(nèi)容到內(nèi)存中
ByteArrayOutputStream baos = new ByteArrayOutputStream() ;
Writer out = new OutputStreamWriter(baos) ;
template.process(root, out) ;
// 將上面生成的HTML內(nèi)容進(jìn)行解析
Document document = Jsoup.parse(baos.toString(StandardCharsets.UTF_8), "UTF-8") ;
// 設(shè)置HTML語法
document.outputSettings().syntax(Document.OutputSettings.Syntax.html) ;
// 構(gòu)建PDF文檔,最后將上面的Document進(jìn)行輸出
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文檔正常生成了。
總結(jié):OpenHtmlToPdf 是一個(gè)功能強(qiáng)大的開源Java庫,專為將HTML內(nèi)容轉(zhuǎn)換為高質(zhì)量的PDF文檔而設(shè)計(jì)。它以其出色的HTML和CSS兼容性、靈活的配置選項(xiàng)以及易于集成的特點(diǎn)而廣泛的認(rèn)可和應(yīng)用。