Geração e Download de Pacotes ZIP com Java e Fetch API

Ao desenvolver aplicações web, frequentemente surge a necessidade de permitir que o usuário baixe um conjunto de arquivos de uma única vez. Em vez de enviar múltiplas requisições, uma abordagem altamente eficiente consiste em compactar dinamicamente esses arquivos no lado do servidor e transmitir o fluxo binário resultante diretamente para o navegador.

Implementação no Backend com Java

No serviodr, podemos utilizar a classe ZipOutputStream para criar o arquivo compactado em memória e escrevê-lo diretamente no OutputStream da resposta HTTP. A utilização do bloco try-with-resources garante o fechamento automático e seguro dos fluxos de entrada e saída, otimizando a estrutura original e evitando vazamentos de memória.

public void exportarArquivosCompactados(HttpServletResponse response, List<String> caminhosDosArquivos, String nomeDoPacote) {
    response.setContentType("application/zip");
    response.setHeader("Content-Disposition", "attachment; filename=\"" + nomeDoPacote + ".zip\"");

    try (ZipOutputStream fluxoZip = new ZipOutputStream(response.getOutputStream())) {
        byte[] buffer = new byte[8192];

        for (String caminho : caminhosDosArquivos) {
            File arquivoOrigem = new File(caminho);
            if (!arquivoOrigem.exists()) {
                continue;
            }

            ZipEntry entradaZip = new ZipEntry(arquivoOrigem.getName());
            fluxoZip.putNextEntry(entradaZip);

            try (FileInputStream fluxoEntrada = new FileInputStream(arquivoOrigem)) {
                int bytesLidos;
                while ((bytesLidos = fluxoEntrada.read(buffer)) != -1) {
                    fluxoZip.write(buffer, 0, bytesLidos);
                }
            }
            fluxoZip.closeEntry();
        }
        fluxoZip.finish();
    } catch (IOException excecao) {
        System.err.println("Falha ao gerar o pacote ZIP: " + excecao.getMessage());
    }
}

Processamento no Frontend com JavaScript

Para consumir esse fluxo binário sem recarregar a página, o cliente deve realizar uma requisição assíncrona configurada para receber um objeto Blob. A API fetch moderna simplifica o tratamento de cabeçalhos de autenticação e a manipulação da resposta em comparação com o tradicional XHR. Após receber os dados, um link temporário é gerado na memória para forçar o download imediato no navegador do usuário.

async function baixarPacoteImagens(urlRequisicao, tokenAutenticacao, nomeArquivo) {
    try {
        const resposta = await fetch(urlRequisicao, {
            method: 'GET',
            headers: {
                'Authorization': `Bearer ${tokenAutenticacao}`
            }
        });

        if (!resposta.ok) {
            throw new Error('Erro na comunicação com o servidor');
        }

        const dadosBlob = await resposta.blob();
        
        // Compatibilidade e gatilho de download
        if (window.navigator && window.navigator.msSaveOrOpenBlob) {
            window.navigator.msSaveOrOpenBlob(dadosBlob, nomeArquivo);
        } else {
            const urlTemporaria = window.URL.createObjectURL(dadosBlob);
            const elementoLink = document.createElement('a');
            elementoLink.href = urlTemporaria;
            elementoLink.download = nomeArquivo;
            
            document.body.appendChild(elementoLink);
            elementoLink.click();
            
            // Limpeza de recursos na memória
            document.body.removeChild(elementoLink);
            window.URL.revokeObjectURL(urlTemporaria);
        }
    } catch (erro) {
        console.error('O download não pôde ser concluído:', erro);
    }
}

Tags: java javascript zipoutputstream fetch-API http-response

Publicado em 7-11 23:54