【问题标题】:File is getting downloaded twice in Java Jersey API文件在 Java Jersey API 中被下载两次
【发布时间】:2019-06-10 11:28:09
【问题描述】:

我正在使用以下代码从 html 下载 PDF 包含我的工作正常但文件被下载两次我试图修改渲染器行为但仍然没有得到任何东西。

public Response downloadResumePdf(@PathParam("userId") String userId) throws IOException, DocumentException {
     String homePath = System.getProperty("user.home");
        String filePath = homePath + "/Downloads/Resume" + LocalDateTime.now().toLocalDate() + ".pdf";
        org.xhtmlrenderer.pdf.ITextRenderer renderer = new ITextRenderer();
        String yourXhtmlContentAsString = "<h1>hi </h1>";
        renderer.setDocumentFromString(yourXhtmlContentAsString);
        renderer.layout();
        java.io.FileOutputStream fos = new java.io.FileOutputStream(filePath);
        renderer.createPDF(fos);
        fos.close();
        File file = new File(filePath);
        return Response
          .ok((Object) file)
          .header("Content-Disposition", "attachment; filename=\"Resume" + LocalDateTime.now().toLocalDate() + ".pdf\"")
          .build();

【问题讨论】:

  • 我无法重现此问题,它只为我下载一次。您是否在某个地方两次调用此端点,使其下载两次?
  • @Mark 在下载文件夹中相同的文件被创建了两次
  • 同一个文件怎么创建两次?它们有不同的文件名吗?
  • @Mark 我只使用上述代码
  • 您正在从您的下载文件夹中加载一个名为 Resume2019-01-16.pdf 的文件以在您的 API 上提供服务,然后您在本地运行您的 API,它将下载到 Resume2019-01-16 (1).pdf,这是“下载两次”吗你提?现在下载文件夹中有两个文件?或者当你去那个端点时它会创建Resume2019-01-16 (1).pdfResume2019-01-16 (2).pdf

标签: java pdf jersey itext html-to-pdf


【解决方案1】:

Mark's answer 中所述,重复的原因是因为您在创建和写入FileOutputStream 时正在创建一个“临时”文件。

解决方案:您不需要创建临时文件来处理下载。不用创建FileOutputStream,只需使用StreamingOutput 并将StreamingOutputOutputStream 传递给ITextRenderer#createPDF(OutputStream) 方法。

@GET
@Produces("application/pdf")
public Response getResumePdf(@PathParam("userId") String userId) {

    StreamingOutput entity = new StreamingOutput() {
        @Override
        public void write(OutputStream output) {
            try {
                ITextRenderer renderer = new ITextRenderer();
                String yourXhtmlContentAsString = "<h1>hi </h1>";
                renderer.setDocumentFromString(yourXhtmlContentAsString);
                renderer.layout();
                renderer.createPDF(output);
                output.flush();
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        }
    }

    return Response.ok(entity)
         .header(...)
         .build();
}

【讨论】:

    【解决方案2】:

    您应该使用 StreamingOutput 而不是使用 File。

    String homePath = System.getProperty("user.home");
        String filePath = homePath + "/Downloads/Resume" + LocalDateTime.now().toLocalDate() + ".pdf";
    
        org.xhtmlrenderer.pdf.ITextRenderer renderer = new ITextRenderer();
    
        String yourXhtmlContentAsString = "<h1>hi </h1>";
        renderer.setDocumentFromString(yourXhtmlContentAsString);
        renderer.layout();
    
        java.io.FileOutputStream fos = new java.io.FileOutputStream(filePath);
        renderer.createPDF(fos);
        //fos.close();
        final File file = new File(filePath);
    
        StreamingOutput fileStream =  new StreamingOutput()
        {
            @Override
            public void write(java.io.OutputStream output) throws IOException, WebApplicationException
            {
                try
                {
    
                    byte[] data = Files.readAllBytes(file.toPath());
                    output.write(data);
                    output.flush();
                }
                catch (Exception e)
                {
                    throw new WebApplicationException("File Not Found. !!");
                }
            }
        };
    
       return Response
           .ok( fileStream, MediaType.APPLICATION_OCTET_STREAM)
           .header("Content-Disposition", "attachment; filename=\"Resume" + LocalDateTime.now().toLocalDate() + ".pdf\"")
           .build();
    

    【讨论】:

    • 我试过上面提到的代码仍然文件被创建了两次
    • 这是 StreamingOutput 的糟糕实现,违背了它的目的。您正在使用Files.readAllBytes() 将整个文件读入内存。
    【解决方案3】:

    问题

    在您的代码中,您将生成一个文件,然后将在您的 API 上提供该文件。此文件使用new java.io.FileOutputStream(filePath) 创建,名为Resume2019-01-16.pdf,位于Downloads 文件夹中。

    由于您在本地运行 API,因此当您访问端点时,浏览器会将您提供的文件下载到您的 Downloads 文件夹。由于Resume2019-01-16.pdf 已经存在,浏览器会将其命名为Resume2019-01-16 (1).pdf

    因此看起来好像正在下载两个文件,但一个是由您的代码生成的,另一个是实际下载的。

    修复

    更改您要提供的文件的文件夹,只有实际下载的文件才会出现在您的Downloads 中,例如:

    String filePath = homePath + "/Documents/Resume" + LocalDateTime.now().toLocalDate() + ".pdf";
    

    或者使用某种方法将文件存储在内存中,而不是创建物理文件并提供该文件。

    【讨论】:

    • 一个是由您的代码生成的,另一个是实际下载的。这是我不想要的问题,我只想创建一个文件
    猜你喜欢
    • 1970-01-01
    • 2012-09-08
    • 1970-01-01
    • 1970-01-01
    • 2013-07-04
    • 2017-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多