flying-saucer + iText + Freemarker实现pdf的导出, 支持中文、css以及图片
前言
项目中有个需求,需要将合同内容导出成pdf。上网查阅到了 iText , iText 是一个生成PDF文档的开源Java库,能够动态的从XML或者数据库生成PDF,同时还可以对文档进行加密,权限控制,并且还支持Java/C#等,但是iText本身提供的HTML解析器还是不够强大,许多HTML标签和属性无法识别,更悲催的是简单的CSS它不认识,排版调整样式让人头大。那么有没有什么方式能够支持css呢,又查阅到了 flying-saucer, flying-saucer也是导出PDF的一种解决方案,并且是基于iText的开源API,并且实现了CSS解析器,能够很好的支持CSS2.1,以及少量的CSS。最终解决方案定为: flying-saucer + iText + Freemarker。
具体实现
流程如下
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.yzb.lee</groupId>
<artifactId>itextpdf</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>itextpdf Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.20</version>
</dependency> <dependency>
<groupId>com.itextpdf.tool</groupId>
<artifactId>xmlworker</artifactId>
<version>5.5.1</version>
</dependency> <!-- 支持中文 -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
<!-- 支持css样式渲染 -->
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf-itext5</artifactId>
<version>9.0.3</version>
</dependency> <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency> <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>itextpdf</finalName>
</build>
</project>
1、html内容的输出
模版文件fileTemplate.html
<html>
<head>
<title>${title}</title>
<!-- link链接应该写文件服务器地址, 出于演示,这里用的localhost -->
<link type="text/css" rel="stylesheet" href="http://localhost:8080/itextpdf/css/pdf.css" />
<style>
@page {
size: 8.5in 11in;
@
bottom-center
{
content
:
"page "
counter(
page
)
" of "
counter(
pages
);
}
}
</style>
</head>
<body>
<h1>Just a blank page.</h1>
<div style="page-break-before: always;">
<div align="center">
<h1>${title}</h1>
<!-- src链接应该写文件服务器地址, 出于演示,这里用的localhost -->
<img alt="加载中..." src="http://localhost:8080/itextpdf/images/aloner.jpg" />
</div>
<table>
<tr>
<td><b>Name</b></td>
<td><b>Age</b></td>
<td><b>Sex</b></td>
</tr>
<#list userList as user>
<tr>
<td>${user.name}</td>
<td>${user.age}</td>
<td><#if user.sex = 1> male <#else> female </#if></td>
</tr>
</#list>
</table>
</div>
<div>
<a href="https://www.baidu.com/" target="_blank">百度</a>
</div>
</body>
</html>
动态数据的获取
public Map<String, Object> getContent() throws IOException {
// 从数据库中获取数据, 出于演示目的, 这里数据不从数据库获取, 而是直接写死
Map<String, Object> variables = new HashMap<String, Object>(3);
List<User> userList = new ArrayList<User>();
User tom = new User("Tom", 19, 1);
User amy = new User("Amy", 28, 0);
User leo = new User("Leo", 23, 1);
userList.add(tom);
userList.add(amy);
userList.add(leo);
variables.put("title", "用户列表");
variables.put("userList", userList);
return variables;
}
动态数据的绑定,html内容的输出
/**
* Generate html string.
*
* @param template
* the name of freemarker teamlate.
* @param variables
* the data of teamlate.
* @return htmlStr
* @throws Exception
*/
public static String generate(String template, Map<String, Object> variables)
throws Exception {
Configuration config = FreemarkerConfiguration.getConfiguation();
Template tp = config.getTemplate(template);
StringWriter stringWriter = new StringWriter();
BufferedWriter writer = new BufferedWriter(stringWriter);
tp.setEncoding("UTF-8");
tp.process(variables, writer);
String htmlStr = stringWriter.toString();
writer.flush();
writer.close();
return htmlStr;
}
2、pdf的导出
private void generatePdf(String htmlStr, OutputStream out)
throws IOException, DocumentException {
//final ServletContext servletContext = getServletContext(); Document document = new Document(PageSize.A4, 30, 30, 30, 30);
document.setMargins(30, 30, 30, 30);
PdfWriter writer = PdfWriter.getInstance(document, out);
document.open(); // html内容解析
HtmlPipelineContext htmlContext = new HtmlPipelineContext(
new CssAppliersImpl(new XMLWorkerFontProvider() {
@Override
public Font getFont(String fontname, String encoding,
float size, final int style) {
Font font = null;
if (fontname == null) {
//字体
String fontCn = getChineseFont();
BaseFont bf;
try {
//注意这里有一个,1
bf = BaseFont.createFont(fontCn+",1",
BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
font = new Font(bf, size, style);
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} }
return font;
}
})) {
@Override
public HtmlPipelineContext clone()
throws CloneNotSupportedException {
HtmlPipelineContext context = super.clone();
try {
ImageProvider imageProvider = this.getImageProvider();
context.setImageProvider(imageProvider);
} catch (NoImageProviderException e) {
}
return context;
}
}; // 图片解析
htmlContext.setImageProvider(new AbstractImageProvider() { // String rootPath = servletContext.getRealPath("/"); @Override
public String getImageRootPath() {
return "";
} @Override
public Image retrieve(String src) {
if (StringUtils.isEmpty(src)) {
return null;
}
try {
// String imageFilePath = new File(rootPath, src).toURI().toString();
Image image = Image.getInstance(src);
image.setAbsolutePosition(400, 400);
if (image != null) {
store(src, image);
return image;
}
} catch (Throwable e) {
e.printStackTrace();
}
return super.retrieve(src);
}
});
htmlContext.setAcceptUnknown(true).autoBookmark(true)
.setTagFactory(Tags.getHtmlTagProcessorFactory()); // css解析
CSSResolver cssResolver = XMLWorkerHelper.getInstance()
.getDefaultCssResolver(true);
cssResolver.setFileRetrieve(new FileRetrieve() {
@Override
public void processFromStream(InputStream in,
ReadingProcessor processor) throws IOException {
try (InputStreamReader reader = new InputStreamReader(in,
CHARSET_NAME)) {
int i = -1;
while (-1 != (i = reader.read())) {
processor.process(i);
}
} catch (Throwable e) {
}
} // 解析href
@Override
public void processFromHref(String href, ReadingProcessor processor)
throws IOException {
// InputStream is = servletContext.getResourceAsStream(href);
URL url = new URL(href);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5 * 1000);
InputStream is = conn.getInputStream(); try (InputStreamReader reader = new InputStreamReader(is,
CHARSET_NAME)) {
int i = -1;
while (-1 != (i = reader.read())) {
processor.process(i);
}
} catch (Throwable e) {
e.printStackTrace();
}
}
}); HtmlPipeline htmlPipeline = new HtmlPipeline(htmlContext,
new PdfWriterPipeline(document, writer));
Pipeline<?> pipeline = new CssResolverPipeline(cssResolver,
htmlPipeline);
XMLWorker worker = null;
worker = new XMLWorker(pipeline, true);
XMLParser parser = new XMLParser(true, worker,
Charset.forName(CHARSET_NAME));
try (InputStream inputStream = new ByteArrayInputStream(
htmlStr.getBytes())) {
parser.parse(inputStream, Charset.forName(CHARSET_NAME));
}
document.close();
}
3、生成的pdf
注意点
1、博客中的代码不是一个完整工程,只依赖博客中的代码是运行不起来的;
2、文件路径的获取,本地文件与远程文件的获取是有区别的, 另外本地文件的获取又存在多种方式;
3、完整工程地址:itextpdf,仔细阅读readme.txt, 工程中存在多个版本, 而本博客对应的是版本4;
4、推荐将SIMSUN.TTC放到工程中, 这就不依赖操作系统了, 可移植性更强;
参考
freemarker+Flying sauser +Itext 整合生成PDF
flying-saucer + iText + Freemarker实现pdf的导出, 支持中文、css以及图片的更多相关文章
- iText + Freemarker实现pdf的导出,支持中文、css以及图片,页眉页脚,页眉添加图片
本文为了记录自己的实现过程,具体的实现步骤是参考博文 https://www.cnblogs.com/youzhibing/p/7692366.html 来实现的,只是在他的基础上添加了页眉页脚及页眉 ...
- [Web Pdf] flying-saucer + iText + Freemarker生成pdf 跨页问题
转载于: https://blog.csdn.net/qq_31980421/article/details/79662988 flying-saucer + iText + Freemarker实 ...
- Java iText+FreeMarker生成PDF(HTML转PDF)
1.背景 在某些业务场景中,需要提供相关的电子凭证,比如网银/支付宝中转账的电子回单,签约的电子合同等.方便用户查看,下载,打印.目前常用的解决方案是,把相关数据信息,生成对应的pdf文件返回给用户. ...
- JS导出PDF插件(支持中文、图片使用路径)
在WEB上想做一个导出PDF的功能,发现jsPDF比较多人推荐,遗憾的是不支持中文,最后找到pdfmake,很好地解决了此问题.它的效果可以先到http://pdfmake.org/playgroun ...
- Java使用Flying Saucer实现HTML代码生成PDF文档
1.需要的jar包:org.xhtmlrenderer.flying-saucer-pdf-itext5,Maven依赖如下: <dependency> <groupId>or ...
- PDF 生成插件 flying saucer 和 iText
最近的项目中遇到了需求,用户在页面点击下载,将页面以PDF格式下载完成供用户浏览,所以上网找了下实现方案. 在Java世界,要想生成PDF,方案不少,所以简单做一个小结吧. 在此之前,先来勾画一下我心 ...
- [itext]Java生成PDF文件
一.前言 最近在做也导出试卷的功能,刚开始是导出为doc,可是导出来格式都有变化,最后说直接将word转为pdf,可是各种不稳定,各种报错.最后想到直接将文件写入pdf(参考:http://www.c ...
- Java利用模板生成pdf并导出
1.准备工作 (1)Adobe Acrobat pro软件:用来制作导出模板 (2)itext的jar包 2.开始制作pdf模板 (1)先用word做出模板界面 (2)文件另存为pdf格式文件 (3) ...
- 使用iText库创建PDF文件
前言 译文连接:http://howtodoinjava.com/apache-commons/create-pdf-files-in-java-itext-tutorial/ 对于excel文件的读 ...
随机推荐
- 团队作业8----第二次项目冲刺(beta阶段)5.23
Day5-05.23 1.每日会议 会议内容: 1.组长林乔桦对昨日的工作进行了总结并且安排今日的任务. 2.潘益靖副组长说明昨日任务的完成情况. 3.组员对昨天的各项工作进行了汇报以及对今天的工作进 ...
- 201521123013 《Java程序设计》第7周学习总结
1. 本章学习总结 2. 书面作业 Q1.ArrayList代码分析 1.1 解释ArrayList的contains源代码 public boolean contains(Object o) { r ...
- Java程序设计第三周学习总结
1. 本周学习总结 2. 书面作业 Q1.代码阅读 public class Test1 { private int i = 1;//这行不能修改 private static int j = 2; ...
- 201521123063 JAVA程序设计 第二周学习总结
1.本周学习重点(2.27-3.5) java中的数组 以二维数组为例,数组名为scores,则 (1)先声明数组 int[][] scores;或int scores[][];或int[] scor ...
- 201521123051 《Java程序设计》 第二周学习总结
1. 本周学习总结 1.学会使用码云:学会如何将项目同步到码云中以及从码云上的项目保存到本地. 2.各数据类型的使用. 3.运算符和表达式的使用. 4.string创建之后不可在修改. 5.Java程 ...
- Servlet的生命周期与运行原理
Servlet的生命周期: 1 加载classLoader 2 实例化 new 3 初始化 init(ServletConfig) 4 处理请求 service doGet d ...
- 框架应用:Spring framework (五) - Spring MVC技术
软件开发中的MVC设计模式 软件开发的目标是减小耦合,让模块之前关系清晰. MVC模式在软件开发中经常和ORM模式一起应用,主要作用是将(数据抽象,数据实体传输和前台数据展示)分层,这样前台,后台,数 ...
- openfire:Openfire源代码在eclipse中的运行配置 + 与spark结合进行二次开发
1.下载源代码:http://www.igniterealtime.org/downloads/source.jsp 2.把源代码解压出的openfire_src文件夹放至eclipse workpl ...
- Eclipse rap 富客户端开发总结(14) :rap 图片、数据缓存处理
一.概述 在进行了 rap 的基本学习之后,您对 rap 的理解是否进入了更高的一个层次呢,个人觉得,对学习 rap 的人来说,进行 rap 的学习是一个探索的过程,在编程中不断的对其进行理解和分析, ...
- 如何使用fiddler抓取https请求(PC和移动端)
最近做一个抓取移动端app接口,并执行评论,收藏的接口功能测试.怎么搞/(ㄒoㄒ)/~~ 按照老思路试一试,第一步还是要用fiddler来帮忙获取接口信息! 一.基本的抓取http请求设置: 1.cm ...