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

来源:互联网 发布:java将int转换成date 编辑:程序博客网 时间:2024/06/08 02:50
<script type="text/javascript">google_ad_client = "pub-8800625213955058";/* 336x280, 创建于 07-11-21 */google_ad_slot = "0989131976";google_ad_width = 336;google_ad_height = 280;//</script><script type="text/javascript"src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>原文:Sean C. Sullivan 翻译:gagaghost 在一个最近的后勤项目中,客户要求我们建一个能让用户能从一个遗留系统查询出货信息的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 APIiText API简单易用。通过使用iText,你能创建自定义的PDF文档。iText库由下边的一些包组成:com.lowagie.servletscom.lowagie.textcom.lowagie.text.htmlcom.lowagie.text.markupcom.lowagie.text.pdfcom.lowagie.text.pdf.codeccom.lowagie.text.pdf.hyphenationcom.lowagie.text.pdf.wmfcom.lowagie.text.rtfcom.lowagie.text.xmlcom.lowagie.tools为了生成PDF文件,你只需要com.lowagie.text和com.lowagie.text.pdf两个包。我们的例子使用了这些iText类:com.lowagie.text.pdf.PdfWritercom.lowagie.text.Documentcom.lowagie.text.HeaderFootercom.lowagie.text.Paragraphcom.lowagie.text.Phrasecom.lowagie.text.Tablecom.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-dispositionContent-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-lengthContent-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.writeTo(sos);sos.flush();在把所有的数据写到流之后,调用flush()方法把所有的字节发送到客户端。打包和部署为了在Tomcat中运行PDFServlet,你需要把应用打包在WAR文件中。iText JAR文件(itext-0.99.jar)必须放在WAR文件的lib目录下边。如果你忘了把iText JAR文件打包进去,servlet会报一个java.lang.NoClassDefFoundError的错误并停止运行。运行应用在WAR文件部署之后,你已经准备好了测试servlet了。Jakarta Tomcat在8080端口上监听请求。在浏览器中请求http://hostname:8080/pdfservlet/createpdf。servlet将会执行并返回浏览器一个PDF文档。4.iText之外的方案iText提供了许多产生PDF文档的底层API。然而,它不是对任何应用都有效。在我的日常工作中,我结合Microsoft Word和Adobe Acrobat使用iText。首先,我们的团队使用Microsoft Word设计了一个出货表单。之后,我们用Acrobat把Word文档转换成PDF文档。然后,我们使用iText的模板的功能,我们把PDF文件装入到我们的应用中。从这里,把数据填入表格和输出最终的PDF文档是相当容易的。对基于报表的Web应用,像JasperReports这样的工具,它提供了比iText更高层次的抽象。5.总结当你的应用需要动态地创建PDF文档的时,iText类库是一个不错的方案。你可以通过增强和扩展本文中的代码来体验iText的能力。很快,由于提供了完善的PDF文档,你将会给你的同事和客户留下深刻的印象。6.其他资源http://www.lowagie.com/iText/ www.jpedal.org www.pdfbox.org xml.apache.org/fop HTTP 1.1 protocol specification RFC 2183 dmoz.org/Computers/Data_Formats/Document/Publishing/PDF www.planetpdf.com www.pdfzone.com
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 乳腺贴的功效 乳腺康贴 乳腺增生贴有用吗 乳腺增生贴多少钱 乳腺贴多少钱一盒 3+银乳腺贴 纳米银乳腺贴 巨战乳姬 双子姬乳 薄姬割下右乳 焰灵姬乳 姬存希洁面乳 姬存希洁面乳多少钱 姬存希水乳 乳酪包 奶酪包做法 芝士包 乳酶生 乳酶生片 乳酶生说明书 乳酶生片婴儿怎么吃 乳酶生和益生菌区别 乳酶生的功效与作用 乳酶生片的功效与作用 乳酸奶 为什么塞乳酸菌反而会得霉菌 乳酸菌片 豪士乳酸菌小口袋面包 乳酸菌胶囊会加重霉菌吗 乳酸菌素片说明书 味动力乳酸菌 乳酸菌会加重便秘 阴道乳酸菌 乳酸菌功效 乳酸菌阴道 活性乳酸菌 喝乳酸菌饮料有什么好处 孕妇喝乳酸菌 乳酸菌素片什么时候吃 乳酸菌可以长期吃吗 乳酸菌原核