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

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/

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
flying-saucer-pdf是一个Java库,用于将HTML文档转换为PDF格式。它提供了一种简单的方式来生成高质量的PDF文件,可以用于生成报告、电子书、发票等各种类型的文档。 使用flying-saucer-pdf可以通过以下步骤来下载PDF工具类: 1. 首先,你需要在你的项目中添加flying-saucer-pdf的依赖。你可以在Maven或Gradle中添加以下依赖: Maven: ```xml <dependency> <groupId>org.xhtmlrenderer</groupId> <artifactId>flying-saucer-pdf</artifactId> <version>9.1.22</version> </dependency> ``` Gradle: ```groovy implementation 'org.xhtmlrenderer:flying-saucer-pdf:9.1.22' ``` 2. 下载完成后,你可以使用flying-saucer-pdf提供的API来生成PDF文件。首先,你需要创建一个`ITextRenderer`对象,然后将HTML内容加载到该对象中,并使用`createPDF()`方法将其转换为PDF文件。以下是一个简单的示例代码: ```java import org.xhtmlrenderer.pdf.ITextRenderer; public class PdfGenerator { public static void main(String[] args) throws Exception { String htmlContent = "<html><body><h1>Hello, World!</h1></body></html>"; ITextRenderer renderer = new ITextRenderer(); renderer.setDocumentFromString(htmlContent); renderer.layout(); String outputFile = "output.pdf"; renderer.createPDF(new FileOutputStream(outputFile)); System.out.println("PDF generated successfully!"); } } ``` 以上代码将生成一个包含"Hello, World!"标题的PDF文件,并将其保存为output.pdf。 希望这个简单的介绍能帮助到你!如果你有任何进一步的问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值