PDF导出工具有itext,但是itext对中文支持不好,还有样式CSS支持也不好,使用IReport比较复杂,上手不太容易,怎么办?

幸好有Flying-Saucer这个项目,帮助我们解决了以上问题!Flying-Saucer最重要的是很方便,不需要使用IReport的复杂操作,只会写html就能够做PDF导出的模板。

使用freemarker的思路

1、编写ftl模板

2、使用freemarker生成html

3、根据生成的html在生成PDF

来一张图片,否则无图无真相

项目依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<properties>
<servlet>3.1.0</servlet>
<freemarker>2.3.22</freemarker>
<flying-saucer>9.0.3</flying-saucer>
</properties>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>${freemarker}</version>
</dependency>
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf</artifactId>
<version>${flying-saucer}</version>
</dependency>
</dependencies>

依赖关系图

项目结构图

主要的操作类

PdfUtils

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package org.xdemo.example.pdf;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.xhtmlrenderer.pdf.ITextRenderer;
import com.lowagie.text.DocumentException;
import freemarker.core.ParseException;
import freemarker.template.MalformedTemplateNameException;
import freemarker.template.TemplateException;
import freemarker.template.TemplateNotFoundException;
/**
 * PDF生成工具类
 * @author Goofy <a href="http://www.xdemo.org">http://www.xdemo.org</a>
 *
 */
public class PdfUtils {
public static void main(String[] args) {
try {
Map<Object, Object> o=new HashMap<Object, Object>();
o.put("name""http://www.xdemo.org/");
String path=PdfHelper.getPath();
generateToFile(path, "resources/tpl.ftl",path+"resources/", o, "D:\\xdemo.pdf");
catch (Exception e) {
e.printStackTrace();
}
}
/**
 * 生成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 {
String html=PdfHelper.getPdfContent(ftlPath, ftlName, data);
OutputStream out = null;
ITextRenderer render = null;
out = new FileOutputStream(outputFile);
render = PdfHelper.getRender();
render.setDocumentFromString(html);
if(imageDiskPath!=null&&!imageDiskPath.equals("")){
//html中如果有图片,图片的路径则使用这里设置的路径的相对路径,这个是作为根路径
render.getSharedContext().setBaseURL("file:/"+imageDiskPath);
}
render.layout();
render.createPDF(out);
render.finishPDF();
render = null;
out.close();
}
/**
 * 生成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 TemplateNotFoundException, MalformedTemplateNameException, ParseException, IOException, TemplateException, DocumentException{
String html=PdfHelper.getPdfContent(ftlPath, ftlName, data);
OutputStream out = null;
ITextRenderer render = null;
out = response.getOutputStream();
render = PdfHelper.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;
}
}

辅助类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package org.xdemo.example.pdf;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Locale;
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;
/**
 * PDF生成辅助类
 * @author Goofy <a href="http://www.xdemo.org">http://www.xdemo.org</a>
 *
 */
@SuppressWarnings("deprecation")
public class PdfHelper {
public static ITextRenderer getRender() throws DocumentException, IOException {
ITextRenderer render = new ITextRenderer();
String path = getPath();
//添加字体,以支持中文
render.getFontResolver().addFont(path + "resources/ARIALUNI.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
render.getFontResolver().addFont(path + "resources/SIMSUN.TTC", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
return render;
}
//获取要写入PDF的内容
public static String getPdfContent(String ftlPath, String ftlName, Object o) throws TemplateNotFoundException, MalformedTemplateNameException, ParseException, IOException, TemplateException {
return useTemplate(ftlPath, ftlName, o);
}
//使用freemarker得到html内容
public static String useTemplate(String ftlPath, String ftlName, Object o) throws TemplateNotFoundException, MalformedTemplateNameException, ParseException, IOException, TemplateException {
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;
}
/**
 * 获取类路径
 * @return
 */
public static String getPath(){
return PdfHelper.class.getResource("").getPath().substring(1);
}
}

模板文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<style type="text/css">
body {
margin-left: 45px;
margin-right: 45px;
font-family: Arial Unicode MS;
font-size: 10px;
}
table {
margin: auto;
width: 100%;
border-collapse: collapse;
border: 1px solid #444444;
}
th,td {
border: 1px solid #444444;
font-size: 10px;
margin-left: 5px;
}
.mcContent {
line-height: 180%;
padding: 20px;
}
.logo {
text-align: center;
}
.title {
text-align: center;
font-weight: bold;
font-size: 20px;
}
.notes {
font-weight: normal;
margin-left: 5px;
margin-right: 5px;
line-height: 18px;
}
.text_content {
margin-left: 5px;
margin-right: 5px;
line-height: 18px;
}
.sum_insured_first_row {
width: 20%;
}
.sum_insured_span {
font-size: 10px;
}
.special_agreements_div {
page-break-before: always;
font-size: 14px;
margin-top: 20px;
}
.special_agreements_div .special_agreements {
font-size: 18px;
font-weight: bold;
}
.title_right {
width: 100%;
margin: 0 auto;
}
.title_right p {
text-align: left;
margin: 0;
margin-left: 50%;
padding: 0;
}
@page {
size: 8.5in 11in;
@
bottom-center
{
content
:
"page "
counter(
page
)
" of  "
counter(
pages
);
}
.signature {
margin: 0 auto;
clear: both;
font-size: 16px;
font-weight: bold;
}
.signature_table {
/*     font-size: 16px; */
font-weight: bold;
}
</style>
</head>
<body>
作者:<a href="http://www.xdemo.org/">http://www.xdemo.org/</a>
<div>
<p>你好:${name}</p>
<div class="logo"><!--这里的图片使用相对与ITextRenderer.getSharedContext().setBaseURL("file:/"+imageDiskPath);的路径-->
图片支持<img src="logo1.png" />
</div>
<div>
<p>Hello PDF: 中文支持</p>
<div style="border:1px solid red;color:red;">
样式支持,红边框,红字
</div>
<div style="border:10px solid blue;color:blue;">
样式支持,蓝色10像素的边框,蓝字
</div>
<hr/>
<table>
<tr style="background:gray;">
<th>A</th>
<th>B</th>
<th>C</th>
<th>D</th>
</tr>
<tr>
<td>100</td>
<td>29</td>
<td>32</td>
<td>43</td>
</tr>
<tr>
<td>100</td>
<td>29</td>
<td>32</td>
<td>43</td>
</tr>
<tr>
<td>100</td>
<td>29</td>
<td>32</td>
<td>43</td>
</tr>
<tr>
<td>100</td>
<td>29</td>
<td>32</td>
<td>43</td>
</tr>
<tr>
<td>100</td>
<td>29</td>
<td>32</td>
<td>43</td>
</tr>
</table>
</div>
</div>
</body>
</html>

注意

本工具类提供了两种字体支持中文,所以定义样式的时候字体只能用:simsun或者arial unicode MS,否则中文显示不出来,如需其他字体另行添加),另外请注意图片的路径问题,html中z如果有图片,图片的路径则使用这里设置的路径的相对路径,这个是作为根路径,如

1
2
3
4
<div class="logo">
    <!--这里的图片使用相对与ITextRenderer.getSharedContext().setBaseURL("file:/"+imageDiskPath);的路径-->
图片支持<img src="logo1.png" />
</div>

如果需要PDF的下载,可以通过generateToServletOutputStream这个方法来获取PDF的输出流,然后通过response写到客户端去

转载请注明来源: http://www.xdemo.org/flying-saucer-html-freemarker-pdf/

Flying-Saucer使用HTML或者FTL(Freemarker模板)生成PDF相关推荐

  1. 使用HTML或者FTL(Freemarker模板)生成PDF 示例2

    2. html2pdf 使用html或者ftl生产pdf 引入 pom.xml <dependency><groupId>com.itextpdf</groupId> ...

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

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

  3. freemarker模板生成pdf文件

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

  4. FreeMarker 模板生成 PDF电子凭证/图片

    一.场景 在某些业务场景中,需要提供相关的电子凭证,比如网银/支付宝中转账的电子回单,签约的电子合同等.方便用户查看,下载,打印.目前常用的解决方案是,把相关数据信息,生成对应的pdf文件返回给用户. ...

  5. iText通过FreeMarker模板生成PDF解决方案

    首先定义一个HTML模板,通过后台数据填充,生成PDF文件. 目录 一.所需依赖 二.生成工具类 三.准备模板 四. 字体和模板放置的位置 五.生成PDF文件预览 一.所需依赖 <!-- pdf ...

  6. 利用 freemarker 模板生成 word 小结

    在企业级开发时,不可避免的会遇到生成 word 文档的需求,有两种常用的方案,1.使用 Apache POI 在后台通过代码生成 word 文档:2.使用模板生成 word 文档.第二种方法比较简单, ...

  7. JavaWeb(14) 页面静态化之使用freemarker模板生成一个html静态页面

    题外话:        页面静态化(展示数据从JSP页面变成HTML页面)实现方式-->模板技术   从本质上来讲,模板技术是一个占位符动态替换技术.一个完整的模板技术需要四个元素:①模板语言( ...

  8. java利用Freemarker模板生成格式友好的doc或者docx文档

    之前写过一篇利用Freemarker模板生成doc的博客,不过那个博客有点缺陷,不支持生成docx格式的文档.所以,这里补充一篇,生成docx或doc格式的文档以具体的docx模板或者doc模板为主. ...

  9. freemarker根据静态模板和动态模板生成PDF与Word

    背景介绍:最近在做老旧项目的二次开发,所以用到了freemarker去生成PDF和Word,涉及到打印静态模板与动态模板.查看了这方面的资料发现大都不全,似是而非.废话不多说,上案例. freemar ...

最新文章

  1. python语言怎么用-Python语言应用解析,如何入门学Python?
  2. SharePoint Portal Server与SharePoint Services之间的关系
  3. MySQL 不落地迁移、导入 PostgreSQL - 推荐 rds_dbsync
  4. Mysql的建表规范与注意事项
  5. JavaScript实现combinationSum组合和算法(附完整源码)
  6. 从0-1背包问题学习回溯法、分支界限法、动态规划
  7. 1100: 求组合数(函数专题)
  8. java 堆排序方式_幾種排序方式的java實現(02:希爾排序,歸並排序,堆排序)
  9. 向量二次规划matlab,MATLAB中使用Opti Toolbox的混合整数二次规划
  10. 引入react文件报错_React Native常见问题(一)
  11. C语言控制台窗口图形界面编程(六):光标操作
  12. oracle财务系统表,Oracle ERP 财务模块表结构.ppt
  13. 五分钟轻松搞定产品需求文档!这可能史上最全PRD文档模板
  14. iphone5s已停用连接itunes怎么办?苹果5s已停用连接itunes解决方法
  15. 十进制,二进制,八进制,十六进制的解意和详细转换
  16. 清华大学计算机竞赛自主招生,清华大学自主招生竞赛有哪些要求
  17. 2022-11-18 mysql列存储引擎-assert failed on i < m_idx.size() at rc_attr.h:342-问题分析
  18. 删除外键的sql语句
  19. ITIL及ITSS相关概念介绍
  20. Java枚举是什么?关于Java枚举的一些理解

热门文章

  1. 亮相Google I/O,字节跳动是这样应用Flutter的
  2. 农村信用社计算机基础知识,农村信用社计算机基础知识题五
  3. 如何加速./mk snod打包
  4. 小鸟 java_java 飞翔小鸟源码
  5. k8s简单集群搭建和应用(包括虚拟机的开启)①
  6. 故宫元宵节首开夜场,票务系统HTTPS加密护航 1
  7. 解决uniapp map遮盖遮罩层
  8. ubuntu 使用GParted对Ubuntu /dev/sda1进行磁盘扩容
  9. 第四章第四节数据资产盘点-数据资产梳理
  10. 容器亲和、反亲和、污点、容忍以及驱逐的介绍