当我们遇到表格数据(类似于word中设计的表格)需要动态的填充数据,而这个数据是从数据库等地方作为对象获取的,这个时候我们需要使用特定的技术去实现动态数据填充以及html页面转换pdf的实现。当我们遇到类似的业务场景的时候,可以参考这篇文章去实现。
1.8
UTF-8
UTF-8
2.3.12.RELEASE
3.1.0
2.3.22
9.1.12
3.12.0
javax.servlet
javax.servlet-api
${servlet}
provided
org.freemarker
freemarker
${freemarker}
org.xhtmlrenderer
flying-saucer-pdf
${flying-saucer}
log4j
log4j
1.2.17
org.slf4j
slf4j-api
2.0.9
com.alibaba
fastjson
1.2.46
junit
junit
org.projectlombok
lombok
org.springframework.boot
spring-boot-dependencies
${spring-boot.version}
pom
import
主要是前三个依赖,剩余的依赖是对日志记录的使用,Freemarker依赖是Java中对模板和数据进行整合的使用,flying-saucer-pdf是针对pdf生成需要。
package com.xiaobai.common;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;
import java.util.Locale;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xhtmlrenderer.pdf.ITextRenderer;
import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.BaseFont;
import freemarker.core.ParseException;
import freemarker.template.Configuration;
import freemarker.template.MalformedTemplateNameException;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateNotFoundException;
/**
* Description: PDF生成工具类
* @author xiaobai
*/
@SuppressWarnings("all")
public class PDFUtil {
private static final Logger logger = LoggerFactory.getLogger(PDFUtil.class);
/**
* Description: 生成PDF到文件
* @param ftlPath 模板文件路径(不含文件名)
* @param ftlName 模板文件(不含路径)
* @param imageDiskPath 图片的磁盘路径
* @param data 数据 (填到模板上的数据)
* @param outputFile 目标文件(全路径名称)
* @throws Exception
*/
public static void generateToFile(String ftlPath, String ftlName, String imageDiskPath, Object data,String outputFile) throws Exception {
OutputStream out = null;
ITextRenderer render = null;
try {
String html = getPdfContent(ftlPath, ftlName, data); //组装模板和数据生成html串
out = new FileOutputStream(outputFile);
render = getRender();
render.setDocumentFromString(html); //此处抛异常
if (imageDiskPath != null && !imageDiskPath.equals("")) {
// html中如果有图片,图片的路径则使用这里设置的路径的相对路径,这个是作为根路径
render.getSharedContext().setBaseURL("file:/" + imageDiskPath);
}
render.layout();
render.createPDF(out);
render.finishPDF();
render = null;
} catch (Exception e) {
logger.error("Exception:",e);
throw e;
}finally{
if (out != null) {
try {
out.close();
} catch (IOException e) {
logger.error("Exception:",e);
throw e;
}
}
}
}
/**
* 生成PDF到输出流中(ServletOutputStream用于下载PDF)
*
* @param ftlPath
* ftl模板文件的路径(不含文件名)
* @param ftlName
* ftl模板文件的名称(不含路径)
* @param imageDiskPath
* 如果PDF中要求图片,那么需要传入图片所在位置的磁盘路径
* @param data
* 输入到FTL中的数据
* @param response
* HttpServletResponse
* @return
* @throws TemplateNotFoundException
* @throws MalformedTemplateNameException
* @throws ParseException
* @throws IOException
* @throws TemplateException
* @throws DocumentException
*/
public static OutputStream generateToServletOutputStream(String ftlPath, String ftlName, String imageDiskPath,
Object data, HttpServletResponse response) throws Exception {
String html = getPdfContent(ftlPath, ftlName, data);
OutputStream out = null;
ITextRenderer render = null;
out = response.getOutputStream();
render = getRender();
render.setDocumentFromString(html);
if (imageDiskPath != null && !imageDiskPath.equals("")) {
// html中如果有图片,图片的路径则使用这里设置的路径的相对路径,这个是作为根路径
render.getSharedContext().setBaseURL("file:/" + imageDiskPath);
}
render.layout();
render.createPDF(out);
render.finishPDF();
render = null;
return out;
}
public static ITextRenderer getRender() throws DocumentException, IOException {
ITextRenderer render = new ITextRenderer();
String path = getPath();
// 添加字体,以支持中文
render.getFontResolver().addFont(path + "fonts/ARIALUNI.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
render.getFontResolver().addFont(path + "fonts/SIMSUN.TTC", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
return render;
}
// 获取要写入PDF的内容
public static String getPdfContent(String ftlPath, String ftlName, Object o) throws Exception {
return useTemplate(ftlPath, ftlName, o);
}
// 使用freemarker得到html内容
public static String useTemplate(String ftlPath, String ftlName, Object o) throws Exception {
String html = null;
Template tpl = getFreemarkerConfig(ftlPath).getTemplate(ftlName);
tpl.setEncoding("UTF-8");
StringWriter writer = new StringWriter();
tpl.process(o, writer);
writer.flush();
html = writer.toString();
return html;
}
/**
* 获取Freemarker配置
*
* @param templatePath
* @return
* @throws IOException
*/
private static Configuration getFreemarkerConfig(String templatePath) throws IOException {
Configuration config = new Configuration();
config.setDirectoryForTemplateLoading(new File(templatePath));
config.setEncoding(Locale.CHINA, "utf-8");
return config;
}
/**
* 获取类项目根路径
*/
public static String getPath() {
//return PDFUtil.class.getResource("").getPath().substring(1); //返回类路径(当前类所在的路径)
return PDFUtil.class.getResource("/").getPath().substring(1); //返回项目根路径(编译之后的根路径)
}
}
文档标题
文档标题
提示:警惕洗钱风险,保护您的权益
账 户 信 息 1
存款人名称
${data.remark1}
办公地址
<#if data.remark2 == "01">
或 省/区/直辖市 市 区/县
<#else>
或 ${data.remark3}省/区/直辖市${data.remark4}市 ${data.remark5} 区/县 ${data.remark6}
#if>
邮寄地址
<#if data.remark7 == "01">
或 1. 2. 省/区/直辖市 市 区/县
<#elseif data.remark7 == "02">
或 1. 2. 省/区/直辖市 市 区/县
<#else>
或 1. 2.${data.remark8}省/区/直辖市${data.remark9}市 ${data.remark10} 区/县 ${data.remark11}
#if>
联系信息
<#if data.remark12 == "01">
或
<#else>
或
#if>
办公电话:区号${data.remark13}直线${data.remark14}分机${data.remark15}
移动电话:${data.remark16}
财务负责人
姓名:${data.remark17}办公电话:区 号${data.remark18}直线${data.remark19}分机${data.remark20}
移动电话:${data.remark21}电子邮箱:${data.remark22}
财务经办人员
姓名:${data.remark23}办公电话:区 号${data.remark24}直线${data.remark25}分机${data.remark26}
移动电话:${data.remark27}
账户种类
人民币
<#if data.remark28 == "01">
1.2.3.
或
4.5. 6.
<#elseif data.remark28 == "02">
1.2.3.
或
4.5. 6.
<#elseif data.remark28 == "03">
1.2.3.
<#if data.remark29 == "01">
或
<#elseif data.remark29 == "02">
或
<#else>
或 ${data.remark30}
#if>
4.5. 6.
<#elseif data.remark28 == "04">
1.2.3.
或
4.5. 6.
<#elseif data.remark28 == "05">
1.2.3.
或
4.5.${data.remark31}6.
<#else>
1.2.3.
或
4.5. 6.${data.remark32}
#if>
外 币
币种:
<#if data.remark33 == "01">
1.2.3.4.5.
<#elseif data.remark33 == "02">
1.2.3.4.5.
<#elseif data.remark33 == "03">
1.2.3.4.5.
<#elseif data.remark33 == "04">
1.2.3.4.5.
<#else>
1.2.3.4.5.${data.remark34}
#if>
种类:
<#if data.remark35 == "01">
1.2.3.4.
<#elseif data.remark35 == "02">
1.2.3.4.
<#elseif data.remark35 == "03">
1.2.3.4.
<#else>
1.2.3.4.${data.remark36}
#if>
账 户 信 息 2
控股股东或
实际控制人
名称:${data.remark37}
证件种类:
<#if data.remark38 == "01">
1.2.3.
<#elseif data.remark38 == "02">
1.2.3.
<#else>
1.2.3. ${data.remark39}
#if>
证件号码:${data.remark40}
证件到期日:
<#if data.remark41 == "01">
1.2. 年 月 日
<#else>
1.2.${data.remark42}年${data.remark43}月${data.remark44}日
#if>
税收居民身份
信息
机构类别:
<#if data.remark45 == "01">
1.2.其他非金融机构
<#else>
1.2.其他非金融机构
#if>
税收居民身份:
<#if data.remark46 == "01">
1.2.仅中国税收居民
<#else>
1.2.仅中国税收居民
#if>
注:属于“消极非金融机构”或“非居民或多重税收身份”的,需进一步提供税收居民声明文件及相关补充资料。
上级法人或主管单位
名称:${data.remark47}
注:申请单位如有上级法人或主管单位,需提供其证照资料及法定代表人/单位负责人身份证件资料。
网上/手机银行/橙e网服务
<#if data.remark48 == "01">
<#else>
#if>
<#if data.remark49 == "01">
<#else>
#if>
或
<#if data.remark50 == "01">
<#else>
#if>
<#if data.remark51 == "01">
<#else>
#if>
USBKEY购买数量:${data.remark52}个
其它增值服务
(可多选)
1.默认开通电话银行
<#if data.remark53 == "01">
2.${data.remark54}
<#if data.remark55??>
②${data.remark54}
<#if data.remark56??>
③${data.remark56};
<#else>
③ ;
#if>
<#else>
② ③ ;
#if>
<#else>
①
② ③ ;
#if>
<#else>
#if>
缴费方式为:
<#if data.remark57 == "01">
按年
<#elseif data.remark57 == "02">
按年
<#else>
按年
#if>
<#if data.remark58 == "01">
3.
<#else>
3.
#if>
<#if data.remark59 == "01">
4.
<#if data.remark60 == "01">
(支付密码器:
<#else>
(支付密码器:
#if>
<#else>
4.(支付密码器:
#if>
<#if data.remark61 == "01">
5.
<#else>
5.
#if>
意 见
xxxx审核意见
xxxx承诺及签章
xxxx审核意见
本单位因结算需要,申请在贵行开立账户,保证开户资料的真实、完整、合规。本单位已阅读、理解《平安银行单位账户管理协议》条款(后附),并同意按协议约定使用账户和办理业务。
法定代表人或其授权人签章:${data.remark62}
申请单位(公章)
${data.remark63}年${data.remark64}月${data.remark65}日
经办:${data.remark66}
主管:${data.remark67}
开户银行(签章)
${data.remark68}年${data.remark69}月${data.remark70}日
(非核准类账户除外)
经办人(签章):${data.remark71}
中国人民银行(签章)
${data.remark72}年${data.remark73}月${data.remark74}日
客户经理UM号:${data.remark75}
客户经理姓名:${data.remark76}
第
一
联
:
开
户
银
行
留
存
第
二
联
:
申
请
单
位
留
存
package com.zy.test;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import com.zy.common.templatebo.PDFTemplateBo;
import com.zy.common.utils.PDFUtil;
public class TestPDFUtil {
@Test
public void testGeneratePDF(){
String templateName = "template";//需要选用的模板名称
String targetPathRoot = "D:/temp/";//生成pdf的目标位置
Map map = generateUnitOpenAccountApplicationData();//构建模板所需数据
try {
String path = PDFUtil.getPath();
//System.out.println(path); //项目根路径
PDFUtil.generateToFile(path,"templates/" + templateName + ".ftl", path + "/images/", map, targetPathRoot + templateName + ".pdf");
System.out.println("生成PDF成功!");
} catch (Exception e) {
e.printStackTrace();
System.out.println("生成PDF失败!");
}
}
public Map generateUnitOpenAccountApplicationData() {
Mapmap = new HashMap();
PDFTemplateBo bo = new PDFTemplateBo();
bo.setRemark1("张三");//存款人名称
bo.setRemark2("02");//办公地址:01同注册地址,02其它 当此项值为02时要设置remark3、remark4、remark5、remark6的值
bo.setRemark3("xxx");//具体办公地址:省
bo.setRemark4("xxx");//具体办公地址:市
bo.setRemark5("xxx");//具体办公地址:区/县
bo.setRemark6("xxx");//具体办公地址:
bo.setRemark7("03");//邮寄地址:01同注册地址,02同办公地址,03其他 当此项值为03时要设置remark8、remark9、remark10、remark11的值
bo.setRemark8("xxx");//具体邮寄地址:省
bo.setRemark9("xxx");//具体邮寄地址:市
bo.setRemark10("xxx");//具体邮寄地址:区/县
bo.setRemark11("xxx");//具体邮寄地址:
bo.setRemark12("01");//联系信息:01法定代表人,02单位负责人
bo.setRemark13("027");//办公电话:区号
bo.setRemark14("88936");//办公电话:直线
bo.setRemark15("985635");//办公电话:分机
bo.setRemark16("13295684565");//办公电话:移动电话
bo.setRemark17("赖总");//财务负责人:姓名
bo.setRemark18("010");//办公电话:区 号
bo.setRemark19("88968");//办公电话:直线
bo.setRemark20("9435649");//办公电话:分机
bo.setRemark21("18868365686");//办公电话:移动电话
bo.setRemark22("[email protected]");//电子邮箱
bo.setRemark23("罗总");//财务经办人员:姓名
bo.setRemark24("020");//办公电话:区 号
bo.setRemark25("89468");//办公电话:直线
bo.setRemark26("9845146");//办公电话:分机
bo.setRemark27("16686866868");//办公电话:移动电话
bo.setRemark28("05");//账户种类:人民币:01定期账户,02基本户,03一般户,04临时户,05专用户,06NRA账户 当此项值为03时要设置remark29的值 当此项为05时要设置remark31的值 当此项值为06时要设置remark32的值
//vo.setRemark29("03");//一般户且用于:01结算,02贷款,03其它 当此项值为03时要设置remark30的值
//vo.setRemark30("预算");//具体的其他账户类型
bo.setRemark31("国有");//remark28值为05时要设置此项 专用户且账户资金性质为
//vo.setRemark32("64987");//remark28值为06时要设置此项 NRA账户且国家代码为
bo.setRemark33("05");//账户种类:外 币:币种:01美元,02港币,03欧元,04日元,05其他 当此项的值为05时要设置remark32的值
bo.setRemark34("英镑");//具体的币种
bo.setRemark35("04");//账户种类:外 币:种类:01经常项目外汇账户,02外汇资本金账户,03外债账户,04其他 当此项值为04时要设置remark34的值
bo.setRemark36("具体的账户种类");//具体的种类
bo.setRemark37("老祝");//控股股东或实际控制人
bo.setRemark38("03");// 证件种类:01身份证,02护照,03其他 当此项值为03时要设置remark37的值
bo.setRemark39("好男人证");//具体的证件种类名称
bo.setRemark40("86686688");//证件号码
bo.setRemark41("02");//证件到期日类型:01长期有效,02具体到期日 当此项值为02时要设置remark40、remark41、remark42的值
bo.setRemark42("2080");//证件到期日 年
bo.setRemark43("08"); //证件到期日 月
bo.setRemark44("18"); //证件到期日 日
bo.setRemark45("02");//机构类别:01消极非金融机构,02其他非金融机构
bo.setRemark46("01");//税收居民身份:01非居民或多重税收身份,02仅中国税收居民
bo.setRemark47("xxx");//上级法人或主管单位名称
bo.setRemark48("01");//是否勾选 开通或加挂网上/手机银行/橙e网,且网上银行服务权限:01勾选,02不勾选
bo.setRemark49("02");//是否勾选 转账与查询(企业管理员可在网银端自设录入及复核用户):01勾选,02不勾选
bo.setRemark50("01");//是否勾选 仅查询:01勾选,02不勾选
bo.setRemark51("02");//接收网上/手机银行激活码的移动电话:01同法定代表人(单位负责人)电话,02同财务负责人电话
bo.setRemark52("20");//USBKEY购买数量
bo.setRemark53("01");//其它增值服务:开通金卫士服务且签约移动电话:01勾选,02不勾选 当此项值为01时要设置remark52的值
bo.setRemark54("13398595998");//电话号码1
//vo.setRemark55("");//电话号码2
//vo.setRemark56("");//电话号码3
bo.setRemark57("02");//缴费方式:01按月,02按条,03按年
bo.setRemark58("01");//是否勾选 开通通兑:01勾选,02不勾选
bo.setRemark59("01");//是否勾选 开通支付密码:01勾选,02不勾选 当此项的值为01时要设置remark58的值
bo.setRemark60("01");//支付密码器类型:01新开,02自备
bo.setRemark61("01");//是否勾选 电子商业汇票签约 :01勾选,02不勾选
bo.setRemark62("法定代表人");//法定代表人或其授权人签章
bo.setRemark63("2018");//签章日期 年
bo.setRemark64("03"); //签章日期 月
bo.setRemark65("10"); //签章日期 日
bo.setRemark66("经办签的字");//经办签字
bo.setRemark67("主管签的字");//主管签字
bo.setRemark68("2018");//签字日期 年
bo.setRemark69("03"); //签字日期 月
bo.setRemark70("10"); //签字日期 日
bo.setRemark71("经办人的签章");//经办人(签章)
bo.setRemark72("2018");//签章日期 年
bo.setRemark73("03");//签章日期 月
bo.setRemark74("10");//签章日期 日
bo.setRemark75("88888888");//客户经理UM号
bo.setRemark76("老刘");//客户经理姓名
map.put("data", bo);
return map;
}
}