根据 FreeMarker 模板导出 PDF 文件
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf-openpdf</artifactId>
<version>${flying-saucer.version}</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>${freemarker.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
- MacOS Mojave: “字体册” 中寻找合适字体(/System/Library/Fonts)
- Windows 10: “设置-个性化-字体” 中寻找合适字体(C:/Windows/Fonts)
- 在互联网上寻找合适字体(免费商业字体)
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Map;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.ui.freemarker.SpringTemplateLoader;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;
import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.BaseFont;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class PDFUtil {
private static Configuration cfg = null;
public static void exportPDF(String html, String pdf, String... fonts) throws DocumentException, IOException, TemplateException {
ITextRenderer renderer = new ITextRenderer();
addFont(renderer, fonts);
try (OutputStream os = new FileOutputStream(pdf)) {
renderer.setDocumentFromString(html);
renderer.layout();
renderer.createPDF(os);
}
}
public static String parseFreemarker(String freemarker, Map<String, Object> dataModel) throws IOException, TemplateException {
if (cfg == null) {
cfg = initConfiguration();
}
Template temp = cfg.getTemplate(freemarker);
try (Writer out = new StringWriter()) {
temp.process(dataModel, out);
return out.toString();
}
}
private static void addFont(ITextRenderer renderer, String... fonts) throws DocumentException, IOException {
ITextFontResolver fontResolver = renderer.getFontResolver();
for (String font : fonts) {
fontResolver.addFont(font, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
}
}
private static Configuration initConfiguration() throws IOException {
Configuration cfg = new Configuration(Configuration.VERSION_2_3_27);
cfg.setTemplateLoader(new SpringTemplateLoader(new DefaultResourceLoader(), "classpath:/templates/"));
cfg.setDefaultEncoding("UTF-8");
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
cfg.setLogTemplateExceptions(false);
cfg.setWrapUncheckedExceptions(true);
return cfg;
}
}
- 准备模板(
classpath:/templates/template.ftl
)
<!DOCTYPE html>
<html>
<head>
<link href="https://cdn.bootcss.com/twitter-bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet"></link>
<style type="text/css">
body {
font-family: 'Microsoft YaHei';
}
@page {
size: A4;
}
.pdf {
max-width: 680px!important;
}
.container {
margin-left: 0;
}
</style>
</head>
<body class="pdf">
<div class="container pdf">
<h1 class="pdf">根据 FreeMarker 模板导出 PDF 文件(基于 Spring Boot)</h1>
<h2 class="pdf">作者:${author}</h2>
<hr></hr>
<h3 class="pdf">测试换行1测试换行2测试换行3测试换行4测试换行5测试换行6测试换行7测试换行测试换行9测试换行10测试换行11测试换行12测试换行</h3>
<p class="pdf">
<img src="https://avatar.csdn.net/6/1/D/3_sai_simon.jpg"></img>
<br></br>
<a href="${url}">文章地址</a>
</p>
<div class="pdf">空 格</div>
</div>
</body>
</html>
public static void main(String[] args) throws IOException, TemplateException {
Map<String, Object> dataModel = new HashMap<>();
dataModel.put("author", "Saisimon");
dataModel.put("url", "https://blog.csdn.net/sai_simon/article/details/98898380");
String content = PDFUtil.parseFreemarker("template.ftl", dataModel);
String pdf = System.getProperty("user.home") + File.separator + "freemarker.pdf";
String font = System.getProperty("user.home") + File.separator + "fonts" + File.separator + "msyh.ttf";
PDFUtil.exportPDF(content, pdf, font);
}
- FreeMarker 模板中的 HTML 标签必须严格按照 XML 的标准,每个标签必须有结束标签。
<img></img>
、<link></link>
、<br></br>
、<hr></hr>
、<input></input>
- 加载的字体需要与样式中的
font-family
对应,否则中文不会显示
- 导出效果