Spring boot rest service to download a zip file which contains multiple file

Here is my working code I have used 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
        }
    }
}

Service Class:-

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;
    }
}

Use these Spring MVC provided abstractions to avoid loading of whole file in memory. org.springframework.core.io.Resource & org.springframework.core.io.InputStreamSource

This way, your underlying implementation can change without changing controller interface & also your downloads would be streamed byte by byte.

See accepted answer here which is basically using org.springframework.core.io.FileSystemResource to create a Resource and there is a logic to create zip file on the fly too.

That above answer has return type as void, while you should directly return a Resource or ResponseEntity<Resource> .

As demonstrated in this answer, loop around your actual files and put in zip stream. Have a look at produces and content-type headers.

Combine these two answers to get what you are trying to achieve.