项目场景:

因为打印功能的模板和背景图每年都会更换,但是数据基本不会发生改变,因此将原来项目itext生成pdf重构为页面和数据分离的模式。


目录:

一、引用jar包

1、flying-saucer-core-9.1.5.jar
2、flying-saucer-pdf-9.1.5.jar
3、freemarker.jar
因为我的项目仅仅是个web项目,还不是maven项目,只能单独引入jar包,如果报错好不到某些方法,可以再单独去下载。这个问题好解决。

二、自定义工具类

1、引入字体解决ITextRenderer不支持中文的问题

C:\Windows\Fonts可以在这里找到自己需要的字体,我这里用到了宋体和微软雅黑,所以就加载了四个字体

2、ExportPdfUtils

freemarker不支持远程模板,需要自定义,提供了接口URLTemplateLoader,可以根据自己需要实现不同的实现,我的工具类就简单的将一个http请求变为url,所以就不需要传模板名称了。

package cn.com.mjsoft.sub.common;import cn.com.mjsoft.sub.dto.PrintProfessionCardDto;
import com.alibaba.fastjson.JSONObject;
import com.itextpdf.text.pdf.BaseFont;
import com.lowagie.text.DocumentException;
import com.sun.istack.internal.NotNull;
import freemarker.cache.URLTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.xhtmlrenderer.layout.SharedContext;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Locale;public final class ExportPdfUtils {private Configuration cfg;private Template template;//字体文件夹路径private String fontDirectoryPaths = "/statics/fonts/";//字体文件名称:宋体-微软雅黑private String[] fontFileNames = new String[]{"simsun.ttc", "msyh.ttc", "msyhbd.ttc", "msyhl.ttc"};//本地模板文件夹private String baseTemplateDir = "/statics/template/";public ExportPdfUtils() {}/*** 特别注意项目本地图片需要单独在img上加上data:image/前缀** @param data* @param request* @return*/public byte[] createPdf(PrintProfessionCardDto data, HttpServletRequest request) {data.setStampPic(request.getSession().getServletContext().getRealPath(data.getStampPic()));JSONObject obj = (JSONObject) JSONObject.toJSON(data);PdfTemplate pdfTemplate = new PdfTemplate(data.getTemplatePath());return this.createPdf(obj, pdfTemplate, true, true);}public byte[] createPdf(JSONObject data, @NotNull PdfTemplate pdfTemplate, boolean isRemoteTemplate, boolean hasImage) {try (StringWriter writer = new StringWriter()) {cfg = new Configuration(Configuration.VERSION_2_3_23);cfg.setEncoding(Locale.CHINA, "UTF-8");//模板为远程文件if (isRemoteTemplate) {RemoteTemplateLoader templateLoader = new RemoteTemplateLoader(pdfTemplate.getTemplatePackagePath());cfg.setTemplateLoader(templateLoader);template = cfg.getTemplate("", "UTF-8");} else {//模板为项目本地文件cfg.setDirectoryForTemplateLoading(new File(pdfTemplate.getTemplatePackagePath()));template = cfg.getTemplate(pdfTemplate.getTemplateFileName(), "UTF-8");}// 将数据输出到html中template.process(data, writer);writer.flush();String html = writer.toString();return this.transStreamToPdf(html, hasImage);} catch (TemplateException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}return null;}private byte[] transStreamToPdf(String html, boolean hasImage) {try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {ITextRenderer renderer = new ITextRenderer();ITextFontResolver fontResolver = renderer.getFontResolver();for (int i = 0; i < fontFileNames.length; i++) {String fontPackagePath = ExportPdfUtils.class.getResource("/").getPath() + fontDirectoryPaths + fontFileNames[i];fontResolver.addFont(fontPackagePath, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);}renderer.setDocumentFromString(html);// 设置模板中的图片路径 (这里的images在resources目录下) 模板中img标签src路径需要相对路径加图片名 如<img src="data:images/xh.jpg"/>SharedContext sharedContext = renderer.getSharedContext();if (hasImage) {sharedContext.setReplacedElementFactory(new B64ImgReplacedElementFactory());sharedContext.getTextRenderer().setSmoothingThreshold(0);}renderer.layout();renderer.createPDF(out);renderer.finishPDF();out.flush();return out.toByteArray();} catch (DocumentException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return null;}class PdfTemplate {//本地模板:模板名称不能为空private String templateFileName;private String templatePackagePath;public PdfTemplate(String templatePackagePath) {this.templatePackagePath = templatePackagePath;}public PdfTemplate(String templateFileName, String templatePackagePath) {this.templateFileName = templateFileName;this.templatePackagePath = templatePackagePath;}public String getTemplateFileName() {return templateFileName;}public void setTemplateFileName(String templateFileName) {this.templateFileName = templateFileName;}public String getTemplatePackagePath() {return templatePackagePath;}public void setTemplatePackagePath(String templatePackagePath) {this.templatePackagePath = templatePackagePath;}}//自定义实现远程模板文件的获取final class RemoteTemplateLoader extends URLTemplateLoader {private String remoteTemplatePath;public RemoteTemplateLoader(String remoteTemplatePath) {this.remoteTemplatePath = remoteTemplatePath;}@Overrideprotected URL getURL(String s) {try {URL url = new URL(remoteTemplatePath);return url;} catch (MalformedURLException e) {e.printStackTrace();}return null;}}}

3、B64ImgReplacedElementFactory

由于我的项目不是maven项目,导致需要按默认获取webapp下的文件不可以,所以就自己实现了ITextRenderer
的html解析工厂类,主要是自定义了本地项目的附件获取方式;

    package cn.com.mjsoft.sub.common;import com.lowagie.text.BadElementException;
import com.lowagie.text.Image;
import org.w3c.dom.Element;
import org.xhtmlrenderer.extend.FSImage;
import org.xhtmlrenderer.extend.ReplacedElement;
import org.xhtmlrenderer.extend.ReplacedElementFactory;
import org.xhtmlrenderer.extend.UserAgentCallback;
import org.xhtmlrenderer.layout.LayoutContext;
import org.xhtmlrenderer.pdf.ITextFSImage;
import org.xhtmlrenderer.pdf.ITextImageElement;
import org.xhtmlrenderer.render.BlockBox;
import org.xhtmlrenderer.simple.extend.FormSubmissionListener;import java.io.IOException;/*** @description:* @author:zxp* @create:2021-12-30 14-09*/
public class B64ImgReplacedElementFactory implements ReplacedElementFactory {/*** 实现createReplacedElement 替换html中的Img标签** @param c         上下文* @param box       盒子* @param uac       回调* @param cssWidth  css宽* @param cssHeight css高* @return ReplacedElement*/public ReplacedElement createReplacedElement(LayoutContext c, BlockBox box, UserAgentCallback uac,int cssWidth, int cssHeight) {Element e = box.getElement();if (e == null) {return null;}String nodeName = e.getNodeName();// 找到img标签if (nodeName.equals("img")) {String attribute = e.getAttribute("src");FSImage fsImage;try {// 生成itext图像fsImage = buildImage(attribute, uac);} catch (BadElementException e1) {fsImage = null;} catch (IOException e1) {fsImage = null;}if (fsImage != null) {// 对图像进行缩放if (cssWidth != -1 || cssHeight != -1) {fsImage.scale(cssWidth, cssHeight);}return new ITextImageElement(fsImage);}}return null;}/*** 直接根据url获取项目本地图片或者三方服务器图片并生成itext图像* 主要是这里自定义* @param srcAttr 属性* @param uac     回调* @return FSImage* @throws IOException         io异常* @throws BadElementException BadElementException*/protected FSImage buildImage(String srcAttr, UserAgentCallback uac) throws IOException,BadElementException {FSImage fsImage;if (srcAttr.startsWith("data:image/")) {String imageName = srcAttr.substring("data:image/".length());//这里可以通过自定义方式获取文件//例如通过file的方式将外部的文件转换为流,然后将字节转换为image,这样就可以只提供一个外部文件的地址,将文件名称写入到模板中,每次仅仅修改模板就可以更改文件了。fsImage = new ITextFSImage(Image.getInstance(imageName));} else {fsImage = uac.getImageResource(srcAttr).getImage();}return fsImage;}/*** 实现remove** @param e 元素*/public void remove(Element e) {}/*** 实现reset*/public void reset() {}/*** 实现setFormSubmissionListener** @param formsubmissionlistener 监听*/public void setFormSubmissionListener(FormSubmissionListener formsubmissionlistener) {}
}

三、解决样式问题

1、主要是css3的某些样式不生效,所以尽量不使用css的样式
2、还有就是默认居中的问题,这里需要使用css3的样式解决,这样就可以去除页边距了;设置字体为微软雅黑,不然无法识别中文。

@page {margin: 0;}
body{font-family: "Microsoft YaHei";}

四、模板

我是用的是html,没有使用ftl,这个官网文档上有解释,这里贴上官方文档链接http://freemarker.foofun.cn/pgui_config_templateloading.html

总结:

这里就是我碰到的问题和解决方案,反正就是碰到什么问题,就会不断尝试去解决,期间我有几次都只想换方式解决了,后来想想还是尝试下好,不然换新的也可能会碰到更多的问题,最后终于解决了。

FreeMaker + ITextRenderer生成pdf相关推荐

  1. itext设置pdf的尺寸_freemark+ITextRenderer 生成PDF,设置pdf的页面大小

    [zz]matlab 求差集 matlab判断2个数组中不同元素--setdiff c = setdiff(A, B) 返回在A中有,而B中没有的值,结果向量将以升序排序返回.在集合论中,c = A ...

  2. html与css入门经典doc,HTML+CSS入门 flying-saucer如何利用HTML来生成PDF文件

    本篇教程介绍了HTML+CSS入门 flying-saucer如何利用HTML来生成PDF文件,希望阅读本篇文章以后大家有所收获,帮助大家HTML+CSS入门. < 1.导入maven依赖 9. ...

  3. 记-ItextPDF+freemaker 生成PDF文件---导致服务宕机

    摘要:已经上线的项目,出现服务挂掉的情况. 介绍:该服务是专门做打印的,业务需求是生成PDF文件进行页面预览,主要是使用ItextPDF+freemaker技术生成一系列PDF文件,其中生成流程有:解 ...

  4. itext html转pdf尺寸设置,如何设置PDF页面尺寸A4,当我们使用ITextRenderer生成从thymeleaf HTML模板PDF?...

    如何设置PDF页面尺寸A4,当我们使用ITextRenderer生成从thymeleaf HTML模板PDF? 我已经生成的PDF,但页面大小是不正确的,如何在JAVA设置页面大小A4 ITextRe ...

  5. 生成 PDF 全攻略【1】初体验

    经历过多少踩坑,翻看过多少类似博客,下载过多少版本的Jar,才能摸索出正确的代码书写方式,才能实现项目经理需求分析书中的功能点. 本文借一次 JavaEE 生成PDF的颠簸的实现过程,描述中小公司程序 ...

  6. 使用Flying-Saucer生成PDF中的条形码

    Flying-Saucer是一个不错的库,可以从Java应用程序中生成PDF文档. 只需生成一堆XHTML,然后将其放入渲染器中,然后使用iText生成所需的文档即可. 但是,当涉及条形码时,Flyi ...

  7. java根据pdf模版动态生成pdf

    java根据pdf模版动态生成pdf packagecom.utils;importjava.io.ByteArrayOutputStream;importjava.io.File;importjav ...

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

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

  9. Flying Saucer生成pdf报表

    使用Flying Saucer生成pdf报表: 1.首先看一下Flying Saucer的官方介绍: https://github.com/flyingsaucerproject/flyingsauc ...

最新文章

  1. 说一说网站与搜索引擎之间不得不知的联系
  2. linux的用户管理与权限学习总结
  3. oracle:sql查询
  4. 智能硬件的时代,嵌入式是否已经日薄西山
  5. 用户首选项NSUserDefaults
  6. Android FrameWork——ActivityManager框架
  7. 转-架构高性能网站秘笈(四)——反向代理缓存
  8. Charles的使用方法
  9. php毕设周记_(完整版)毕设周记
  10. 2021春招美团算法笔试题
  11. 数据库 查询计算机系姓王,数据库原理与应用课后实验三
  12. dubbo异常源码分析处理
  13. 优派 ELITE XG320Q、XG320U / UG 评测
  14. 多人在线编辑文档 开发_十个在线小工具,科研amp;工作必备神器!
  15. 虚拟机中如何给Ubuntu系统进行联网
  16. 气候变化如何影响致命的龙卷风?
  17. mark制图软件_Mac 都有哪些好用的绘图软件
  18. Java 之父求职被嫌年纪大
  19. mac看图软件哪个好用_办公记事软件哪个好?工作记事本便签app哪个好用
  20. 单台 MySQL 支撑不了这么多的并发请求,我们该怎么办?

热门文章

  1. 即计算机信息检索是指利用计算机,计算机信息检索技术布尔逻辑运算示意图.ppt...
  2. 【引语练习题】直接引语 转化为 间接宾语
  3. 【C语言】数据结构——树
  4. 磁盘序列号,磁盘ID,卷序列号的区别
  5. 苹果电脑重装苹果系统12版本u盘制作
  6. input默认值,点击清除,离开恢复
  7. 计算机硬件及应用评审,2018年东莞市计算机教育软件评审活动.docx
  8. 码农你看懂了,就发财了
  9. 在centos7.6编译kurento
  10. 大学生程序设计邀请赛(华东师范大学) 黑心啤酒厂