Spring Boot Rest 服务下载包含多个文件的 zip 文件

Posted

技术标签:

【中文标题】Spring Boot Rest 服务下载包含多个文件的 zip 文件【英文标题】:Spring boot rest service to download a zip file which contains multiple file 【发布时间】:2018-12-22 21:08:32 【问题描述】:

我可以下载单个文件,但如何下载包含多个文件的 zip 文件。

以下是下载单个文件的代码,但我有多个文件要下载。任何帮助都将不胜感激,因为我在过去 2 天一直坚持这一点。

@GET
@Path("/download/fname/ext")
    @Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response  downloadFile(@PathParam("fname") String fileName,@PathParam("ext") String fileExt)
    File file = new File("C:/temp/"+fileName+"."+fileExt);
    ResponseBuilder rb = Response.ok(file);
    rb.header("Content-Disposition", "attachment; filename=" + file.getName());
    Response response = rb.build();
    return response;

【问题讨论】:

你试过response.setContentType("application/zip");吗? 我认为你将不得不使用rb.header("Content-Type", "application/zip"); 所以 zip 文件已经存在或者您希望即时创建它?另外,一个问题是完整的文件需要在内存中还是在下载时需要以块的形式流式传输? 我必须即时创建 zip 文件并回答您的第二个问题是完整文件需要在内存中,但如果超过 100 MB,我们将限制下载。 @abhishekchauhan:不能保证您将拥有一个并发客户端,因此根据内存占用量,100MB 可能必须乘以允许的并发连接数。只是一个想法。 【参考方案1】:

这是我使用 response.getOuptStream() 的工作代码

@RestController
public class DownloadFileController 

    @Autowired
    DownloadService service;

    @GetMapping("/downloadZip")
    public void downloadFile(HttpServletResponse response) 

        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment;filename=download.zip");
        response.setStatus(HttpServletResponse.SC_OK);

        List<String> fileNames = service.getFileName();

        System.out.println("############# file size ###########" + fileNames.size());

        try (ZipOutputStream zippedOut = new ZipOutputStream(response.getOutputStream())) 
            for (String file : fileNames) 
                FileSystemResource resource = new FileSystemResource(file);

                ZipEntry e = new ZipEntry(resource.getFilename());
                // Configure the zip entry, the properties of the file
                e.setSize(resource.contentLength());
                e.setTime(System.currentTimeMillis());
                // etc.
                zippedOut.putNextEntry(e);
                // And the content of the resource:
                StreamUtils.copy(resource.getInputStream(), zippedOut);
                zippedOut.closeEntry();
            
            zippedOut.finish();
         catch (Exception e) 
            // Exception handling goes here
        
    

服务等级:-

public class DownloadServiceImpl implements DownloadService 

    @Autowired
    DownloadServiceDao repo;

    @Override
    public List<String> getFileName() 

        String[] fileName =  "C:\\neon\\FileTest\\File1.xlsx", "C:\\neon\\FileTest\\File2.xlsx", "C:\\neon\\FileTest\\File3.xlsx" ;

        List<String> fileList = new ArrayList<>(Arrays.asList(fileName));       
        return fileList;
    

【讨论】:

我们怎样才能给要下载的 zip 文件的位置?【参考方案2】:

使用这些 Spring MVC 提供的抽象来避免将整个文件加载到内存中。 org.springframework.core.io.Resource & org.springframework.core.io.InputStreamSource

这样,您的底层实现可以在不更改控制器接口的情况下进行更改,并且您的下载也将逐字节流式传输。

查看已接受的答案here,它基本上是使用org.springframework.core.io.FileSystemResource 创建Resource,并且还有动态创建zip 文件的逻辑。

上述答案的返回类型为void,而您应该直接返回ResourceResponseEntity&lt;Resource&gt;

如this answer 中所示,围绕您的实际文件循环并放入 zip 流。查看producescontent-type 标头。

结合这两个答案以获得您想要实现的目标。

【讨论】:

感谢您的支持。现在我可以动态创建 zip 并下载它。 欢迎您!最好用最终的工作代码更新您的问题,这样它也可以帮助其他人。【参考方案3】:
public void downloadSupportBundle(HttpServletResponse response)

      File file = new File("supportbundle.tar.gz");
      Path path = Paths.get(file.getAbsolutePath());
      logger.debug("__path  - absolute Path", path.getFileName(),
            path.getRoot().toAbsolutePath());

      response.setContentType("application/octet-stream");
      response.setHeader("Content-Disposition", "attachment;filename=supportbundle.tar.gz");
      response.setStatus(HttpServletResponse.SC_OK);

      System.out.println("############# file name ###########" + file.getName());

      try (ZipOutputStream zippedOut = new ZipOutputStream(response.getOutputStream())) 

         FileSystemResource resource = new FileSystemResource(file);

         ZipEntry e = new ZipEntry(resource.getFilename());
         e.setSize(resource.contentLength());
         e.setTime(System.currentTimeMillis());
         zippedOut.putNextEntry(e);
         StreamUtils.copy(resource.getInputStream(), zippedOut);
         zippedOut.closeEntry();

         zippedOut.finish();
       catch (Exception e) 
         
      

【讨论】:

以上是关于Spring Boot Rest 服务下载包含多个文件的 zip 文件的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 spring rest 服务/spring boot 下载 Excel

具有多个用户的 Spring Boot REST 服务[关闭]

Spring Boot 微服务 REST API 安全

无法使用 Spring Boot Rest 服务将 JSON 转换为 Java 对象

Spring Boot:如何将工作流实现为集成外部应用程序的同步 REST 服务

使用 Spring Boot 的多个 REST 调用