一、导出工具类
传入参数为需要渲染的数据,以及模板的位置。
需要准备好字体文件,同项目一起打包。可以在”控制面板\外观和个性化\字体“中找到想要的字体
其中工具类传入的参数示例为:
List<QuestionExportVO> questionExportVOList = new ArrayList<>();
Map<String, Object> data = new HashMap<>();
data.put("questionExportVOList", questionExportVOList);
baos = PDFTemplateUtil.createPDF(data, "QuestionReplyDetails.ftl");
public class PDFTemplateUtil {
/**
* 通过模板导出pdf文件
*
* @param data 数据
* @throws Exception
*/
public static ByteArrayOutputStream createPDF(Object data, String templateName) throws Exception {
// 创建一个FreeMarker实例, 负责管理FreeMarker模板的Configuration实例
Configuration cfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
// 指定FreeMarker模板文件的位置
cfg.setClassForTemplateLoading(PDFTemplateUtil.class, "/templates");
ITextRenderer renderer = new ITextRenderer();
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
// 设置 css中 的字体样式(暂时仅支持宋体和黑体) 必须,不然中文不显示
renderer.getFontResolver().addFont("/templates/font/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
renderer.getFontResolver().addFont("/templates/font/calibrib.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
// 设置模板的编码格式
cfg.setEncoding(Locale.CHINA, "UTF-8");
// 获取模板文件
Template template = cfg.getTemplate(templateName, "UTF-8");
StringWriter writer = new StringWriter();
// 将数据输出到html中
template.process(data, writer);
writer.flush();
String html = writer.toString();
// 把html代码传入渲染器中
renderer.setDocumentFromString(html);
renderer.layout();
renderer.createPDF(out, false);
renderer.finishPDF();
out.flush();
return out;
}
}
}
二、配置模板
根据需求画出想要的界面,注意并不是html,而是ftl格式(可以先画一个html,画出想要的格式后,再改造成ftl)。
其中有很多ftl格式才有的标签,用于实现数据渲染。可以做到动态增加表格,比如:
<#list detail.images as image>
<#if image ??>
<img style="width: 99%;padding-left: 2px;padding-top: 2px;" src="${image}" alt="image"/>
</#if>
</#list>
<#list detail.images as image>代表在集合中循环操作,??代表如果对象存在(不为null)的话
${(child.conclusion)!''}
则代表如果为null的时候,则用空字符串作为默认输出值
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title></title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: SimSun;
padding: 30px 20px 0;
}
section {
display: block;
}
.preface p {
line-height: 30px;
display: inline-block;
}
section > table {
page-break-inside: auto;
-fs-table-paginate: paginate;
border-spacing: 0;
cellspacing: 0;
cellpadding: 0;
border-collapse: collapse;
table-layout: fixed;
width: 100%;
font-size: 13px;
text-align: left;
word-wrap: break-word;
}
section table td {
padding: 5px 0;
}
section table tr {
page-break-inside: avoid;
page-break-after: auto;
}
.topTitle section {
width: 30%;
font-size: 13px;
display: inline-block;
margin-top: 20px;
}
.outTitle section {
font-size: 13px;
display: inline-block;
}
.detail {
margin-top: 20px;
}
.box3 img {
width: 100%;
}
.box3 p {
font-size: 12px;
}
img {
width: 50%;
}
</style>
</head>
<body>
<#if questionExportVOList ??>
<section class="detail">
<table border="1" cellspacing="0" cellpadding="0">
<#list questionExportVOList as data>
<tr style="font-weight: bold;font-size: 14px;text-align: center;">
<td colspan="2" width="100%">问题归属成果:${(data.stageOutcomeName)!''}</td>
</tr>
<#list data.questionDetails as detail>
<tr>
<td colspan="2" width="100%" style="font-family: Calibri;font-weight: bold;font-size: 12px;background-color:yellow;"> ${(detail.serialNumber)!''}</td>
</tr>
<tr>
<th rowspan="7">
<#list detail.images as image>
<#if image ??>
<img style="width: 99%;padding-left: 2px;padding-top: 2px;" src="${image}" alt="image"/>
</#if>
</#list>
</th>
<td><b style="font-size: 12px;">问题所属图纸或模型:</b>${(detail.fileName)!''}</td>
</tr>
<tr>
<td><b style="font-size: 12px;">问题标题:</b>${(detail.questionTitle)!''}</td>
</tr>
<tr>
<td><b style="font-size: 12px;">问题描述:</b>${(detail.questionDesc)!''}</td>
</tr>
<tr>
<td>专业:${(detail.major)!''}</td>
</tr>
<tr>
<td>知悉人员:${(detail.knowingStaff)!''}</td>
</tr>
<tr>
<td>主责人员:${(detail.participants)!''}</td>
</tr>
<tr>
<td>上传附件:${(detail.attachmentName)!''}</td>
</tr>
<#if detail.children ??>
<#list detail.children as child>
<tr style="font-weight: bold;font-size: 12px;">
<td colspan="2" width="100%">${(child.operate)!''}</td>
</tr>
<#if child.conclusion ??>
<tr>
<td>复核人员:${(child.createBy)!''}</td>
<#if child.conclusion == "同意">
<td>复核结论:<b style="color: green;">${(child.conclusion)!''}</b></td>
<#else >
<td>复核结论:<b style="color: red;">${(child.conclusion)!''}</b></td>
</#if>
</tr>
<#else >
<tr>
<td colspan="2" width="100%">回复人员:${(child.createBy)!''}</td>
</tr>
</#if>
<#if child.replyContent ??>
<tr>
<td colspan="2" width="100%">${(child.replyContent)!''}</td>
</tr>
</#if>
</#list>
</#if>
</#list>
</#list>
</table>
</section>
</#if>
</body>
</html>