Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 515|回复: 0

[jsp学习]如何在WEB应用中动态创建PDF文件

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-10-1 22:31:59 | 显示全部楼层 |阅读模式
    最近的后勤项目中,客户要求我们建一个能让用户能从一个遗留系统查询出货信息的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站点并下载最新的版本。iText站点提供了API文档和一个全面的指南。
    除了iText,我们还要用servlet.如果你不熟悉servlet,你可以通过Jason Hunter的书《Java Servlet Programming》来学习它。你需要一个J2EE应用服务器或可以独立运行的servlet引擎。开源软件Tomcat,Jetty和Jboss是不错的选择。下文假设你使用的是Jakarta Tomcat。   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
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-18 17:41 , Processed in 0.422819 second(s), 50 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表