Donwload de arquivos zip

Tem arquivos em um banco de dados.

O parâmetro é byte[] e no banco de dados no postgres é bytea.

Como posso ter vários arquivos no registro, como faço o download em spring, colocando todos arquivos em um arquivo zip e fazer o donwload no navegador ?

1 - Pegue todos os arquivos do banco
2 - Crie um arquivo temporário para cada arquivo
3 - Crie um arquivo compactado (.zip)
4 - Sete o arquivo como o content do response.

Sobre os itens que você falou:

  1. Já tenho.
  2. Utilizando o File ?
    3 e 4) Como fazer ?

Sim

Uma das várias opções existentes

Se spring mvc
Se spring boot

1 curtida

Obrigado, vou tentar e te informo.

Com java, vc consegue criar um Zip usando as classes do pacote java.util.zip.

1 curtida

Fiz assim:

	@GetMapping(value = "/download/{id}", produces = "application/zip")
	public void download(@PathVariable("id") String id,
			HttpServletResponse response) {
		try {
			response.setContentType("application/zip");
			response.setStatus(HttpServletResponse.SC_OK);
			response.addHeader("Content-Disposition", "attachment; filename=\"arquivos_conta_receber_" + idDtoParaEntidade(id) + ".zip\"");
			ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
			BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(byteArrayOutputStream);
			ZipOutputStream zipOutputStream = new ZipOutputStream(bufferedOutputStream);

			ContaPagarReceberArquivoImagemEntity cprArqImg = new ContaPagarReceberArquivoImagemEntity();

			cprArqImg.setContaPagarReceber(converterEntidadeContaReceber(new ContaReceberDTO(id)));

			RetornoJackson listarTodos = listarTodos(cprArqImg, null);

			ArrayList<File> files = new ArrayList<>(2);

			for (Object object : listarTodos.getLista()) {
				ContaPagarReceberArquivoImagemEntity cprArqImgZip = (ContaPagarReceberArquivoImagemEntity) object;
				byte[] logomarcaFoto = cprArqImgZip.getArquivoImagem().getLogomarcaFoto();

			}

		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		}
	}

Faz o donwload, mas sem arquivo nenhum. o que pode estar faltando ?

Dá este erro ao fazer o donwload. Imagem em anexo.

erro

O que o método getLista retorna? Pode postá-lo?

Lista de arquivo imagens por conta para receber.

as classe são:
package br.eti.netsoft.erp.modelo.financeiro;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;
import org.hibernate.envers.AuditOverride;
import org.hibernate.envers.Audited;
import org.hibernate.envers.RelationTargetAuditMode;

import br.eti.netsoft.erp.modelo.ErpEntity;
import br.eti.netsoft.erp.modelo.arquivoimagem.ArquivoImagemEntity;
import br.eti.netsoft.modelo.auditoria.AuditableBaseEntity;
import br.eti.netsoft.util.anotacao.ExclusaoLogica;

/**
 * @description Modelo para arquivos ou imagems para a contas pagar ou receber
 * @author GH SISTEMAS
 */
@Entity
@Table(name = "TB_CON_PAG_REC_IMG_ARQ", schema = "FINANCEIROS", indexes = {
		@Index(columnList = "ST_REGISTRO", name = "I1_CON_PAG_REC_IMG_ARQ"),
		@Index(columnList = "FK_CONTA_PAGAR_RECEBER", name = "I2_CON_PAG_REC_IMG_ARQ"),
		@Index(columnList = "FK_ARQUIVO_IMAGEM", name = "I3_CON_PAG_REC_IMG_ARQ")})
@Audited
@AuditOverride(forClass = AuditableBaseEntity.class)
@ExclusaoLogica
public class ContaPagarReceberArquivoImagemEntity extends ErpEntity {

	private static final long serialVersionUID = -7273641592040911533L;

	private ContaPagarReceberEntity contaPagarReceber;
	private ArquivoImagemEntity arquivoImagem;

	@Id
	@Override
	@Column(name = "PK_CON_PAG_REC_IMG_ARQ")
	@GeneratedValue(generator = "system-uuid")
	@GenericGenerator(name = "system-uuid", strategy = "uuid2")
	public String getId() {
		return super.getId();
	}

	@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
	@ManyToOne(targetEntity = ContaPagarReceberEntity.class, cascade = {
			CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DETACH})
	@JoinColumn(name = "FK_CONTA_PAGAR_RECEBER", nullable = false)
	public ContaPagarReceberEntity getContaPagarReceber() {
		return contaPagarReceber;
	}

	public void setContaPagarReceber(ContaPagarReceberEntity contaPagarReceber) {
		this.contaPagarReceber = contaPagarReceber;
	}

	@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
	@ManyToOne(targetEntity = ArquivoImagemEntity.class, cascade = {
			CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DETACH})
	@JoinColumn(name = "FK_ARQUIVO_IMAGEM", nullable = false)
	public ArquivoImagemEntity getArquivoImagem() {
		return arquivoImagem;
	}

	public void setArquivoImagem(ArquivoImagemEntity arquivoImagem) {
		this.arquivoImagem = arquivoImagem;
	}
}

e
package br.eti.netsoft.erp.modelo.arquivoimagem;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;
import org.hibernate.envers.AuditOverride;
import org.hibernate.envers.Audited;

import br.eti.netsoft.erp.modelo.ErpEntity;
import br.eti.netsoft.modelo.auditoria.AuditableBaseEntity;
import br.eti.netsoft.modelo.enuns.TipoArquivoImagemEnum;
import br.eti.netsoft.util.anotacao.ExclusaoLogica;
import br.eti.netsoft.util.comun.StringUtil;

@Entity
@Table(name = "TB_ARQUIVO_IMAGEM", schema = "GERAIS", indexes = {
		@Index(columnList = "ST_REGISTRO", name = "I1_ARQUIVO_IMAGEM"),
		@Index(columnList = "DS_NOME", name = "I2_ARQUIVO_IMAGEM"),
		@Index(columnList = "DS_EXTENSAO", name = "I3_ARQUIVO_IMAGEM"),
		@Index(columnList = "DS_NOME_CORRETO", name = "I4_ARQUIVO_IMAGEM"),
		@Index(columnList = "NR_TAMANHO", name = "I5_ARQUIVO_IMAGEM"),
		@Index(columnList = "ST_TIPO", name = "I6_ARQUIVO_IMAGEM")})
@Audited
@AuditOverride(forClass = AuditableBaseEntity.class)
@ExclusaoLogica
public class ArquivoImagemEntity extends ErpEntity {

	private static final long serialVersionUID = 5216149951618404098L;

	private String nome;
	private String extensao;
	private String nomeCorreto;
	private Integer tamanho;
	private String tabela;
	private String logomarcaBase64;
	private byte[] logomarcaFoto;
	private TipoArquivoImagemEnum tipo;

	@Id
	@Override
	@Column(name = "PK_ARQUIVO_IMAGEM")
	@GeneratedValue(generator = "system-uuid")
	@GenericGenerator(name = "system-uuid", strategy = "uuid2")
	public String getId() {
		return super.getId();
	}

	@Column(name = "DS_NOME", length = 500, nullable = false)
	public String getNome() {
		return nome;
	}

	public void setNome(String nome) {
		if (StringUtil.isNotNuloVazio(nome)) {
			this.nome = nome.toUpperCase();
		} else {
			this.nome = nome;
		}
	}

	@Column(name = "DS_EXTENSAO", length = 100, nullable = false)
	public String getExtensao() {
		return extensao;
	}

	public void setExtensao(String extensao) {
		if (StringUtil.isNotNuloVazio(extensao)) {
			this.extensao = extensao.toUpperCase();
		} else {
			this.extensao = extensao;
		}
	}

	@Column(name = "DS_NOME_CORRETO", length = 500, nullable = false)
	public String getNomeCorreto() {
		return nomeCorreto;
	}

	public void setNomeCorreto(String nomeCorreto) {
		this.nomeCorreto = nomeCorreto;
	}

	@Column(name = "NR_TAMANHO", length = 11, nullable = false)
	public Integer getTamanho() {
		return tamanho;
	}

	public void setTamanho(Integer tamanho) {
		this.tamanho = tamanho;
	}

	@Column(name = "DS_TABELA", length = 150, nullable = false)
	public String getTabela() {
		return tabela;
	}

	public void setTabela(String tabela) {
		if (StringUtil.isNotNuloVazio(tabela)) {
			this.tabela = tabela.toUpperCase();
		} else {
			this.tabela = tabela;
		}
	}

	@Column(name = "IM_LOGO", nullable = false)
	public byte[] getLogomarcaFoto() {
		return logomarcaFoto;
	}

	public void setLogomarcaFoto(byte[] logomarcaFoto) {
		this.logomarcaFoto = logomarcaFoto;
	}

	@Column(name = "IM_LOGO_BASE_64", length = 50000, nullable = false)
	public String getLogomarcaBase64() {
		return logomarcaBase64;
	}

	public void setLogomarcaBase64(String logomarcaBase64) {
		this.logomarcaBase64 = logomarcaBase64;
	}

	@Column(name = "ST_TIPO", length = 10, nullable = false)
	@Enumerated(EnumType.STRING)
	public TipoArquivoImagemEnum getTipo() {
		return tipo;
	}

	public void setTipo(TipoArquivoImagemEnum tipo) {
		this.tipo = tipo;
	}
}

O que vai se retornado mesmo é uma lista de ArquivoImagemEntity, que são imagens ou arquivos.

Certo, mas essa lista de ArquivoImagemEntity são arquivos (.txt, ;jpg, .doc, .pdf. etc)?
Caso sejam, apenas, array de byte, realmente vai ter erro. Você não pode compactar arrays de byte e ter arquivos ao final do download. Você precisa, primeiro, criar os arquivos e compactá-los.

Sim

Como fazer então ?

Presumo que esteja usando java 8 +:

byte[] bytes = ...;
Path path = Paths.get("/temp/nome_do_arquivo.txt");//Se for outro tipo de arquivo, tente ver como fazer isso para o tipo específico de arquivo
Files.write(path, bytes);

Assim, você tem um arquivo temporário.
Então você vai executar a compressão do(s) arquivo(s):

String sourceFile = "/temp/nome_do_arquivo.txt";
FileOutputStream fos = new FileOutputStream("compressed.zip");
ZipOutputStream zipOut = new ZipOutputStream(fos);
File fileToZip = new File(sourceFile);
FileInputStream fis = new FileInputStream(fileToZip);
ZipEntry zipEntry = new ZipEntry(fileToZip.getName());
zipOut.putNextEntry(zipEntry);
byte[] bytes = new byte[1024];
int length;
while((length = fis.read(bytes)) >= 0) {
    zipOut.write(bytes, 0, length);
}
zipOut.close();
fis.close();
fos.close();

Aí é só aplicar a mesma lógica em um loop de arquivos.

No seu código, eu não achei a chamada ao método que adiciona o arquivo ao zip: putNextEntry