最近的项目中遇到了需求,用户在页面点击下载,将页面以PDF格式下载完成供用户浏览,所以上网找了下实现方案。

在Java世界,要想生成PDF,方案不少,所以简单做一个小结吧。

在此之前,先来勾画一下我心中比较理想的一个解决方案。在企业应用中,碰到的比较多的PDF的需求,可能是针对某个比较典型的具备文档特性的内容,导出成为PDF进行存档。由于我们现在往往使用一些开源框架,诸如ssh来构建我们的应用,所以我们相对熟悉的方案是针对具体的业务逻辑设计实体,使用开源框架来实现我们的业务逻辑。而PDF的导出,最好不要破坏现有的程序框架,甚至能复用我们业务逻辑层的代码。因为如果把PDF作为一种特殊的表现形式的话,实际上它有点类似模板。最佳的情况,是我们能够通过编写某种模板,把PDF的大概样子确定下来,然后把数据和模板做一次整合,得到最后的结果

带着这个目标,开始在网上搜索解决方案。也找到了一些方案,下面简单小结一下:

Jasper Report

看到的市面上采用的最多的方案,是Jasper Report。相关的文档也很多,不过很杂,需要完全掌握,我认为还是有些坡度和时间的。这个时间和坡度我认为主要来自于对iReport这个IDE的反复尝试,对里面的每个属性的摸索。

Jasper Report的设计思路,本身是不违反我上面所说的初衷的。因为我们的努力方向是先生成模板,然后得到数据,最后将两者整合得到结果。但是Jasper Report的问题在于,其生成模板的方式过于复杂,即使有IDE的帮助,我们还是需要对其中的众多规则有所了解才行,否则就会给调试带来极大的麻烦。

所以,我认为Jasper Report是一个半调子方案,这种强依赖于IDE进行可视化编辑的方式令我很不爽。同时,由此带来的诸多的限制,相信也让很多使用者颇为头疼。在经历了一番痛苦的挣扎后,决定放弃使用这种方案。

iText

其实Jasper Report是基于iText的。于是有的人会说,那么直接使用iText不是一种倒退么?的确,直接使用iText似乎就需要直接使用原生的API进行编程了。不过幸好iText其实提供了一些方便的API,通过使用这些API,我们可以直接将HTML代码转化成iText可识别的Document对象,从而导出PDF文档。

java代码:

 import java.io.FileOutputStream;
import java.io.FileReader;
import java.util.ArrayList; import com.lowagie.text.Document;
import com.lowagie.text.Element;
import com.lowagie.text.html.simpleparser.HTMLWorker;
import com.lowagie.text.html.simpleparser.StyleSheet;
import com.lowagie.text.pdf.PdfWriter; public class MainClass {
public static void main(String[] args) throws Exception {
Document document = new Document();
StyleSheet st = new StyleSheet();
st.loadTagStyle("body", "leading", "16,0");
PdfWriter.getInstance(document, new FileOutputStream("html2.pdf"));
document.open();
ArrayList p = HTMLWorker.parseToList(new FileReader("example.html"), st);
for (int k = 0; k < p.size(); ++k)
document.add((Element) p.get(k));
document.close();
}
}
 

这是从网上找到的一个例子。从代码中,我们可以看到,iText本身提供了一个简单的HTML的解析器,它可以把HTML转化成我们需要的PDF的document。

有了这个东西,基本上我的目标就能达成一大半了。接下来我的任务就是根据实际情况去编写HTML代码,然后扔进这个方法,就OK了。而真正的HTML代码,我们则可以在这里使用真正的模板技术,Freemarker或者Velocity去生成我们所需要的内容。当然,这已经是我们熟门熟路的东西了。

正当我觉得这个方案基本能符合我的要求的时候,我也同样找到了它的很多弱项:

1. 无法识别很多HTML的tag和attribute(应该是iText的HTMLParser不够强大) 
2. 无法识别CSS

如果说第一点我还可以勉强接受的话,那么第二点我就完全不能接受了。无法识别简单的CSS,就意味着HTML失去了最基本的活力,也无法根据实际要求调整样式。

所以这种方案也必然无法成为我的方案。

flying sauser

在这种情况下,我几乎已经燃起了自己编写一个支持CSS解析的HTML Parser的想法。幸好,在一个非常偶然的情况下,我在google中搜到了这样一个开源项目,它能够满足我的一切需求。这就是flying sauser,项目主页是:https://xhtmlrenderer.dev.java.net/

项目的首页非常吸引人:An XML/XHTML/CSS 2.1 Renderer。这不正是我要的东西么?

仔细再看里面的文档:

引用
Flying Saucer is an XML/CSS renderer, which means it takes XML files as input, applies formatting and styling using CSS, and generates a rendered representation of that XML as output. The output may go to the screen (in a GUI), to an image, or to a PDF file. Because we believe most people will be interested in re-using their knowledge of web layout, our main target for content is XHTML 1.0 (strict), an XML document format that standardizes HTML.

完美了。这东西能解析HTML和CSS,而且能输出成image,PDF等格式。哇!我们来看看sample代码(代码丑陋,不过已经能说明问题了): 
java代码:

运行,成功!实在太简单了!API帮你完成了一切!

有了这个东西,我们就可以将PDF的生成流程变成这样:

1) 编写Freemarker或者Velocity模板,打造HTML,勾画PDF的样式(请任意使用CSS)

2) 在你的业务逻辑层引入Freemarker的引擎或者Velocity的引擎,并将业务逻辑层中可以获取的数据和模板,使用引擎生成最终的内容

3) 将我上面的sample代码做简单封装后,调用,生成PDF

这样,我想作为一个web程序员来说,上面的3点,都不会成为你的绊脚石。你可以轻松驾驭PDF了。

在Flying Saucer的官方文档中,有一些Q&A,可以解决读者们大部分的问题。包括PDF的字体、PDF的格式、Image如何处理等等。大家可以尝试着去阅读。

还有一篇文章,好像是作者写的,非常不错:http://today.java.net/pub/a/today/2007/06/26/generating-pdfs-with-flying-saucer-and-itext.html

Freemarker+Flying sauser +Itext 整合生成PDF

Freemarker、Flying sauser 、Itext ,这三个框架的作用就不详细介绍了,google一下就知道了。

Itext提供了很多底层的API,让我们可以用java代码画一个pdf出来,但是很不灵活,布局渲染代码都hard code 进java类里面了。

当需求发生改变时,哪怕只需要更改一个属性名,我们都要重新修改那段代码,很不符合开放关闭的原则。想到用模版来做渲染,但自己实现起来比较繁琐,然后google了下,找到了用freemarker做模版,Flying sauser 照着模版做渲染,让Itext做输出生成PDF的方案。

freemarker和itext都比较熟悉了,Flying sauser 第一次听说,看完官方的user guide(http://flyingsaucerproject.github.com/flyingsaucer/r8/guide/users-guide-R8.html)后,自己着手做了个demo实践:

测试数据模型:

java代码:

 package com.jeemiss.pdfsimple.entity;   

 public class User {   

     private String name;
private int age;
private int sex; /**
* Constructor with all fields
*
* @param name
* @param age
* @param sex
*/
public User(String name, int age, int sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
} /////////////////////// getter and setter /////////////////////////////////////////// public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
}

java代码:

 package com.jeemiss.pdfsimple.freemarker;   

 import freemarker.template.Configuration;   

 public class FreemarkerConfiguration {   

     private static Configuration config = null;   

     /**
* Static initialization.
*
* Initialize the configuration of Freemarker.
*/
static{
config = new Configuration();
config.setClassForTemplateLoading(FreemarkerConfiguration.class, "template");
} public static Configuration getConfiguation(){
return config;
} }
 

html生成器:

java代码:

 package com.jeemiss.pdfsimple.generator;   

 import java.io.BufferedWriter;
import java.io.StringWriter;
import java.util.Map;
import com.jeemiss.pdfsimple.freemarker.FreemarkerConfiguration;
import freemarker.template.Configuration;
import freemarker.template.Template; public class HtmlGenerator { /**
* 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;
} }
 

pdf生成器:

java代码:

用来做测试的ftl模版,用到部分css3.0的属性来控制pdf强制分页和输出分页信息

html代码:

 <html>
<head>
<title>${title}</title>
<style>
table {
width:100%;border:green dotted ;border-width:2 0 0 2
}
td {
border:green dotted;border-width:0 2 2 0
}
@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>
</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>
</body>
</html>
 

最后写个测试用例看看:

java代码:

 package com.jeemiss.pdfsimple.test;   

 import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import com.jeemiss.pdfsimple.entity.User;
import com.jeemiss.pdfsimple.generator.HtmlGenerator;
import com.jeemiss.pdfsimple.generator.PdfGenerator; public class TestCase
{
@Test
public void generatePDF() {
try{
String outputFile = "C:\\sample.pdf";
Map<String,Object> variables = new HashMap<String,Object>(); 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", "User List");
variables.put("userList", userList); String htmlStr = HtmlGenerator.generate("sample.ftl", variables); OutputStream out = new FileOutputStream(outputFile);
PdfGenerator.generate(htmlStr, out); }catch(Exception ex){
ex.printStackTrace();
} }
}

到C盘下打开sample.pdf ,看看输出的结果:

flying saucer 使用中的一些问题 (java导出pdf)

flying saucer(源代码托管在githubhttps://github.com/flyingsaucerproject/flyingsaucer)是java导出pdf的一种解决方案,最早是从downpour老大的文章里看到它:http://www.iteye.com/topic/509417 ,感觉比之前的iText好用许多,它可以解析css,即我将页面先设置好,然后传递给它,它既可以给我生成一个pdf出来,跟页面一样,当时感觉很酷,于是就研究了一下,现在项目中也用到了,效果还不错。
   
     优点很明显,之前也提到了,可以解析css,这样很方便,大大的减少了工作量。pdf加水印也变得很简单——只需为body设置一个background-image即可。
     说说使用中需要注意的一些问题吧: 
[list=1]

    • 中文换行问题
         老外做的东西,没有考虑到中文问题。默认提供的包里,中文不会换行,有人修改了源代码,解决了这个问题,重新编译好的包在附件里,可以下载。需要注意的是,在官网提供的jar包里,有两个包,一个是core-renderer.jar,另一个是core-renderer-minimal.jar。引用时,只需引用前者就行。有人曾经说用这个重新编译后的包替换了原来的包之后,不起作用,原因就在此。

      中文换行包下载地址:http://community.csdn.net/detail/shanliangliuxing

      另外,想要中文换行,如果是table,那么table 的style必须加上这句话

      html代码:

       

      css路径问题 
           在一个java project里,使用相对css路径是可以的,效果也都不错。但在java web project里,使用css相对路径是不可以的(最起码这里困扰了我很久,差点就放弃flying saucer了)。例如,我有一个模板叫addOne.jsp,里面引用到了某个css,就应该这样写(windows)

      jHTML代码:

    •  <link href="file:///D|/project/WebContent/commons/css/module-pdf.css" rel="stylesheet" type="text/css" />
    • 只有这样写了之后,它才能找到这个css,很诡异。每次换了机器之后都要改路径,很麻烦。

    • 中文字体问题
         downpour老大在它那篇文章里提到了怎样处理中文字体的,他可能高估了许多人的水平。其实说起来,很简单,就两点:一是在java代码里引用字体,二是在页面上引用字体。
    • 引用字体:
    • java代码:
    •  
 // 解决中文支持问题
ITextFontResolver fontResolver = renderer.getFontResolver();
fontResolver.addFont("C:/Windows/Fonts/arialuni.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);

这里引用了arialuni.ttf字体,它位于C盘windows/fonts文件夹下,将它引用后,还需要在页面上使用这个字体

html代码:

这里的Arial Unicode MS 即刚才 的arialuni.ttf字体的名字,换了其它字体后要注意修改这里的名称。这样才可以在pdf中显示中文。 
许多人有这样一个问题——按照以上两个步骤做了之后,页面中还是没有中文,这时,请检查你引用的css文件,其中一定设置了其它字体,只需将它去掉即可

缺点:
我在使用中发现,flying saucer不支持富文本,如果用到了KindEditor此类富文本编辑器,
还要将其中的内容转化成pdf,那对flying saucer来说就是个灾难。会报一堆错误,目前我还没有找到解决方案。还好这次项目中不是必须使用富文本编辑器,对于有此类需求的同学来说,请慎重选择flying saucer。另外,flying saucer严格遵守html规则,一个小小的错误,都会导致它报错。诸如
html代码:

此类的html代码在jsp中是不会有问题的,可是flying saucer却会报错,曾经这个问题导致我花了一小时时间来寻找问题所在。不过很难说这到底是缺点还是优点

最后贴一个较完整的例子:

我使用spring mvc,在controller里

java代码:

 @RequestMapping("/pdf/{projectId}")
public ModelAndView generatePdf(HttpServletRequest request,
HttpServletResponse response, @PathVariable
String projectId) {
Project project = this.projectService.getProjectById(projectId);
ModelAndView mav = new ModelAndView();
if (project == null) {
mav.setViewName("forward:/error/page-not-found");
return mav;
}
//中文需转义
String pdfName = "pdfName"; response.setHeader("Content-disposition", "attachment;filename="+pdfName;
response.setContentType("application/pdf");
OutputStream os = response.getOutputStream();
ITextRenderer renderer = new ITextRenderer();
//指定模板地址
renderer.setDocument("http://localhost/project/preview/"+projectId); ITextFontResolver fontResolver = renderer.getFontResolver();
if (StringUtils.isOSWindow())
fontResolver.addFont("C:/Windows/Fonts/ARIALUNI.TTF",
BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
else
fontResolver.addFont("/usr/share/fonts/TTF/ARIALUNI.TTF",
BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
renderer.layout();
renderer.createPDF(os);
os.close(); return null;
} @RequestMapping("/preview/{projectId}")
public ModelAndView pdf(@PathVariable
String projectId) {
Project project = this.projectService.getProjectById(projectId);
ModelAndView mav = new ModelAndView();
if (project == null) {
mav.setViewName("forward:/error/page-not-found");
return mav;
}
mav.setViewName("pdf");
mav.addObject("project",project);
return mav;
}

jsp页面如下

html代码:

 @RequestMapping("/pdf/{projectId}")
public ModelAndView generatePdf(HttpServletRequest request,
HttpServletResponse response, @PathVariable
String projectId) {
Project project = this.projectService.getProjectById(projectId);
ModelAndView mav = new ModelAndView();
if (project == null) {
mav.setViewName("forward:/error/page-not-found");
return mav;
}
//中文需转义
String pdfName = "pdfName"; response.setHeader("Content-disposition", "attachment;filename="+pdfName;
response.setContentType("application/pdf");
OutputStream os = response.getOutputStream();
ITextRenderer renderer = new ITextRenderer();
//指定模板地址
renderer.setDocument("http://localhost/project/preview/"+projectId); ITextFontResolver fontResolver = renderer.getFontResolver();
if (StringUtils.isOSWindow())
fontResolver.addFont("C:/Windows/Fonts/ARIALUNI.TTF",
BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
else
fontResolver.addFont("/usr/share/fonts/TTF/ARIALUNI.TTF",
BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
renderer.layout();
renderer.createPDF(os);
os.close(); return null;
} @RequestMapping("/preview/{projectId}")
public ModelAndView pdf(@PathVariable
String projectId) {
Project project = this.projectService.getProjectById(projectId);
ModelAndView mav = new ModelAndView();
if (project == null) {
mav.setViewName("forward:/error/page-not-found");
return mav;
}
mav.setViewName("pdf");
mav.addObject("project",project);
return mav;
}

使用flyingsaucer将网页转换为pdf之中文问题彻底解决

前几天遇到个导出pdf的需求,在网络上查找了一下java导出pdf的方案.多数人推荐使用iText,研究了一下,感觉直接写pdf的方法太笨,可维护性差,一旦pdf格式要变化改起来很费劲.还有一个方案,可以先预先定义一个pdf作为模板文件,然后用业务数据进行填空.是个不错的方案,只可惜不适合我的需求.需求中有些行是动态加行的,这个方案无法实现.后来发现有可以将网页直接转成pdf的开源包flyingsaucer(中文名:灰碟),逐将注意力转移到这上面,发现是个不错的选择.只要写网页就可以了,而且pdf格式变化维护起来也方便,代码也会比较干净.只是它对中文支持的不好,但这不是无法解决的.下面就来说说这个flyingsaucer.

Flyingsaucer使用iText2.0.8作为其pdf输出的基础工具,另外增加了解析html/xml并形成pdf式排版的功能.最重要的它还支持css样式表.组合这些能力后,它就可以将网页变成pdf了.但是,它也有他的问题.大家知道iText的版本现在已经升级为5.0以上了,而flyingsaucer却依然沿用2.0.8的版本.为什么呢? 因为这个灰碟貌似自2007年就已经停止维护了,最终版本flyingsaucer-R8.也就是说这是个几年前的工具包,至于新的替代此功能的包又在哪里?我没有找到,倒是有个功能相似但是收费的,不知道是不是它的成长版.这是题外话我们不研究.只看这个flyingsaucer-R8这个版本能否满足我们的基本要求吧.
    在使用过程中发现flyingsaucer-R8对导出pdf的网页有一些要求.
    1. 所有的标签必须都闭合.
    2. 网页开头引入的DTD必须与网页体中使用的标签一致.
    3. 部分不太常用的html标签貌似不认.比如<u>.
    因为flyingsaucer解析html文档是遵照xml标准来的,所以这个网页写起来不能像我们平时的网页那么随意.xml该有的规则都要遵守.这个要求并不高我们可以做到,而且试了下导出的pdf文档没啥问题,因此我们还是可以使用它来满足我们的需求.(至于,这个工具包怎么用,这里有不多说了,google一下一大片.这里只写目前google不到的东西.)
    既然要用它不可回避的就会遇到其对中文支持不好的问题.
    问题1:来源自渲染器输出时没有使用支持中文的字体.虽然我们看到iText有亚洲语言包iTextAsian.jar,但是仅仅引入此包并不能使我们的中文字符输出.以至于网上有个哥们写到:
    打开ITextOutputDevice这个类找到:

java代码:

改成:

java代码:

 try {
cb.setFontAndSize(BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED), _font.getSize2D()/_dotsPerPoint);
} catch (Exception e) {
}

Ok,改了以后我们终于可以看到pdf里有中文了.但是别高兴的太早哦,问题并没有完全解决.如果一段标签中有且只有中文字符的时候,导出pdf后内容便会消失.比如<div>中文</div>,这样的代码将什么也输出不了,而<div>中文a</div>则会将标签内容全部输出.通过测试我们发现,纯中文是无法输出的,但是加上一点点英文、数字或符号就可以输出了.有同学可能要说我们把纯中文后面加上空格不就行了?我只能说很不幸,加空格是不管用的.如果你的页面上纯中文的地方可以随便让你加字母/数字/符号,那可以不必往下看了.但是我觉得大多数的人恐怕不会这么干的,即使我们想客户也不让啊.那就要解决这个问题.

开源的东西有个好处,可以看源代码.从源码中我发现是字体的问题,于是乎,google一下,找到以下方案:
在导出的代码里加入这两句引入字体

java代码:

于是我照做了.杯具的是情况没有任何好转.即使有好转这个绝对路径的字体引入方式也很让人不舒服吧.所以这个不是我们想要的解决方案.

    Google不到只能继续从代码里找办法了.通过跟深入的研究代码,发现问题根源所在.输出PDF时在计算字符宽度的时候,对中文字符计算出的宽度居然是0.这也就能解释为什么纯中文字符串输出后会看不到了,因为字符总体的宽度被计算为0也就失去了被输出的机会,而加上一点非中文字符的则至少会有一点宽度,即获得了输出的机会,即使实际宽度比计算的宽度要宽也是可以输出的.
    于是修改BaseFont中的getWidth(String text)方法

java代码:

java代码:

  1.  ·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······15001.if (char1 < 128 || (char1 >= 160 && char1 <= 255))
    02. total += widths[char1];
    03.else if ((char1 >= 19968) && (char1 <= 40869)) // 如果是中文字符加宽度500
    04. total += 500;
    05.else
    06. total += widths[PdfEncodings.winansi.get(char1)];

再次测试,通过.至此,使用flyingsaucer网页导出成pdf中文问题总算解决了.可是总觉得这个解决的方法有点不太正宗,因为修改了父类嘛.但又没有找到其他正宗的解决方案,只能先这样解决一下了.发出此文,只当抛砖引玉,如果有哪位高人有更好的解决方案请不吝赐教啊.

附件提供修改了的flyingsaucer-R8的两个jar包: core-renderer.jar和iText2.0.8.jar另有一个iText亚洲语言包.

下载修改源码后的jar包地址:http://download.csdn.net/detail/shanliangliuxing/3640286

下面是我自己利用flying saucer技术生成pdf文档的实现代码:

Servlet方式:

html代码:

java代码:

Struts1形式:

html代码:

java代码:

 public void viewExportPDF(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
ServletContext sc = request.getSession().getServletContext();
String rootpath = sc.getRealPath(""); //值为D:\apache-tomcat-6.0.26\webapps\webmonitor
//把路径中的反斜杠转成正斜杠
rootpath = rootpath.replaceAll("\\\\", "/"); //值为D:/apache-tomcat-6.0.26/webapps/webmonitor
//临时存储目录
String pdfPathName = rootpath + "/WebReport.pdf";
ArrayList<String> list = new ArrayList<String>();
for(int i=0;i<outstreamlist.size();i++) {
list.add(outstreamlist.get(i));
}
//调用方法
boolean flag = createPdf(list, pdfPathName, request, response);
if (flag == true) {
//要实现另存为下载,必须满足两个条件:导入commons-upload.jar包,表单提交
try {
OutputStream out = response.getOutputStream();
byte by[] = new byte[1024];
File fileLoad = new File(pdfPathName);
response.reset();
response.setContentType("application/pdf");
response.setHeader("Content-Disposition",
"attachment; filename=WebReport.pdf");
long fileLength = fileLoad.length();
String length1 = String.valueOf(fileLength);
response.setHeader("Content_Length", length1);
FileInputStream in = new FileInputStream(fileLoad);
int n;
while ((n = in.read(by)) != -1) {
out.write(by, 0, n);
}
in.close();
out.flush(); } catch(Exception e) {
e.printStackTrace();
}
} else {
renderText(response, ERR_MESSAGE);
}
return ; } //生成pdf
public boolean createPdf(ArrayList<String> list, String pdfPathName,
HttpServletRequest request, HttpServletResponse response)
throws Exception { /**
* 用rootpath指定目录也可以生成pdf文件,只不过不能在myeclipse的左边导航窗口中看不到而已
* 左边导航窗口对应C盘目录下的workspace目录下程序
* 用rootpath指定的目录是D盘Tomcat目录
*/
ServletContext sc = request.getSession().getServletContext();
String rootpath = sc.getRealPath(""); //值为D:\apache-tomcat-6.0.26\webapps\webmonitor
//把路径中的反斜杠转成正斜杠
rootpath = rootpath.replaceAll("\\\\", "/"); //值为D:/apache-tomcat-6.0.26/webapps/webmonitor boolean flag = false;
String outputFile = pdfPathName;
//指定目录导出文件
OutputStream os = new FileOutputStream(outputFile);
ITextRenderer renderer = new ITextRenderer();
StringBuffer html = new StringBuffer();
//组装成符合W3C标准的html文件,否则不能正确解析
html.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">");
html.append("<html xmlns=\"http://www.w3.org/1999/xhtml\">")
.append("<head>")
.append("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />")
.append("<style type=\"text/css\" mce_bogus=\"1\">body {font-family: SimSun;}</style>")
.append("<style type=\"text/css\">img {width: 500px;}</style>")
.append("<style type=\"text/css\">table {font-size:13px;}</style>")
.append("</head>")
.append("<body>");
html.append("<center>");
html.append("<h1>统计报表</h1>");
for(int i=0;i<list.size();i++) {
html.append("<div>" + list.get(i) + "</div>");
}
html.append("</center>");
html.append("</body></html>");
try {
renderer.setDocumentFromString(html.toString());
// 解决图片的相对路径问题,图片路径必须以file开头
renderer.getSharedContext().setBaseURL("file:/" + rootpath);
renderer.layout();
renderer.createPDF(os);
os.close();
flag = true;
} catch (Exception e) {
flag = false;
e.printStackTrace();
}
return flag;
}

原文地址:http://blog.csdn.net/shanliangliuxing/article/details/6833471

PDF 生成插件 flying saucer 和 iText的更多相关文章

  1. 赞!jsPDF – 基于 HTML5 的强大 PDF 生成工具

    jsPDF 是一个基于 HTML5 的客户端解决方案,用于生成各种用途的 PDF 文档.使用方法很简单,只要引入 jsPDF 库,然后调用内置的方法就可以了.浏览器兼容性: IE 10, Firefo ...

  2. word和.txt文件转html 及pdf文件, 使用poi jsoup itext心得

    word和.txt文件转html 及pdf文件, 使用poi jsoup  itext心得本人第一次写博客,有上面不足的或者需要改正的希望大家指出来,一起学习交流讨论.由于在项目中遇到了这一个问题,在 ...

  3. jsPDF – 基于 HTML5 的强大 PDF 生成工具

    jsPDF 是一个基于 HTML5 的客户端解决方案,用于生成各种用途的 PDF 文档. 使用方法很简单,只要引入 jsPDF 库,然后调用内置的方法就可以了. 米扑科技项目用到了HHTML5生成PD ...

  4. 轻量级验证码生成插件webutil-licenseImage

    轻量级验证码生成插件webutil-licenseImage源码与实例应用   webutil-licenseImage 插件内置4种验证码样式,支持用户扩展.自定义样式实现简单验证码. 源码脱管地址 ...

  5. 基于canvas的二维码邀请函生成插件

    去年是最忙碌的一年,实在没时间写博客了,看着互联网行业中一个又一个人的倒下,奉劝大家,健康要放在首位,保重身体.好了,言归正传,这是17年的第一篇博文,话说这天又是产品同学跑过来问我说:hi,lenn ...

  6. 一个基于原生JavaScript开发的、轻量的验证码生成插件

    Vcode.js 一个基于原生JavaScript开发的.轻量的验证码生成插件 V: 1.0.0 DEMO:https://jofunliang.github.io/Vcode.js/example. ...

  7. Springboot 系列(十一)使用 Mybatis(自动生成插件) 访问数据库

    1. Springboot mybatis 介绍 MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数获取 ...

  8. KiCad 一款强大的 BOM 和 装配图生成插件

    KiCad 一款强大的 BOM 和 装配图生成插件 可以生成 BOM 和在线的图形. https://github.com/openscopeproject/InteractiveHtmlBom In ...

  9. jquery二维码生成插件_二维码生成器

    jquery二维码生成插件_二维码生成器 下载地址:jquery生成二维码.rar

随机推荐

  1. qgroundcontrol开发环境搭建源码编译

    qgroundcontrol是一款无人机地面站开源软件,C++/QT开发 在https://github.com/mavlink/qgroundcontrol上就能找到,选择稳定版下载最新的是2.6 ...

  2. Using Interface Builder记录

    1.interface builder的作用主要是用来设计视图,文件的拓展名诶.storyboard或者.xib :这两文件的区别是,.xib文件只能设计一个视图控制器,也就只能显示一个视图,.sto ...

  3. 关于if(a<b<c)判断的问题

    由于判断时的执行顺序,不要写成if(a<b<c)这种形式,很有可能得出的结果与我们想像的结果不一致,要写成if(a<b && b<c)!

  4. M4: 使用CommandBar

    本小节将介绍如何使用CommandBar, CommandBar分为PrimaryCommands和SecondaryCommands,在PrimaryCommands中不要放置多于四个按钮.然后将不 ...

  5. 第三个Sprint冲刺第三天

    讨论地点:宿舍 讨论成员:邵家文.李新.朱浩龙.陈俊金 讨论问题:增强了界面的效果,改善了视角

  6. CSS盒状模型简介

    CSS盒状模型 在平时的开发过程中还是经常得写博客,这2天有个公司找我面试,在面试当中提到了CSS中的盒状模型.这个东西在平时的前端开发经常用到.以下简单介绍一下: CSS中的盒状模型由:margin ...

  7. What does "Rxlch" mean in ENCODE?

    In ENCODE project, we could see some files are called "...rxlch...", which means "rev ...

  8. Jena Fuseki 102

    Version Fuseki v1 Fuseki v2 since Jena 2.13.0 Both v1 and v2 are active and maintained.[2015/06/29] ...

  9. C#调用C++ DLL类方法

    C++的优势在于高效灵活,C#的优势在于简单易用,两者结合起来对项目开发来说是件好事,而且C++不容易反编译,也保障了代码的安全性,如果一些核心算法使用C#编写,那么保密就是一个问题. C++生成的D ...

  10. PHP、JAVA、C#、Object-C 通用的DES加密

    PHP.JAVA.C#.Object-C 通用的DES加密 PHP: 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 ...