org.xhtmlrenderer
flying-saucer-pdf
9.1.18
2. 工具类
import java.io.*;
import java.util.Locale;
import java.util.Map;
import org.xhtmlrenderer.pdf.ITextRenderer;
import com.lowagie.text.pdf.BaseFont;
import freemarker.template.Configuration;
import freemarker.template.Template;
public class PdfUtil {
* 通过模板导出pdf文件
* @param data 数据
* @param templateFileName 模板文件名
* @throws Exception
public static ByteArrayOutputStream createPDF(Map<String,Object> data, String templateFileName) throws Exception {
// 创建一个FreeMarker实例, 负责管理FreeMarker模板的Configuration实例
Configuration cfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
// 指定FreeMarker模板文件的位置
cfg.setClassForTemplateLoading(PdfUtil.class,"/templates");
ITextRenderer renderer = new ITextRenderer();
OutputStream out = new ByteArrayOutputStream();
try {
// 设置 css中 的字体样式(暂时仅支持宋体和黑体) 必须,不然中文不显示
renderer.getFontResolver().addFont("/static/font/SIMSUN.TTC", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
// 设置模板的编码格式
cfg.setEncoding(Locale.CHINA, "UTF-8");
// 获取模板文件
Template template = cfg.getTemplate(templateFileName, "UTF-8");
StringWriter writer = new StringWriter();
// 将数据输出到html中
template.process(data, writer);
writer.flush();
String html = writer.toString();
// 把html代码传入渲染器中
renderer.setDocumentFromString(html);
// 设置模板中的图片路径 (这里的images在resources目录下) 模板中img标签src路径需要相对路径加图片名 如<img src="images/xh.jpg"/>
String url = PdfUtil.class.getClassLoader().getResource("static/images").toURI().toString();
renderer.getSharedContext().setBaseURL(url);
renderer.layout();
renderer.createPDF(out, false);
renderer.finishPDF();
out.flush();
return (ByteArrayOutputStream)out;
} finally {
if(out != null){
out.close();
代码中需要注意路径设置,否则会导致css和图片引入无效
cfg.setClassForTemplateLoading(PdfUtil.class,"/templates");
指定FreeMarker模板文件的位置
renderer.getFontResolver().addFont("/static/font/SIMSUN.TTC", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
指定字体文件,否则中文不显示
PdfUtil.class.getClassLoader().getResource("static/images").toURI().toString();
指定模板中图片路径
宋体字体下载: https://dl.pconline.com.cn/download/367689-1.html
静态资源目录结构:
3. 使用
建议使用时,先写一个html静态页面,调试好了再复制到ftl文件中,保存成模板
静态index.html
<!DOCTYPE html>
<meta charset="utf-8"/>
<title></title>
<style>
.center{
width: 380px;
height: 538px;
background: url("images/zs.png") center no-repeat;
margin: 10% auto;
font-family: SimSun;
position: relative;
.name{
position: absolute;
top: 216px;
left: 60px;
font-size: 20px;
width: 74px;
text-align: center;
display: block;
</style>
</head>
<div class="center">
<span class="name">李逍遥</span>
</body>
</html>
模板zhengshu.ftl
<!DOCTYPE html>
<meta charset="utf-8"/>
<title></title>
<style>
.center{
width: 380px;
height: 538px;
background: url("images/zs.png") center no-repeat;
margin: 15% auto;
font-family: SimSun;
position: relative;
.name{
position: absolute;
top: 216px;
left: 60px;
font-size: 20px;
width: 74px;
text-align: center;
display: block;
</style>
</head>
<div class="center">
<span class="name">${name}</span>
</body>
</html>
把需要设置数据的地方,用freemarker语法进行占位${}
@Test
public void pdf() throws IOException {
ByteArrayOutputStream baos = null;
FileOutputStream out = null;
try {
Map<String,Object> data = new HashMap<>();
data.put("name", "李逍遥");
baos = PdfUtil.createPDF(data, "zhengshu.ftl");
String fileName = "获奖证书.pdf";
File file = new File(fileName);
out = new FileOutputStream(file);
baos.writeTo(out);
} catch (Exception e) {
e.printStackTrace();
} finally {
if(baos!=null){
baos.close();
if(out != null){
out.close();
使用controller
mport java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/pdf")
public class PdfController {
@RequestMapping("/export")
public void exportPdf(HttpServletResponse response) throws Exception{
ByteArrayOutputStream baos = null;
OutputStream out = null;
try {
// 模板中的数据,实际运用从数据库中查询
Map<String,Object> data = new HashMap<>();
data.put("name", "李逍遥");
baos = PdfUtil.createPDF(data, "zhengshu.ftl");;
// 设置响应消息头,告诉浏览器当前响应是一个下载文件
response.setContentType( "application/x-msdownload");
// 告诉浏览器,当前响应数据要求用户干预保存到文件中,以及文件名是什么 如果文件名有中文,必须URL编码
String fileName = URLEncoder.encode("获奖证书.pdf", "UTF-8");
response.setHeader( "Content-Disposition", "attachment;filename=" + fileName);
out = response.getOutputStream();
baos.writeTo(out);
baos.close();
} catch (Exception e) {
e.printStackTrace();
throw new Exception("导出失败:" + e.getMessage());
} finally{
if(baos != null){
baos.close();
if(out != null){
out.close();
4. 横向打印
有时网页比较宽时,生成的pdf宽度不够,导致显示内容不完整,可以通过在模板css设置@page
控制
/*设置页面宽高 A4大小*/
@page{size:297mm 210mm;}
https://blog.csdn.net/weixin_39806100/article/details/86616041
https://www.iteye.com/problems/64595