- 制作模板
- 引入依赖
- 引入所需字体文件
- 工具类的编写
- 业务实现
一、模板制作
(1)编写html代码 ,需要替换的值与内容预留出来,用${name}代替,需循环处.表格前加上<#list listKey as t> ${t.name}
(2)将写好的html文件用文本打开,复制代码,用xml格式工具格式一下。最后将html文件后缀改为.ftl
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>PDF导出</title>
<style type="text/css">
*{
box-sizing: border-box;
}
body{
font-family: SimSun;
}
.content {
width: 100%;
height: 100%;
text-align: center;
font-size: 16px;
}
.contentHeader {
height: 60px;
line-height: 60px;
font-size: 30px;
}
.title {
width: 100%;
height: 25px;
line-height: 25px;
}
.titleLeft {
padding-left: 20px;
float: left;
}
.titleRight {
padding-right: 20px;
float: right;
}
table {
width: 98%;
height: 100%;
border-collapse: collapse;
text-align: center;
font-size: 16px;
margin: 0 2%;
}
td {
padding: 8px;
}
.tdOne {
width: 120px;
}
.footerTable {
width: 98%;
height: 100%;
border-collapse: collapse;
text-align: center;
font-size: 16px;
}
.footerTd{
border-bottom: 1px solid transparent;
}
</style>
</head>
<body>
<div class='content'>
<div class='contentHeader'>设备任务单</div>
<div class='title'>
<span class='titleLeft'>所属组织: ${pkcompany}</span>
<span class='titleRight'>打印人:${psnname}</span>
</div>
<table border="1">
<tr>
<td class='tdOne'>标题</td>
<td class='tdTwo'>${contractno}设备任务单</td>
<td class='tdOne'>流水号</td>
<td class='tdTwo'>${pk_equtask}</td>
</tr>
<tr>
<td class='tdOne'>提交人</td>
<td class='tdTwo'>${creatorname}</td>
<td class='tdOne'>所属部门</td>
<td class='tdTwo'>${creatordepname}</td>
</tr>
<tr>
<td class='tdOne'>申请日期</td>
<td class='tdTwo'>${createdate}</td>
<td class='tdOne'>生产代码</td>
<td class='tdTwo'>${shengchandaima}</td>
</tr>
<tr>
<td class='tdOne'>合同号</td>
<td class='tdTwo'>${contractno}</td>
<td class='tdOne'>制号</td>
<td class='tdTwo'>${zhihao}</td>
</tr>
<tr>
<td class='tdOne'>客户所在地</td>
<td class='tdTwo'>${cusaddress}</td>
<td class='tdOne'>数量</td>
<td class='tdTwo'>1.0</td>
</tr>
<tr>
<td class='tdOne'>内部型号</td>
<td class='tdTwo'>${equxinghao_task}</td>
<td class='tdOne'>内部设备名称</td>
<td class='tdTwo'>${equname_task}</td>
</tr>
<tr>
<td class='tdOne'>合同型号</td>
<td class='tdTwo'>${innerEquxinghao}</td>
<td class='tdOne'>合同设备名称</td>
<td class='tdTwo'>${innerEquname}</td>
</tr>
<tr>
<td class='tdOne'>开始日期~要求交货时间</td>
<td class='tdTwo' colspan="3">${begindate}~${jiaohuodate}</td>
</tr>
<tr>
<td class='tdOne'>操作画面语言</td>
<td class='tdTwo'>${caozuoxitong}</td>
<td class='tdOne'>电气图纸语言</td>
<td class='tdTwo'>${def1}</td>
</tr>
<tr>
<td class='tdOne'>说明书语言</td>
<td class='tdTwo'>${def2}</td>
<td class='tdOne'>设备标识、标牌语言</td>
<td class='tdTwo'>${def3}</td>
</tr>
<tr>
<td class='tdOne'>电压要求</td>
<td class='tdTwo'>${dianya}</td>
<td class='tdOne'>CE认证</td>
<td class='tdTwo'>${cerenzheng}</td>
</tr>
<tr>
<td class='tdOne'>技术要求</td>
<td class='tdTwo'>${jishuyaoqiu}</td>
<td class='tdOne'>客户环境(温度)说明</td>
<td class='tdTwo'>${kehuhuanjing}</td>
</tr>
<tr>
<td class='tdOne'>所属制造部</td>
<td class='tdTwo'>${makedept}</td>
<td class='tdOne'>所属技术组</td>
<td class='tdTwo'>${tecdept}</td>
</tr>
<tr>
<td class='tdOne'>合同负责人</td>
<td class='tdTwo'>${salername}</td>
<td class='tdOne'>紧急程度</td>
<td class='tdTwo'>${jinjichengdu}</td>
</tr>
<tr>
<td colspan="4" class='footerTd'>审批记录</td>
</tr>
</table>
<table border="1" class='footerTable'>
<tr>
<td>节点名称</td>
<td>审批操作</td>
<td>审批意见</td>
<td>审批人</td>
<td>审批时间</td>
</tr>
<#list listKey as t>
<tr>
<td>${t.taskdefname}</td>
<td>${t.approveresult}</td>
<td>${t.approvecontentvalue}</td>
<td>${t.noticename}</td>
<td>${t.approvedatevalue}</td>
</tr>
</#list>
</table>
</div>
</body>
</html>
二、所需pom依赖
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.23</version>
</dependency>
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf</artifactId>
<version>9.0.9</version>
</dependency>
三、引入字体所需文件,我的放在resources下新建一个template ===》font目录下 simsun.ttc
四、实体类
没啥说的,自己去改路径,debug走一下,需要图片就放开注释的代码
```java
package com.tjk.tjkcom.util;
import com.lowagie.text.pdf.BaseFont;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.xhtmlrenderer.pdf.ITextRenderer;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.StringWriter;
import java.util.Locale;
import java.util.Map;
public class PDFTemplateUtil {
/**
* 通过模板导出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(PDFTemplateUtil.class,"/mailtemplate");
ITextRenderer renderer = new ITextRenderer();
OutputStream out = new ByteArrayOutputStream();
try {
// 设置 css中 的字体样式(暂时仅支持宋体和黑体) 必须,不然中文不显示
renderer.getFontResolver().addFont("/mailtemplate/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路径需要相对路径加图片名 如
// String url = PDFTemplateUtil.class.getClassLoader().getResource("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();
}
}
}
}
五、业务实现
(1)写你的代码,controller -service -serviceimpl - mapper
package com.example.demo.controller;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/pdf")
public class PdfController {
@RequestMapping("/export")
public void exportPdf(HttpServletResponse response) throws Exception{
ByteArrayOutputStream baos = null;
OutputStream out = null;
try {
// 模板中的数据,实际运用从数据库中查询
------------------------------------
------------------------------------
------------------------------------
baos = PDFTemplateUtil.createPDF(resultMap, "Test.ftl");
// 设置响应消息头,告诉浏览器当前响应是一个下载文件
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
response.setCharacterEncoding("utf-8");
response.setContentType("application/x-msdownload");
// 告诉浏览器,当前响应数据要求用户干预保存到文件中,以及文件名是什么 如果文件名有中文,必须URL编码
String fileName = URLEncoder.encode("设备任务单:"+hashMap.get("contractno").toString()+".pdf", "UTF-8");
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
/*response.setHeader("Content-Disposition", "attachment;filename=".concat(String.valueOf(URLEncoder.encode(fileName, "UTF-8"))));*/
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();
}
}
}
}
六、最后建议,前后分离,如果调不通,看看前端代码,console.log(error) 多输出日志,debug跟踪一下