文章目录

  • SpringBoot+FreeMarker+flying-saucer-pdf实现PDF预览、分页需求
    • 需求说明
    • 程序示例
      • 程序示例说明
      • 添加依赖包
      • FreeMarker模板文件编写
      • 工具类编写
      • 程序示例控制器编写
      • PDF分页实现
    • 参考链接
    • 源代码地址

SpringBoot+FreeMarker+flying-saucer-pdf实现PDF预览、分页需求

需求说明

  1. MicroSoft Word文档转换PDF文档
  2. 实际工作场景中,类似于业务部门提供合同的Word文档范本,预览合同、签署合同、下载合同均需求使用PDF文档。

程序示例

程序示例说明

示例程序通过两种方式实现了FreeMarker+flying-saucer-pdf的PDF预览、分页需求

  1. FreeMarker模板位于应用程序资源目录下:/resources/templates/freemarkers
  2. FreeMarker模板存储于其它存储单元,例如数据库

添加依赖包

<!-- xml 将html模板文件转换成pdf -->
<dependency><groupId>org.xhtmlrenderer</groupId><artifactId>flying-saucer-pdf</artifactId><version>9.1.22</version>
</dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

FreeMarker模板文件编写

<html><head><style>span{border-bottom: 1px solid black;}p{line-height: 1.5;}@page {size: 210mm 297mm; /*设置纸张大小:A4(210mm 297mm)、A3(297mm 420mm) 横向则反过来*/margin-bottom: 1cm;padding: 1em;@top-center {content: "页眉中间位置";font-family: SimSun;font-size: 15px;color:#000;};@bottom-center{content: "页脚中间位置";font-family: SimSun;font-size: 15px;color:#000;};@bottom-right{content: "第" counter(page) "页 共" counter(pages) "页";font-family: SimSun;font-size: 15px;color:#000;};}#pagenumber:before {content: counter(page);}#pagecount:before {content: counter(pages);}</style>
</head><body style="font-family: SimSun;"><p><h1 style="text-align: center;">公司授权委托书</h1></p><br /><br /><p>致:<span>${tenEntName!}</span></p><p>&#160;&#160;&#160;&#160;我单位现委托<span>${userName!}</span>作为我单位合法委托代理人,授权其代表我单位进行<span>${indexTitle!}</span>账户相关管理工作。该委托代理人的授权范围为:代表我单位在<span>${indexTitle!}</span>上注册、签署文件、使用<span>${indexTitle!}</span>、资金交易、融资等与<span>${indexTitle!}</span>有关的一切事务。在整个<span>${indexTitle!}</span>使用过程中,该代理人的一切行为,均代表本单位,与本单位的行为具有同等法律效力。本单位将承担该代理人行为带来的全部法律后果和法律责任。</p><p>&#160;&#160;&#160;&#160;以上授权委托有效期自盖章之日(含当日)起至<span>${indexTitle!}</span>账户注销和/或<span>${indexTitle!}</span>全部融资款项结算完毕终止。</p><p>&#160;&#160;&#160;&#160;代理人无权转换代理权。</p><p>&#160;&#160;&#160;&#160;特此委托。</p><p>&#160;&#160;&#160;&#160;代理人姓名:<span>${userName!}</span></p><p>&#160;&#160;&#160;&#160;身份证号码:<span>${userNum!}</span></p><br /><br /><p>&#160;&#160;&#160;&#160;委托人(盖章):</p><p>&#160;&#160;&#160;&#160;日期:<span>${year!}</span><span>${month!}</span><span>${day!}</span></p><br /><br />    <br /><br />    <br /><br />    <br /><br />    <br /><br />    <br /><br /><br /><br />    <br /><br />    <br /><br /><p>附:委托代理人身份证复印件(<span>正反面、</span>加盖公章)</p><div id = "header"></div></body></html>

注意事项:

  1. 在body标签中指定模板文件字体。本文是宋体:font-family: SimSun;
  2. FreeMarker文件对Html标签要求很严格,尽量使用正确的标签。
  3. 模板文件位置应用程序资源目录下:/resources/templates/freemarkers

工具类编写

  • FreeMarker工具类
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;import java.io.IOException;
import java.io.StringWriter;
import java.util.Locale;
import java.util.Map;public class FreemarkerUtil {/*** 从模板文件中加载* @param templateFileName* @param data* @return* @throws IOException* @throws TemplateException*/public static String loadTemplateFromFile(String templateFileName, Map<String, String> data) throws IOException, TemplateException {// 创建一个FreeMarker实例, 负责管理FreeMarker模板的Configuration实例Configuration cfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);// 指定FreeMarker模板文件的位置cfg.setClassForTemplateLoading(FreemarkerUtil.class,"/templates/freemarkers");// 设置模板的编码格式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();return html;}/*** 从存储单元中中加载* @param templateFileContent* @param data* @return* @throws IOException* @throws TemplateException*/public static String loadTemplateFromStorage(String templateFileContent, Map<String, String> data) throws IOException, TemplateException {String templateName = "自定义模板名称";StringWriter stringWriter = new StringWriter();StringTemplateLoader loader = new StringTemplateLoader();loader.putTemplate(templateName, templateFileContent);Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);cfg.setTemplateLoader(loader);cfg.setDefaultEncoding("UTF-8");Template template = cfg.getTemplate(templateName);template.process(data, stringWriter);String html = stringWriter.toString();return html;}}
  • PDF工具类
import com.lowagie.text.pdf.BaseFont;
import org.xhtmlrenderer.pdf.ITextRenderer;import java.io.ByteArrayOutputStream;
import java.io.OutputStream;public class PDFUtil {public static ByteArrayOutputStream createPDFFromHtml(String html) throws Exception {ITextRenderer renderer = new ITextRenderer();OutputStream out = new ByteArrayOutputStream();// 设置 css中 的字体样式(暂时仅支持宋体和黑体) 必须,不然中文不显示renderer.getFontResolver().addFont("/font/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);// 把html代码传入渲染器中renderer.setDocumentFromString(html);//            // 设置模板中的图片路径 (这里的images在resources目录下) 模板中img标签src路径需要相对路径加图片名 如<img src="data:images/xh.jpg"/>
//            String url = PDFTemplateUtil.class.getClassLoader().getResource("images").toURI().toString();
//            renderer.getSharedContext().setBaseURL(url);renderer.layout();renderer.createPDF(out, false);renderer.finishPDF();out.flush();ByteArrayOutputStream byteArrayOutputStream = (ByteArrayOutputStream) out;return byteArrayOutputStream;}}

程序示例控制器编写

import cn.tyrone.springboot.freemarker.util.FreemarkerUtil;
import cn.tyrone.springboot.freemarker.util.PDFUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;@RestController
@RequestMapping("/freemarker/pdf")
public class Freemarker2PDFController {/*** 从模板文件中加载* @param response* @throws Exception*/@GetMapping("/template/file")public void loadFromTemplate(HttpServletResponse response) throws Exception {String templateFileName = "demo.ftl";Map<String, String> data = new HashMap<>();data.put("userName", "孙悟空");data.put("userNum", "110101199003074071");data.put("year", "2022");data.put("month", "01");data.put("day", "24");data.put("siteName", "帅链平台");data.put("ticketTitle", "帅票");data.put("tenEntName", "郑州市公共交通集团有限公司");data.put("indexTitle", "帅链科技");String html = FreemarkerUtil.loadTemplateFromFile(templateFileName, data);ByteArrayOutputStream baos = PDFUtil.createPDFFromHtml(html);response.setContentType("application/pdf");OutputStream out = response.getOutputStream();baos.writeTo(out);baos.close();}/*** 从存储单元中加载* @param response* @throws Exception*/@GetMapping("/template/storage")public void loadFromStorage(HttpServletResponse response) throws Exception {Map<String, String> data = new HashMap<>();data.put("userName", "孙悟空");data.put("userNum", "110101199003074071");data.put("year", "2022");data.put("month", "01");data.put("day", "24");data.put("siteName", "帅链平台");data.put("ticketTitle", "帅票");data.put("tenEntName", "郑州市公共交通集团有限公司");data.put("indexTitle", "帅链科技");String templateContent = "<html><head><style>span{border-bottom:1px solid black}p{line-height:1.5}@page{size:210mm 297mm;margin-bottom:1cm;padding:1em;@top-center{content:\"页眉中读取存储单元间位置\";font-family:SimSun;font-size:15px;color:#000};@bottom-center{content:\"页脚中间位置\";font-family:SimSun;font-size:15px;color:#000};@bottom-right{content:\"第\"counter(page)\"页 共\"counter(pages)\"页\";font-family:SimSun;font-size:15px;color:#000}}#pagenumber:before{content:counter(page)}#pagecount:before{content:counter(pages)}</style></head><body style=\"font-family: SimSun; \"><p><h1 style=\"text-align: center;\">公司授权委托书</h1></p><br/><br/><p>致:<span>${tenEntName!}</span></p><p>&#160;&#160;&#160;&#160;我单位现委托<span>${userName!}</span>作为我单位合法委托代理人,授权其代表我单位进行<span>${indexTitle!}</span>账户相关管理工作。该委托代理人的授权范围为:代表我单位在<span>${indexTitle!}</span>上注册、签署文件、使用<span>${indexTitle!}</span>、资金交易、融资等与<span>${indexTitle!}</span>有关的一切事务。在整个<span>${indexTitle!}</span>使用过程中,该代理人的一切行为,均代表本单位,与本单位的行为具有同等法律效力。本单位将承担该代理人行为带来的全部法律后果和法律责任。</p><p>&#160;&#160;&#160;&#160;以上授权委托有效期自盖章之日(含当日)起至<span>${indexTitle!}</span>账户注销和/或<span>${indexTitle!}</span>全部融资款项结算完毕终止。</p><p>&#160;&#160;&#160;&#160;代理人无权转换代理权。</p><p>&#160;&#160;&#160;&#160;特此委托。</p><p>&#160;&#160;&#160;&#160;代理人姓名:<span>${userName!}</span></p><p>&#160;&#160;&#160;&#160;身份证号码:<span>${userNum!}</span></p><br/><br/><p>&#160;&#160;&#160;&#160;委托人(盖章):</p><p>&#160;&#160;&#160;&#160;日期:<span>${year!}</span>年<span>${month!}</span>月<span>${day!}</span>日</p><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><p>附:委托代理人身份证复印件(<span>正反面、</span>加盖公章)</p><div id=\"header\"></div></body></html>";String html = FreemarkerUtil.loadTemplateFromStorage(templateContent, data);ByteArrayOutputStream baos = PDFUtil.createPDFFromHtml(html);response.setContentType("application/pdf");OutputStream out = response.getOutputStream();baos.writeTo(out);baos.close();}}

PDF分页实现

flying-saucer-pdf是通过css样式实现分页的,如下:

<style>span{border-bottom: 1px solid black;}p{line-height: 1.5;}@page {size: 210mm 297mm; /*设置纸张大小:A4(210mm 297mm)、A3(297mm 420mm) 横向则反过来*/margin-bottom: 1cm;padding: 1em;@top-center {content: "页眉中间位置";font-family: SimSun;font-size: 15px;color:#000;};@bottom-center{content: "页脚中间位置";font-family: SimSun;font-size: 15px;color:#000;};@bottom-right{content: "第" counter(page) "页 共" counter(pages) "页";font-family: SimSun;font-size: 15px;color:#000;};}#pagenumber:before {content: counter(page);}#pagecount:before {content: counter(pages);}</style>

参考链接

https://www.iteye.com/blog/wuxiangxin-1550349

源代码地址

https://github.com/myNameIssls/springboot-study/tree/master/springboot-freemarker

SpringBoot+FreeMarker+flying-saucer-pdf实现PDF预览、分页需求相关推荐

  1. iText和flying saucer结合生成pdf的技术

    原博文地址 http://blog.csdn.net/shanliangliuxing/article/details/6833471 下面是我自己利用flying saucer技术生成pdf文档的实 ...

  2. iTextRenderer(Flying Saucer) HTML转PDF

    iTextRenderer(Flying Saucer) HTML转PDF iTextRenderer 在依赖 iText 的基础上,单独实现了HTML渲染PDF,基本上能实现 CSS 2.1的整体性 ...

  3. Springboot + layui + FTP文件上传删除 + HTTP文件下载预览 + pdf.js文件预览(项目实战总结)

    文件管理 0.需求及前言 1.前端,上传按钮嵌入数据表格中 2.利用IIS部署FTP文件服务器 3.后台FTP连接和文件操作 4.FTP遇到的问题和解决方案 5.预览PDF文件V1.0:FTP+临时文 ...

  4. 在线文件/文档预览/分页分片预览 之开源kkfileview(word转pdf,pdf截取,pdf转图片,Aspose jobConverter , OpenOffice ,libreoffice )

    前提说明 浏览器不能直接浏览word文件,但可以浏览pdf文件!!! 可以后台把word,excel 转成成pdf.然后给前端预览: 业界常用的开源工具有:Aspose jobConverter ,  ...

  5. java flexpaper_java web word文件 pdf文件在线预览源码(flexpaper)

    [实例简介]java web word文件 pdf文件在线预览源码 经过测试 [实例截图] [核心代码] BrowsenOnline html, body{ height:100%; } body { ...

  6. DevExpress的PdfViewer添加工具栏实现PDF打开、预览、保存、打印

    场景 Winform控件-DevExpress18下载安装注册以及在VS中使用: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/1 ...

  7. Java通过openOffice实现word,excel,ppt转成pdf实现在线预览

    Java通过openOffice实现word,excel,ppt转成pdf实现在线预览 一.OpenOffice 1.1 下载地址 1.2 JodConverter 1.3 新建实体类PDFDemo ...

  8. 引用pdf插件在线预览的问题

    引用pdf插件在线预览带中文名称文件报错解决 解决 由图可知插件pdf.js在解析带有中文的pdf文件时出现乱码问题 直接去改pdf.js比较麻烦且不好改,我们可以在预览pdf时候这么定义: Prin ...

  9. Android实现PDF格式文件预览

    前言: 接着上一篇的博客,在搜索出手机内的.pdf格式文件后,实现pdf文件的预览的方式有很多, 1.Android PdfViewer项目地址: https://github.com/barteks ...

  10. vue-pdf实现pdf文件在线预览

    1. 前言 PDF文件在线预览的功能相信大家都是有遇到过的, 但在我平时的项目中, 公司提供了相应的插件, 但是在h5等其他项目中, 我们还是只能靠自己呀! 今天就大概说一下 vue-pdf 这个组件 ...

最新文章

  1. Angular多个页面引入同一个组件报错The Component ‘MyComponentComponent‘ is declared by more than one NgModule怎么办?
  2. 课程表美化 css_通过这门11小时的免费课程学习HTML和CSS
  3. 宏基因组实战8. 分箱宏基因组binning, MqaxBin, MetaBin, VizBin
  4. BZOJ 1859 Luogu P2589 [ZJOI2006]碗的叠放 (计算几何)
  5. thinkphp两表联查并且分页
  6. WinSock三种选择I/O模型
  7. mysql存储过程报错_MySQL存储过程错误No data - zero rows fetched, selected, or processed
  8. [从零开始]HelloWorld——第一个应用程序
  9. 小舅子的工作每周轮换一次
  10. oracle ola_Ola HallengrenSQL Server维护解决方案–数据库完整性检查
  11. Delphi多层开发方案比较
  12. 年度重磅!2020年度中国计算机视觉人才调研报告正式发布
  13. jquery实现百度类似搜索提示功能(AJAX应用)
  14. Python实现双色球随机选号
  15. 教你用GoldWave进行基础的混音准备
  16. 2021全球程序员收入报告出炉!
  17. java的过滤器_java过滤器
  18. Android系统 GPIO状态查询
  19. ps还原上一步快捷键_photoshop恢复上一步操作的快捷键是什么
  20. 如何使用graphpad做柱形图_Graphpad Prism 8作图教程(2):XY图的属性设置

热门文章

  1. 道高一尺 魔高一丈(使用插件订火车票)
  2. 读取文件时内容乱码解决方法
  3. 海南信用社计算机试题,2015年海南农村信用社考试试题——计算机基础知识一...
  4. 如何在linux下配置网络桥接?-使初学者轻松远离ping不通的烦恼
  5. 为什么自来水按立方米收费?
  6. Python中常见的__init__.py是什么意思?详解Python import的方式和原理
  7. 亚马逊账号关联:一生只能有一个店铺
  8. python库numpy使用技巧(一)——提取数组中非零元素
  9. Centos Denyhosts 一键安装配置脚本
  10. Java流程控制练习题