文件在 Java 泽西 API 中被下载两次

File is getting downloaded twice in Java Jersey API

我正在使用以下代码从 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();

问题

在您的代码中,您将生成一个文件,然后将在您的 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";

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

您应该使用 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();

中所述,重复的原因是因为您在创建和写入 FileOutputStream.

时创建了一个 "temporary" 文件

解决方法:不需要创建临时文件来处理下载。无需创建 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();
}