安装转化工具
本演示是在windows11上进行的
通过网盘分享的文件:wkhtmltopdf.zip
链接: https://pan.baidu.com/s/1RX6biSPAXZxuP9J01lLGTA?pwd=tawt 提取码: tawt
配置环境变量

引入依赖
java
<dependency>
<groupId>com.openhtmltopdf</groupId>
<artifactId>openhtmltopdf-core</artifactId>
<version>1.0.10</version>
</dependency>
<!-- PDFBox 后端(必须) -->
<dependency>
<groupId>com.openhtmltopdf</groupId>
<artifactId>openhtmltopdf-pdfbox</artifactId>
<version>1.0.10</version>
</dependency>
编写工具类
java
package org.dromara.pdfScriptPlugs.utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.codec.binary.Base64;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;
/**
*
*/
@Slf4j
public class HtmlToPdfUtils {
public static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
/**
* html转化为pdf文件
*
* @param htmlContent
* @return String base64编码的文件
* @throws IOException
*/
public static String convertHtmlToPdfBase64(String htmlContent) throws IOException {
LocalDateTime start = LocalDateTime.now();
Process process = null;
try {
long t0 = System.currentTimeMillis();
ProcessBuilder pb = new ProcessBuilder("wkhtmltopdf", "--encoding", "utf-8", "-", "-");
// 建议显式设置工作目录或环境变量,避免某些机器上找不到字体/配置时变慢
// pb.directory(new File("/tmp"));
process = pb.start();
long t1 = System.currentTimeMillis();
// 1. 异步消费 stderr,避免缓冲区写满阻塞
final InputStream errorStream = process.getErrorStream();
Thread stderrGobbler = new Thread(() -> {
try (InputStream es = errorStream) {
byte[] buf = new byte[4096];
while (es.read(buf) != -1) {
// String s = new String(buf, 0, len, StandardCharsets.UTF_8);
// log.debug("wkhtmltopdf stderr: {}", s);
}
} catch (IOException e) {
log.warn("Error reading wkhtmltopdf stderr", e);
}
}, "wkhtmltopdf-stderr-gobbler");
stderrGobbler.setDaemon(true);
stderrGobbler.start();
// 2. 写入 HTML 到 stdin
try (OutputStream stdin = process.getOutputStream()) {
byte[] data = htmlContent.getBytes(StandardCharsets.UTF_8);
stdin.write(data);
stdin.flush();
}
long t2 = System.currentTimeMillis();
// 3. 读取 stdout 中的 PDF
try (InputStream inputStream = process.getInputStream();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(32 * 1024)) {
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
long t3 = System.currentTimeMillis();
// 4. 等待进程结束并检查退出码(带超时)
boolean finished = process.waitFor(30, TimeUnit.SECONDS);
if (!finished) {
process.destroyForcibly();
throw new RuntimeException("wkhtmltopdf 转换超时(>30s)");
}
String base64 = Base64.encodeBase64String(outputStream.toByteArray());
long t4 = System.currentTimeMillis();
log.info("convertHtmlToPdfBase64 success, total cost={} ms", (t4 - t0));
return base64;
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("wkhtmltopdf 转换被中断");
} catch (IOException e) {
throw new RuntimeException("html转pdf异常: " + e.getMessage());
} finally {
if (process != null && process.isAlive()) {
process.destroy();
}
log.info("convertHtmlToPdfBase64 end: {}", LocalDateTime.now().format(formatter));
}
}
public static byte[] core(String htmlContent) throws IOException {
LocalDateTime start = LocalDateTime.now();
Process process = null;
long t0 = System.currentTimeMillis();
ProcessBuilder pb = new ProcessBuilder("wkhtmltopdf", "--encoding", "utf-8", "-", "-");
process = pb.start();
long t1 = System.currentTimeMillis();
final InputStream errorStream = process.getErrorStream();
Thread stderrGobbler = new Thread(() -> {
try (InputStream es = errorStream) {
byte[] buf = new byte[4096];
while (es.read(buf) != -1) {
}
} catch (IOException e) {
log.warn("Error reading wkhtmltopdf stderr", e);
}
}, "wkhtmltopdf-stderr-gobbler");
stderrGobbler.setDaemon(true);
stderrGobbler.start();
// 2. 写入 HTML 到 stdin
try (OutputStream stdin = process.getOutputStream()) {
byte[] data = htmlContent.getBytes(StandardCharsets.UTF_8);
stdin.write(data);
stdin.flush();
}
long t2 = System.currentTimeMillis();
// 3. 读取 stdout 中的 PDF
try (InputStream inputStream = process.getInputStream();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(32 * 1024)) {
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
long t3 = System.currentTimeMillis();
// 4. 等待进程结束
boolean finished = process.waitFor(30, TimeUnit.SECONDS);
if (!finished) {
process.destroyForcibly();
throw new RuntimeException("wkhtmltopdf 转换超时(>30s)");
}
return outputStream.toByteArray();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("wkhtmltopdf 转换被中断");
} catch (IOException e) {
throw new RuntimeException("html转pdf异常: " + e.getMessage());
} finally {
if (process != null && process.isAlive()) {
process.destroy();
}
log.info("convertHtmlToPdfBase64 end: {}", LocalDateTime.now().format(formatter));
}
}
}
测试转化效果
java
import org.dromara.pdfScriptPlugs.utils.HtmlToPdfUtils;
import java.io.IOException;
/**
* @Author: zhouhai
* @Date: 2026/01/09
*/
public class Test {
public static void main(String[] args) {
try {
String htmlContent = "<html><body><h1>Hello, World!</h1></body></html>";
System.out.println( HtmlToPdfUtils.convertHtmlToPdfBase64(htmlContent));
} catch (IOException e) {
}
}
}
效果
base64
23:07:49.471 [main] INFO org.dromara.pdfScriptPlugs.utils.HtmlToPdfUtils -- convertHtmlToPdfBase64 success, total cost=1298 ms
23:07:49.475 [main] INFO org.dromara.pdfScriptPlugs.utils.HtmlToPdfUtils -- convertHtmlToPdfBase64 end: 2026-01-09 23:07:49.475
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Ge/D3P6/qlTzW3IKhP8qo39szeUdF5Habx/nWsKeehN/C9p/TzX3CnZWA7s078X7R2ivPZVR29/fKm5Hj+N+x4xjznHKcdpxznGf44LjzH4S7rDn4/7KVua8wNCQxvHZ9e57ypwX8NzJQ8T397SCV2om/2zvg5V99pT4QuLpbP+IlDkJ+V/muTIZCmVuZHN0cmVhbQplbmRvYmoKMjAgMCBvYmoKNDgzOQplbmRvYmoKMTggMCBvYmoKPDwgL1R5cGUgL0ZvbnQKL1N1YnR5cGUgL0NJREZvbnRUeXBlMgovQmFzZUZvbnQgL1RpbWVzTmV3Um9tYW5Cb2xkCi9DSURTeXN0ZW1JbmZvIDw8IC9SZWdpc3RyeSAoQWRvYmUpIC9PcmRlcmluZyAoSWRlbnRpdHkpIC9TdXBwbGVtZW50IDAgPj4KL0ZvbnREZXNjcmlwdG9yIDE2IDAgUgovQ0lEVG9HSURNYXAgL0lkZW50aXR5Ci9XIFswIFs2OTcgNjk3IDM5OCAyNDkgNDQ4IDIyNCAyMjQgODk2IDM5OCA0OTggMjk4IF0KXQo+PgplbmRvYmoKMTkgMCBvYmoKPDwgL0xlbmd0aCA0MzQgPj4Kc3RyZWFtCi9DSURJbml0IC9Qcm9jU2V0IGZpbmRyZXNvdXJjZSBiZWdpbgoxMiBkaWN0IGJlZ2luCmJlZ2luY21hcAovQ0lEU3lzdGVtSW5mbyA8PCAvUmVnaXN0cnkgKEFkb2JlKSAvT3JkZXJpbmcgKFVDUykgL1N1cHBsZW1lbnQgMCA+PiBkZWYKL0NNYXBOYW1lIC9BZG9iZS1JZGVudGl0eS1VQ1MgZGVmCi9DTWFwVHlwZSAyIGRlZgoxIGJlZ2luY29kZXNwYWNlcmFuZ2UKPDAwMDA+IDxGRkZGPgplbmRjb2Rlc3BhY2VyYW5nZQoyIGJlZ2luYmZyYW5nZQo8MDAwMD4gPDAwMDA+IDwwMDAwPgo8MDAwMT4gPDAwMEE+IFs8MDA0OD4gPDAwNjU+IDwwMDZDPiA8MDA2Rj4gPDAwMkM+IDwwMDIwPiA8MDA1Nz4gPDAwNzI+IDwwMDY0PiA8MDAyMT4gXQplbmRiZnJhbmdlCmVuZGNtYXAKQ01hcE5hbWUgY3VycmVudGRpY3QgL0NNYXAgZGVmaW5lcmVzb3VyY2UgcG9wCmVuZAplbmQKCmVuZHN0cmVhbQplbmRvYmoKNiAwIG9iago8PCAvVHlwZSAvRm9udAovU3VidHlwZSAvVHlwZTAKL0Jhc2VGb250IC9UaW1lc05ld1JvbWFuQm9sZAovRW5jb2RpbmcgL0lkZW50aXR5LUgKL0Rlc2NlbmRhbnRGb250cyBbMTggMCBSXQovVG9Vbmljb2RlIDE5IDAgUj4+CmVuZG9iagoyIDAgb2JqCjw8Ci9UeXBlIC9QYWdlcwovS2lkcyAKWwo1IDAgUgpdCi9Db3VudCAxCi9Qcm9jU2V0IFsvUERGIC9UZXh0IC9JbWFnZUIgL0ltYWdlQ10KPj4KZW5kb2JqCnhyZWYKMCAyMQowMDAwMDAwMDAwIDY1NTM1IGYgCjAwMDAwMDAwMDkgMDAwMDAgbiAKMDAwMDAwNzM2NyAwMDAwMCBuIAowMDAwMDAwMTYzIDAwMDAwIG4gCjAwMDAwMDAyNTggMDAwMDAgbiAKMDAwMDAwMDY1MSAwMDAwMCBuIAowMDAwMDA3MjI0IDAwMDAwIG4gCjAwMDAwMDAyOTUgMDAwMDAgbiAKMDAwMDAwMDMzOCAwMDAwMCBuIAowMDAwMDAwNDg3IDAwMDAwIG4gCjAwMDAwMDAzNzkgMDAwMDAgbiAKMDAwMDAwMDU0OSAwMDAwMCBuIAowMDAwMDAwOTU4IDAwMDAwIG4gCjAwMDAwMDEyNDcgMDAwMDAgbiAKMDAwMDAwMDc3MiAwMDAwMCBuIAowMDAwMDAwOTM4IDAwMDAwIG4gCjAwMDAwMDEyNjcgMDAwMDAgbiAKMDAwMDAwMTUyNSAwMDAwMCBuIAowMDAwMDA2NDc3IDAwMDAwIG4gCjAwMDAwMDY3MzggMDAwMDAgbiAKMDAwMDAwNjQ1NiAwMDAwMCBuIAp0cmFpbGVyCjw8Ci9TaXplIDIxCi9JbmZvIDEgMCBSCi9Sb290IDExIDAgUgo+PgpzdGFydHhyZWYKNzQ2NQolJUVPRgo=