【问题标题】:get the PDF from a URL and push it to the clients browser for download从 URL 获取 PDF 并将其推送到客户端浏览器以供下载
【发布时间】:2014-11-06 21:30:48
【问题描述】:

我在外部服务器上安装了 PDF。我必须在我的 Java servlet 中访问它们并将它们推送到客户端浏览器。 PDF 应该直接下载,或者它可能会打开一个“保存或打开”对话框窗口。 这是我在我的代码中尝试的,但它不能做太多。

URL url = new URL("http://www01/manuals/zseries.pdf");
ByteArrayOutputStream bais = new ByteArrayOutputStream();
InputStream in = url.openStream();

int FILE_CHUNK_SIZE = 1024 * 4;
byte[] chunk = new byte[FILE_CHUNK_SIZE]; 
int n =0;
 while ( (n = in.read(chunk)) != -1 ) {
        bais.write(chunk, 0, n);
  }

我尝试了很多方法来做到这一点,但都没有成功。如果你有什么好的方法,我欢迎!

【问题讨论】:

  • 你的程序是桌面程序还是servlet?

标签: java http httprequest httpurlconnection urlconnection


【解决方案1】:

当您读取数据时,您会在服务器端的程序内存中获取数据。要将其发送到用户的浏览器,您还必须写入您已阅读的所有内容。

不过,在开始写作之前,您应该给出一些适当的标题。

  • 通过设置 mime 类型指示您通过 PDF 文件发送
  • 设置内容长度。
  • 表明该文件用于下载而不是显示在浏览器中。

要设置 mime 类型,请使用

response.setContentType("application/pdf");

要设置内容长度,假设它与您从 URL 获得的内容长度相同,请使用:

HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.connect();
if ( connection.getResponseCode() == 200 ) {
    int contentLength = connection.getContentLength();
    response.setContentLength( contentLength );

要表明您希望下载文件,请使用:

    response.setHeader( "Content-Disposition", "attachment; filename=\"zseries.pdf\"";

(注意将文件名更改为您希望用户在保存对话框中看到的任何内容)

最后,从刚刚打开的 URLConnection 中获取输入流,获取 servlet 的响应输出流,然后开始从一个读取并写入另一个:

    InputStream pdfSource = connection.getInputStream();
    OutputStream pdfTarget = response.getOutputStream();

    int FILE_CHUNK_SIZE = 1024 * 4;
    byte[] chunk = new byte[FILE_CHUNK_SIZE]; 
    int n =0;
    while ( (n = pdfSource.read(chunk)) != -1 ) {
        pdfTarget.write(chunk, 0, n);
    }
} // End of if

记得使用 try/catch 来解决这个问题,因为这些方法中的大多数都会抛出 IOException、超时异常等,并最终关闭两个流。还要记住做一些有意义的事情(比如给出错误输出),以防响应不是 200。

【讨论】:

    【解决方案2】:

    您可以将字节数组传输到客户端,然后使用 Itext 在新文件中“标记”pdf。之后使用 java.awt.Desktop 启动文件。

    public static void lauchPdf(byte[] bytes, String fileName) throws DocumentException, IOException{
        PdfReader reader = new PdfReader(bytes);
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(fileName));
        stamper.close();
        Desktop dt = Desktop.getDesktop();
        dt.browse(getFileURI(fileName));
    }
    

    【讨论】:

    • 这是网络应用程序。我不认为 AWT 在这里适用。
    【解决方案3】:

    你不需要推动任何东西(希望你真的不需要,因为实际上你不能)。从发出请求的浏览器的角度来看,您可以从数据库中获取 PDF,即时生成它或从文件系统中读取它(这是您的情况)。所以,假设你的 HTML 中有这个:

    <a href="/dl/www01/manuals/zseries.pdf">DOWNLOAD FILE</a>
    

    您需要为/dl/* 注册一个servlet 并像这样实现doGet(req, resp)

    public void doGet(
                  HttpServletRequest req
                , HttpServletResponse resp
    ) throws IOException { 
    
      resp.setContentType("application/pdf");
      response.setHeader("Content-Disposition",
              "attachment; filename=\"" + suggestFilename(req) + "\"");
    
      // Then copy the stream, for example using IOUtils.copy ...
      // lookup the URL from the bits after /dl/*
      URL url = getURLFromRequest(req);
      InputStream in = url.openConnection().getInputStream();
      IOUtils.copy(in, resp.getOutputStream());
      fin.close();
    }
    

    IOUtils 来自 Apache Commons IO(或者只是编写自己的 while 循环)

    【讨论】:

    • 正如我所提到的,我必须使用系统外部的 URL 访问 PDF。我这里没有使用任何文件系统。
    • 没什么大不了的。跳过content-length 标头并使用url.openConnection().getInputStream() 来获取输入流而不是使用文件(稍后您可能希望使用HTTP 客户端来代理文件的长度)
    猜你喜欢
    • 2014-04-05
    • 1970-01-01
    • 1970-01-01
    • 2018-01-09
    • 2020-01-14
    • 2018-04-25
    • 1970-01-01
    • 2011-06-13
    • 2018-12-11
    相关资源
    最近更新 更多