分享
 
 
 

在WEB应用中动态创建PDF文件

王朝other·作者佚名  2008-05-19
窄屏简体版  字體: |||超大  

在一个最近的后勤项目中,客户要求我们建一个能让用户能从一个遗留系统查询出货信息的Web站点,有三个主要的需求:

1.出货信息必须以PDF文档的格式返回;

2.PDF文件必须能通过浏览器下载;

3.PDF文件必须能用Adobe Acrobat Reader阅读;

尽管我们的团队有很多J2EE Web应用的开发经验,但在PDF文档处理上却没有多少经验。我们需要找一个能在服务器端Web应用里产生复杂的PDF文档的纯Java类库。最后,我们发现iText(http://www.lowagie.com/iText/)能完全满足我们的需要。

1.iText类库

iText是一个创建和处理PDF文档的开源纯Java类库。Bruno Lowagie和Paulo Soares领导着这个项目。IText API能让Java开发人员以编程的方式创建PDF文档。iText提供了很多的特性:

支持PDF和FDF文档

各种页面尺寸

横向和竖向布局

页边距

表格

断字

页头

页脚

页码

条形码

字体

颜色

文档加密

JPEG,GIF,PNG和WMF图片

有序和无序列表

阴影

水印

文档模板

iText是一个开源库。在写本文的时候,iText可以在两个许可协议下使用:Mozilla Public License和LGPL。如果想了解详细信息,请参考iText站点。在本文中,你将会看到iText API的应用。我们将阐述如何在服务器端应用中使用iText和servlet动态生成PDF文档。

2.开始(Getting Started)

首先,你需要一个iText Jar文件。访问iText站点并下载最新的版本。在写本文时,最新的版本是使0.99。iText站点提供了API文档和一个全面的指南。

除了iText,我们还要用servlet.如果你不熟悉servlet,你可以通过Jason Hunter的书《Java Servlet Programming》来学习它。你需要一个J2EE应用服务器或可以独立运行的servlet引擎。开源软件Tomcat,Jetty和Jboss是不错的选择。下文假设你使用的是Jakarta Tomcat 4.1。

1.iText API

iText API简单易用。通过使用iText,你能创建自定义的PDF文档。iText库由下边的一些包组成:

com.lowagie.servlets

com.lowagie.text

com.lowagie.text.html

com.lowagie.text.markup

com.lowagie.text.pdf

com.lowagie.text.pdf.codec

com.lowagie.text.pdf.hyphenation

com.lowagie.text.pdf.wmf

com.lowagie.text.rtf

com.lowagie.text.xml

com.lowagie.tools

为了生成PDF文件,你只需要com.lowagie.text和com.lowagie.text.pdf两个包。

我们的例子使用了这些iText类:

com.lowagie.text.pdf.PdfWriter

com.lowagie.text.Document

com.lowagie.text.HeaderFooter

com.lowagie.text.Paragraph

com.lowagie.text.Phrase

com.lowagie.text.Table

com.lowagie.text.Cell

关键的类是Document和PdfWriter。在创建PDF文档时,你将经常使用这两个类。Document是PDF文档基于对象的描述。你可以通过调用Document类提供的方法往文档中加入内容。PdfWriter对象通过java.io.OutputStream对象与Document关联在一起。

3.在Web应用中使用iText

在设计阶段,你必须决定如何使用iText。我们使用了下边的技术开发了我们的Web应用。

1.A技术

在服务器文件系统上创建PDF文件。应用使用java.io.FileOutputStream把文件写到服务器文件系统上。用户通过HTTP GET方法下载该文件。

2.B技术

使用java.io.ByteArrayOutputStream在内存中创建PDF文件。应用通过servlet的输出流将该PDF文件字节发送到客户端。

由于应用不需要把文件写到文件系统上,这样能保证在集群服务环境中能正常工作,所以我更倾向于使用B技术。如果你的应用运行在集群环境中且服务器集群不提供会话亲和的功能,A技术可能会导致失败。

3.例子:PDFServlet

我们的例子应用由一个类组成:PDFServlet。这个servlet采用B技术。输出流OutputStream是java.io.ByteArryOutputStream。用ByteArrayOutputStream,PDF文档字节将存储在内存中。当PDFServlet接收到一个HTTP请求时,它将动态地生成一个PDF文档并将该文档发送到客户端。

PDFServlet类扩展了javax.servlet.http.HttpServlet类并导入了两个iText包:com.lowagie.text和com.lowagie.text.pdf。

doGet方法

大多数servlet覆盖了doPost和doGet方法中的一个方法。我们的servlet没有什么不同。PDFServlet类覆盖了doGet方法。该servlet将在接收到HTTP GET请求后生成一个PDF文件。

在核心部分,servlet的doGet方法做了如下的工作:

1.创建一个包含PDF文档字节的ByteArrayOutputStream对象;

2.在reponse对象上设置HTTP响应头内容;

3.得到servlet输出流;

4.把文档字节写到servlet的输出流中;

5.刷新servlet输出流;

generatePDFDocumentBytes方法

generatePDFDocumentBytes方法负责创建PDF文档。在这个方法中三个最重要的对象是Document对象,ByteArrayOutputStream对象和PdfWriter对象。PdfWriter使用ByteArrayOutputStream关联Document。

Document doc = new Document();

ByteArrayOutputStream baosPDF = new ByteArrayOutputStream();

PdfWriter docWriter = null;

docWriter = PdfWriter.getInstance(doc, baosPDF);

// ...

用add方法把内容添加到Document中。

doc.add(new Paragraph(

"This document was created by a class named: "

+ this.getClass().getName()));

doc.add(new Paragraph(

"This document was created on "

+ new java.util.Date()));

当你添加完内容后,要关闭Document和PdfWriter对象。

doc.close();

docWriter.close();

当关闭文档后,ByteArrayOutputStream对象返回到调用者。

return baosPDF;

ByteArrayOutputStream包含了PDF文档的所有字节。

HTTP响应头

在这个应用中,我们仅仅关注四个HTTP 响应头:Content-type,Content-disposition,Content-length,和Cache-control。如果你从没有使用过HTTP头,请参考HTTP 1.1规范。

研究在PDFServlet中的doGet方法,你会注意到要在任何数据写到servlet输出流之前设置HTTP响应头内容,这是很重要的,也是细微的一点。

让我们更详细地说明一下每个响应头的含义。

Content-type

在servlet中,HttpServletResponse有一个表明响应所包含内容类型的参数。对PDF文件而言,内容类型是application/pdf。如果servlet没有设置类型,web浏览器很难决定如何处理这个文件。

PDFServlet用下边的代码设置内容类型:

resp.setContentType("application/pdf");

Content-disposition

Content-disposition头提供给浏览器确定HTTP响应内容的信息。当浏览器读到这些头信息后,它能确定:

HTTP响应包含一个文件;

包含在响应中的文件名;

该文件是显示在浏览器主窗口中还是要用外部的应用查看;

RFC 2183中有对Content-disposition头完整的解释。

通过合适地设置Content-disposition的值,servlet能指示浏览器是“内嵌”显示文件还是把它当作附件处理。

例1.内嵌显示一个文件

Content-disposition: inline; filename=foobar.pdf

例2.往response里附加一个文件

Content-disposition: attachment; filename=foobar.pdf

下边的伪码说明了如何设置头信息:

public void doGet(HttpServletRequest req, HttpServletResponse resp)

{

// ...

resp.setHeader(

"Content-disposition",

"inline; filename=foobar.pdf" );

// ...

}

Cache-Control

根据你应用的特性不同,你可以让浏览器缓存或者不缓存你正在生成的PDF文件。服务器端应用可以有很多种HTTP 头来控制内容缓存。下边是一些例子:

Cache-Control: no-cache

Cache-Control: no-store

Cache-Control: must-revalidate

Cache-Control: max-age=30

Pragma: no-cache

Expires: 0

关于Cache-Control头的全面解释见HTTP 1.1规范。

PDFServlet把Cache-Control设置为max-age=30。这个头信息告诉浏览器缓存这个文件的最长时间为30秒。

Content-length

Content-length头必须设置成PDF文件中字节的数值。如果Content-length没有设置正确,浏览器可能不能正确地显示该文件。下边是例子代码:

ByteArrayOutputStream baos = getByteArrayOutputStream();

resp.setContentLength(baos.size());

把PDF文档送到Web浏览器

PDFServlet通过把字节流写到servlet的输出流的方式把PDF文档送到客户端。它通过调用HttpServletResponse对象的getOutputStream方法来获得输出流。getOutputStream方法返回一个javax.servlet.ServletOutputStream类型的对象。

ServletOutputStream sos;

sos = resp.getOutputStream();

baos.writ

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有