说明

调用方法生成PDF时,使用的ftl模版,以及字体都是从jar中读取的,无需担心多节点部署

引用jar

<dependency><groupId>org.freemarker</groupId><artifactId>freemarker-gae</artifactId><version>2.3.23</version>
</dependency><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version>
</dependency>
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.76</version>
</dependency>

文件存放路径

// 字体文件
resources/fonts
// 模版文件
resources/templates

代码

import com.lowagie.text.pdf.BaseFont;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.xhtmlrenderer.pdf.ITextRenderer;import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.StringWriter;
import java.util.Map;@Component
public class PdfHelper {/*** classpath路径*/private String classpath = getClass().getResource("/").getPath();/*** 指定FreeMarker模板文件的位置*/private String templatePath = "/templates";/*** freeMarker模板文件名称*/private String templateFileName = "pdf.ftl";/*** 图片路径 —— 默认是classpath下面的images文件夹*/private String imagePath = "/images/";/*** 字体资源文件 存放路径*/private String fontPath = "fonts/";/*** 字体   [宋体][simsun.ttc]   [黑体][simhei.ttf]*/private String font = "simsun.ttc";/*** 指定编码*/private String encoding = "UTF-8";@Value("{$file.path}")private String filePath;/*** 生成pdf** @param data 传入到freemarker模板里的数据* @param out  生成的pdf文件流*/public void createPDF(Map<String, Object> data, OutputStream out, String templateName) throws Exception {// 创建一个FreeMarker实例, 负责管理FreeMarker模板的Configuration实例Configuration cfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);// 指定FreeMarker模板文件的位置ITextRenderer renderer = new ITextRenderer();String simsun = System.getProperty("user.dir") + "/simsun.ttc";String arialuni = System.getProperty("user.dir") + "/arialuni.ttf";File fondFile = new File(simsun);if (!fondFile.exists()) {getFondPath();}// 设置 css中 的字体样式(暂时仅支持宋体和黑体)renderer.getFontResolver().addFont(simsun, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);renderer.getFontResolver().addFont(arialuni, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);StringTemplateLoader stringLoader = new StringTemplateLoader();String templateString = getFileData("templates/" + templateName);stringLoader.putTemplate("myTemplate", templateString);cfg.setTemplateLoader(stringLoader);Template tpl = cfg.getTemplate("myTemplate", "utf-8");StringWriter writer = new StringWriter();// 把null转换成""Map<String, Object> dataMap = CommunalTool.objectToMap(data);// 将数据输出到html中tpl.process(data, writer);writer.flush();String html = writer.toString();// 把html代码传入渲染器中renderer.setDocumentFromString(html);renderer.layout();renderer.createPDF(out, false);renderer.finishPDF();out.flush();out.close();}// 读取jar中的ftl模版文件private String getFileData(String path) {InputStream stream = getClass().getClassLoader().getResourceAsStream(path);// log.info("infile:"+infile);StringBuffer sb = new StringBuffer();BufferedReader br = null;try {br = new BufferedReader(new InputStreamReader(stream, "UTF-8"));String s = null;while ((s = br.readLine()) != null) {sb.append(s);}br.close();return sb.toString();} catch (Exception e) {e.printStackTrace();return null;} finally {if (br != null) {try {br.close();} catch (Exception e) {e.printStackTrace();}}}}/*** 获取字体路径** @return* @throws IOException*/private String getFondPath() throws IOException {String fontPath = System.getProperty("user.dir");InputStream inputStream = getClass().getClassLoader().getResourceAsStream("fonts/simsun.ttc");//在根目录生成一个文件File targetFile = new File(fontPath + "/simsun.ttc");// //将流转成File格式FileUtils.copyInputStreamToFile(inputStream, targetFile);InputStream arialuniStream = getClass().getClassLoader().getResourceAsStream("fonts/arialuni.ttf");File arialuni = new File(fontPath + "/arialuni.ttf");FileUtils.copyInputStreamToFile(arialuniStream, arialuni);return fontPath;}public void setClasspath(String classpath) {this.classpath = classpath;}public void setTemplatePath(String templatePath) {this.templatePath = templatePath;}public void setTemplateFileName(String templateFileName) {this.templateFileName = templateFileName;}public void setImagePath(String imagePath) {this.imagePath = imagePath;}public void setFontPath(String fontPath) {this.fontPath = fontPath;}public void setFont(String font) {this.font = font;}public void setEncoding(String encoding) {this.encoding = encoding;}}

工具类

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.serializer.ValueFilter;
import org.apache.commons.lang3.StringUtils;
import sun.misc.BASE64Encoder;import java.io.File;
import java.io.FileInputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;public class CommunalTool {/*** 转换数据中的null为""(空串)** @param obj       转换之前的数据* @param beanClass 转换之后的数据类型* @return 返回Object* @throws Exception*/public static Object objectToData(Object obj, Class<?> beanClass) throws Exception {return JSONObject.parseObject(objectToString(obj), beanClass);}/*** Map中的null转换成""(空串)** @param map 转换之前的数据* @return 返回 Map<String,Object>* @throws Exception*/public static Map<String, Object> objectToMap(Map<String, Object> map) throws Exception {return JSONObject.parseObject(objectToString(map), Map.class);}/*** 把list中的null转换成""(空串)** @param list 转换之前的数据* @return 返回list* @throws Exception*/public static List objectToList(List list) throws Exception {return JSONObject.parseObject(objectToString(list), List.class);}// fistJson 的一个过滤器static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");static DateFormat format = new SimpleDateFormat("yyyy-MM-dd");private static ValueFilter filter = new ValueFilter() {@Overridepublic Object process(Object obj, String s, Object v) {if (v instanceof Date) {return simpleDateFormat.format(v);} else {if (v == null) {return "";} else {return v;}}}};/*** 将对象转换为json格式的字符串** @param obj* @return String*/public static String objectToString(Object obj) {// JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd";return JSON.toJSONString(obj, filter, SerializerFeature.WriteNonStringKeyAsString, SerializerFeature.WriteNullStringAsEmpty);}/*** 将图片转成base64 字符串** @param path 文件路径* @return* @throws Exception*/public static String encodeBase64Picture(String path) throws Exception {File file = new File(path);FileInputStream inputFile = new FileInputStream(file);byte[] buffer = new byte[(int) file.length()];inputFile.read(buffer);inputFile.close();String result = new BASE64Encoder().encode(buffer);if (StringUtils.isNotBlank(result)) {result = "data:image/png;base64," + result;} else {result = null;}return result;}/*** 时间转换  yyyy-MM-dd** @param date* @return*/public static String getTransformationDate(Date date) {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");return sdf.format(date);}/*** 时间转换  yyyy-MM-dd** @param date* @return*/public static String getTimeDate(Date date) {int minte = getMinute(date);minte = minte % 5;SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");Date afterDate = new Date(date.getTime() + 300000);System.out.println(sdf.format(afterDate));return "1";}/*** 功能描述:返回分** @param date*            日期* @return 返回分钟*/public static int getMinute(Date date) {Calendar calendar = Calendar.getInstance();calendar.setTime(date);return calendar.get(Calendar.MINUTE);}/*** 获取日期年份* @param date 日期* @return*/public static String FORMAT_FULL = "yyyy-MM-dd HH:mm:ss";public static String getTime(Date date) {SimpleDateFormat df = new SimpleDateFormat(FORMAT_FULL);return df.format(date).substring(12, 16);}}

ftl模版

电子化模版单个表格
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta charset="UTF-8" /><title>模版</title><style type="text/css">body{width:100%;}@media screen and (max-width: 768px) {body{font-size: 14px;}table{table-layout: fixed;}  }p{line-height: 26px;margin-right:15px;}table td p{line-height:6px;margin-right:0;padding-right:0;padding-left:0;}span{margin:0;padding:0;}</style><style type="text/css" mcs_bogus="1">@page {size: a4 landscape;/*210*297*//*size:195mm 271mm;*/margin: 8mm 8mm;padding: 0;/*border:solid #F00 1px;*/background-image:url(images/water.gif);background-repeat:no-repeat;background-position:center;@top-left {content: element(header);}@bottom-left {content: element(footer);}@bottom-center {content: "--- " counter(page) " ---" counter(main-heading);}@bottom-right {content: "";}}@page blank {size: a4 portrait;/*size:195mm 271mm;*/margin: 10mm 10mm;padding: 0;@top-left {content: normal}@bottom-left {content: normal}@top-right {content: normal}@bottom-right {content: normal}@bottom-center {content: normal}}#pagenumber:before {content: counter(page);}#pagecount:before {content: counter(pages);}/* Used for generating Table of content */#toc a::after {content: leader('.') target-counter(attr(href), page);}/* Use this class forfirst level titles */.page_break_before {page-break-before: always;}/* Use this class for forcing page break inside pdf */.page_breaker {page-break-after: always;}.blank {page : blank;}.version {page: version;}@page :[counter(page)=3] {margin-top:0;margin-right:0;@bottom-center {content: "第N页";font-family:SimSun,'宋体';font-size:10px;}}@page version {@bottom-left {content: "version";margin: 0;padding: 0;font-size: 8pt;font-style:italic;font-family:SimSun,'宋体';}}/* footnote */.notebox {page: notebox;}@page notebox {page-break-after: auto;}@media print {.notebox {position: relative;}.notebox .content {width: 100%;margin-bottom: 0px;}.notebox .footnote {position: absolute;top: 265mm;left: 0;z-index: 100;border-top: 1pt solid #000;width: 100%;font-size: 8.76pt;}}body {line-height: 100%;font-family:SimSun,'宋体';/*width:178mm;*/margin: 0;}.page {/*size:195mm 271mm;*/height: 100mm;/*height:246mm; 16K*/border: 0px;}.font {font-size: 10px;line-height: 20px;}.xhx {border-bottom:solid 1px #000000;}td{border-top:solid 1px #000000;border-bottom:solid 0px #000000;border-left:solid 1px #000000;border-right:solid 0px #000000;display:inline-black;padding:6px 0px 6px 0px;margin:0px;}tr td:last-child {border-right:solid 1px #000000;}table { page-break-inside:auto; -fs-table-paginate:paginate;border-spacing: 0;border-bottom:solid 1px #000000;}</style>
</head>
<body><div style="width:90%;margin:0 auto"><div><h2 style="text-align: center;">${name}</h2><div class="Section1"><div style="width:100%;overflow:hidden;"><div style="float:left;"><span>货物交接单号:</span><img src="${zhwjjdh}" style="height:50px;width:150px;" /></div><div style="float:right;"><span>生成时间:2021-12-16</span></div></div><table cellspacing="0" cellpadding="0" style="width:100%;margin:0;text-align: center;border-bottom:solid 0px #000000;" rules="all" border="0"><thead style="display:table-header-group;border:0px;cellpadding:0;cellspacing:0;height:0px;"></thead><tbody><tr style="border-bottom: none"><td width="15%">工程名称</td><td width="85%" style="text-align:left;padding-left:10px;"></td></tr><tr><td >合同名称</td><td  style="text-align:left;padding-left:10px;"></td></tr><tr><td >合同编号</td><td style="text-align:left;padding-left:10px;"></td></tr><tr><td >违约事实</td><td style="text-align:left;padding-left:10px;"></td></tr><tr><td >约谈情况</td><td style="text-align:left;padding-left:10px;"></td></tr><tr><td height="50px">供应商</td><td height="80px" style="text-align:left;padding-left:10px;"></td></tr><tr><td height="50px">物资公司</td><td height="80px"></td></tr><tr><td height="50px">项目管理部门</td><td height="80px" style="text-align:left;padding-left:10px;"></td></tr><tr><td height="50px">物资部</td><td height="80px" style="text-align:left;padding-left:10px;"></td></tr><tr><td height="50px">财务部</td><td height="80px" style="text-align:left;padding-left:10px;"></td></tr></tbody><tfoot style="display:table-footer-group;"><tr><td style="height: 0px;padding: 0px;border: none;border-bottom: solid 1px #000000;" colspan="2"></td></tr></tfoot></table><p>注:1.涉及技术的违约事实,由项目管理部门确认;涉及商务的违约事实,由物资公司/供应中心确认;技术、商务均涉及的,由项目管理部门,由物资公司/供应中心确认。各个单位可根据实际情况增加其他部门(单位)确认。</p></div></div>
</div>
</body>
</html>

调用主函数生成

import com.sgcc.cn.utils.PdfHelper;import java.io.File;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.Map;public class test {public static void main(String[] args) {try {PdfHelper pdfHelper = new PdfHelper();Map<String,Object> map = new HashMap<>();map.put("name","唯有碎银解千愁");FileOutputStream out = new FileOutputStream(new File( "D:\\1.pdf"));pdfHelper.createPDF(map,out,"gererate.ftl");} catch (Exception e) {e.printStackTrace();}}
}

电子化模版嵌套表格

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta charset="UTF-8" /><title>调配申请单</title><style type="text/css">body{width:100%;}@media screen and (max-width: 768px) {body{font-size: 14px;}table{table-layout: fixed;}  }p{line-height: 26px;margin-right:15px;}table td p{line-height:6px;margin-right:0;padding-right:0;padding-left:0;}span{margin:0;padding:0;}</style><style type="text/css" mcs_bogus="1">@page {size: a4 landscape;/*210*297*//*size:195mm 271mm;*/margin: 8mm 8mm;padding: 0;/*border:solid #F00 1px;*/background-image:url(images/water.gif);background-repeat:no-repeat;background-position:center;@top-left {content: element(header);}@bottom-left {content: element(footer);}@bottom-center {content: "--- " counter(page) " ---" counter(main-heading);}@bottom-right {content: "";}}@page blank {size: a4 portrait;/*size:195mm 271mm;*/margin: 10mm 10mm;padding: 0;@top-left {content: normal}@bottom-left {content: normal}@top-right {content: normal}@bottom-right {content: normal}@bottom-center {content: normal}}#pagenumber:before {content: counter(page);}#pagecount:before {content: counter(pages);}/* Used for generating Table of content */#toc a::after {content: leader('.') target-counter(attr(href), page);}/* Use this class forfirst level titles */.page_break_before {page-break-before: always;}/* Use this class for forcing page break inside pdf */.page_breaker {page-break-after: always;}.blank {page : blank;}.version {page: version;}@page :[counter(page)=3] {margin-top:0;margin-right:0;@bottom-center {content: "第N页";font-family:SimSun,'宋体';font-size:10px;}}@page version {@bottom-left {content: "version";margin: 0;padding: 0;font-size: 8pt;font-style:italic;font-family:SimSun,'宋体';}}/* footnote */.notebox {page: notebox;}@page notebox {page-break-after: auto;}@media print {.notebox {position: relative;}.notebox .content {width: 100%;margin-bottom: 0px;}.notebox .footnote {position: absolute;top: 265mm;left: 0;z-index: 100;border-top: 1pt solid #000;width: 100%;font-size: 8.76pt;}}body {line-height: 100%;font-family:SimSun,'宋体';/*width:178mm;*/margin: 0;}.page {/*size:195mm 271mm;*/height: 100mm;/*height:246mm; 16K*/border: 0px;}.font {font-size: 10px;line-height: 20px;}.xhx {border-bottom:solid 1px #000000;}td{border-top:solid 1px #000000;border-bottom:solid 0px #000000;border-left:solid 1px #000000;border-right:solid 0px #000000;display:inline-black;padding:6px 0px 6px 0px;margin:0px;}tr td:last-child {border-right:solid 1px #000000;}table { page-break-inside:auto; -fs-table-paginate:paginate;border-spacing: 0;border-bottom:solid 1px #000000;}</style>
</head>
<body><div style="width:90%;margin:0 auto"><div><h2 style="text-align: center;">调配申请单</h2><div class="Section1"><div style="width:95%;overflow:hidden;text-align: right;"><div>编号:${receive.zdpsq}</div></div><table cellspacing="0" cellpadding="0" style="width:100%;margin:0;text-align: center;" rules="all" border="0" frame="void"><tbody><tr style="border-bottom: none"><td width="10%" >申请单位</td><td width="18%" >${receive.zbutxt}</td><td width="18%" >申请日期</td><td width="18%" >${receive.createDate}</td><td width="18%" >调配类型</td><td width="18%" >市内调配/省内跨市调配</td></tr><tr><td rowspan="3" >需求<br/>描述</td><td colspan="2">调配方式</td><td>划转</td><td>拟调配地址</td><td>${receive.zdpdz}</td></tr><tr><td colspan="2">联系人</td><td>${receive.zxqflxr}</td><td>联系电话</td><td>${receive.zxqflxfs}</td></tr><tr><td colspan="5" style="padding:0px 0px 0px 0px;border:solid 0px #000000"><table cellspacing="0" cellpadding="0" style="width:100%;margin:0;text-align: center;border-bottom:solid 0px #000000;" rules="all" border="0"><thead style="display:table-header-group;"><td>序号</td><td>物料编码</td><td>物料名称</td><td>规格型号</td><td>单位</td><td>需求数量</td><td>备注</td></thead><tbody><#list checkList as item><tr><td>${item_index+1}</td><td>${item.matnr}</td><td>${item.maktx}</td><td>${item.zggxh}</td><td>${item.meins}</td><td>${item.menge}</td><td>${item.remark}</td></tr></#list></tbody><tfoot style="display:table-footer-group;"><tr><td style="height: 0px;padding: 0px;border: none;border-bottom: solid 0px #000000;" colspan="5"></td></tr></tfoot></table></td></tr><tr><td height="170px">市公司分管领导(签字)</td><td></td><td height="170px">市公司物资部/物资供应中心(签字、盖章)</td><td></td><td height="170px">市公司专业部门(签字、盖章)</td><td></td></tr><tr><td colspan="6">本调配单一式四份,省/地市物资部、省物资公司/县公司供应分中心、调入方和调出方各一份</td></tr></tbody></table ></div></div>
</div>
</body>
</html>

如果不想把文件存在本地,想在生成之后返回流文件,代码如下

public byte[] createPDF(Map<String, Object> data, String templateName) throws Exception {// 创建一个FreeMarker实例, 负责管理FreeMarker模板的Configuration实例Configuration cfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);// 指定FreeMarker模板文件的位置ITextRenderer renderer = new ITextRenderer();String simsun = System.getProperty("user.dir") + "/simsun.ttc";String arialuni = System.getProperty("user.dir") + "/arialuni.ttf";File fondFile = new File(simsun);if (!fondFile.exists()) {getFondPath();}// 设置 css中 的字体样式(暂时仅支持宋体和黑体)renderer.getFontResolver().addFont(simsun, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);renderer.getFontResolver().addFont(arialuni, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);StringTemplateLoader stringLoader = new StringTemplateLoader();String templateString = getFileData("templates/" + templateName);stringLoader.putTemplate("myTemplate", templateString);cfg.setTemplateLoader(stringLoader);Template tpl = cfg.getTemplate("myTemplate", "utf-8");StringWriter writer = new StringWriter();// 把null转换成""Map<String, Object> dataMap = CommunalTool.objectToMap(data);// 将数据输出到html中tpl.process(data, writer);writer.flush();String html = writer.toString();// 把html代码传入渲染器中renderer.setDocumentFromString(html);ByteArrayOutputStream out = new ByteArrayOutputStream();renderer.layout();renderer.createPDF(out);renderer.finishPDF();byte[] fileByte = out.toByteArray();out.flush();out.close();return fileByte;}

在文件中添加图片,代码如下

在ftl文件中添加代码<span>货物交接单号:</span>
<img src="${zhwjjdh}" style="height:50px;width:150px;" />用java代码把图片转换成base64
/*** 将图片转成base64 字符串** @param path 文件路径* @return* @throws Exception*/public static String encodeBase64Picture(String path) throws Exception {File file = new File(path);FileInputStream inputFile = new FileInputStream(file);byte[] buffer = new byte[(int) file.length()];inputFile.read(buffer);inputFile.close();String result = new BASE64Encoder().encode(buffer);if (StringUtils.isNotBlank(result)) {result = "data:image/png;base64," + result;} else {result = null;}return result;}

如果想要动态读取模版也可以

templateString  这个就是模版字符串,然后你可以写一个扩展方法去读取,如你想从数据库中存储和读取
String templateString = getFileData("templates/" + templateName);
stringLoader.putTemplate("myTemplate", templateString);

设置mysql数据库存储文件的字段为大字段类型blob

// 这里只提供一个公共方法,读取文件后返回一个字符串。
public String uploadModelSql(MultipartFile file) {BufferedReader reader = null;StringBuffer sbf = new StringBuffer();try {// Reader read = new InputStreamReader(file.getInputStream(), "UTF-8");Reader read = new InputStreamReader(file.getInputStream(), "utf-8");reader = new BufferedReader(read);String tmpString = null;//一行一行的读取文件里面的内容,这个是防止文件存储数据库之后,在读取模版布局问题while ((tmpString = reader.readLine()) != null) {sbf.append(tmpString).append("\r\n");}if (sbf == null) {throw new RuntimeException("文件内容为空!");}return sbf.toString();} catch (IOException e) {e.printStackTrace();return sbf.toString();} finally {if (reader != null) {try {reader.close();} catch (IOException e1) {e1.printStackTrace();}}}}

模版下载

/*** 下载模版文件** @param response* @param id* @return*/@RequestMapping("/downLoad")public void downLoadFile(HttpServletResponse response, @RequestParam String id) {try {//根据id查询数据库中的记录SignatureTemplatesFile record = signatureTemplatesFileService.downLoadFile(id);// 清空responseresponse.reset();// 设置response的Header,record.getTemplateName() 文件名称response.addHeader("Content-Disposition", "attachment;filename=" + new String(record.getTemplateName()));// response.addHeader("Content-Length", "" + file.length());OutputStream toClient = new BufferedOutputStream(response.getOutputStream());response.setContentType("application/octet-stream");//大字段中的字符串,转换成byte数组byte[] bytes = record.getTemplateFile().getBytes();toClient.write(bytes);toClient.flush();toClient.close();} catch (Exception e) {e.printStackTrace();}}

总结

代码写的有点乱,总体来说该有的功能都有了,如:从jar中读取字体和ftl模版,如果你不想从jar中读取,可以自己改造一下,就是不管你是从其他地方读文件或者从数据库中字符串,总之你要把他转换成字符串,最后给(templateString)它就行。还有PDF生成的时候也可以返回流文件,你可以把返回的流文件,存储fastDFS(文件管理插件)上面去统一管理。

java中freemarker使用ftl模版生成PDF文件相关推荐

  1. 利用PDF模版生成PDF文件

    文章目录 前言 一.注备好PDF模版 二.代码示例 1.依赖 2.代码示例 总结 前言 如何利用PDF模版填充数据,生成我们想要的PDF文件呢? 一.准备好PDF模版 1.注备好需要生成的PDF文件 ...

  2. springboot 基于.ftl模板生成pdf文件

    目录 Demo前置简述 生成pdf内容 项目结构 主要实现 api测试 完整代码地址 Demo前置简述 实现功能:用户个人信息测试数据加上ftl模板得到html字符串,然后根据html字符串生成pdf ...

  3. PDF功能实现1——Java实现动态页面在后台生成PDF文件

    # 项目描述: 1.项目功能需求:增加证明打印功能,打印时,需将内容生成pdf文件并保存,然后数据库增加一笔打印记录 2.功能分析:由于不单单只是页面打印,所以比较常用的window.print()首 ...

  4. 根据html改为ftl模板生成pdf文件,支持中文及换行

    这里demo用的maven来管理项目,pom.xml如下: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns: ...

  5. java 字符串转pdf文件_java中根据模板生成pdf文件

    原标题:java中根据模板生成pdf文件 阅读目录 简介 业务需求 引入jar包 pdf模板文件与方法参数 代码部分 总结归纳 回到顶部 简介 本文使用java引入apach提供的pdf操作工具生成p ...

  6. java按模板生成pdf_java中根据模板生成pdf文件

    简介 本文使用java引入apache提供的pdf操作工具生成pdf文件,主要是根据需求开发了一个util类,记录一下学习和开发过程. 业务需求 因为业务需要,对于不同的用户要生成一个不同的pdf文件 ...

  7. freemarker模板生成pdf文件

    文章目录 1.pom依赖 2.ftl模板以及宋体文件 2.1.文件路径 2.2.ftl文件模板(test.ftl) 3.controller生成pdf文件 1.pom依赖 <!--freemar ...

  8. itextword加公章 java_使用itext和freemarker来根据Html模板生成PDF文件,加水印、印章...

    org.xhtmlrenderer flying-saucer-pdf-itext5 9.1.18 org.freemarker freemarker 2.3.27-incubating 将html模 ...

  9. freemarker 模板生成pdf文件并下载

    利用freemarker 模板生成pdf文件,通过浏览器直接下载或生成文件到指定目录 1.pom.xml文件 <!--引入Freemarker的依赖--> <dependency&g ...

最新文章

  1. I2C从驱动到应用(中篇)
  2. Vue实现仿音乐播放器10-更多按钮实现下拉刷新
  3. 从涂鸦到发布 —— 理解API的设计过程
  4. Android中获取网络图片的三种方法
  5. DDD~领域事件中使用分布式事务
  6. ASP.NET Core自定义响应内容
  7. reddit_我在3天内疯狂地审查了Reddit上的50个投资组合,从中学到了什么。
  8. 英特尔助力金山云带你畅游云端的游戏世界
  9. HTML5个人求职简历模板下载
  10. Python+pandas读取Excel文件统计最受欢迎的前3位演员
  11. linux命令echo的实现,Linux echo命令的使用及三种实现方式
  12. Idea安装Eslint插件详解 提示:Plugin NativeScript was not installed解决
  13. .md文件好用编辑软件分享Typora
  14. OGNL表达式【mybatis】
  15. 地图索引文件MXD保存到数据库中
  16. 天眼查app协议逆向分析
  17. 核磁共振成像脉冲序列——杨正汉(2)
  18. 【Google Play】APK 扩展包 ( 2021年09月 最新处理方案 | 文件准备 | 拷贝文件至内置存储 | 解压及使用扩展文件 )
  19. win10系统怎么做电影服务器,瞧瞧Win10是如何将电影推送到电视机上的
  20. 计算机 dc代表什么意思,dc和ac代表什么意思

热门文章

  1. react-intl中injectIntl/intlProvider方法的源码简析
  2. Scrapy遇到的常见错误-Unknown command: crawl
  3. 基于Ernie-3.0的电影评论情感分析
  4. css3 @support,CSS @supports (CSS3条件判断)
  5. 鲸享云业务长视频B(B站)
  6. 2023最新大猿人中控充值系统/免授权版/支持公众号H5+分销等功能
  7. 计算机与信息技术研究生,心之所向,素履以往——访计算机与信息技术学院硕士研究生乔洁...
  8. 关于C#中批量修改button等控件属性的办法
  9. vscode设置默认自动换行方法步骤
  10. tp5.1使用验证码类时,验证码图片不显示