1
Hello, I have a jsf page where I upload the data from a entidade
, between the data there is an attached file (pdf, xls, jpg etc.).
I would like you, when clicking on the file name, to download the file.
If anyone can help in any way thank you.
Method I use to add the file :
public void doUpload(FileUploadEvent fileUploadEvent) throws IOException {
UploadedFile uploadedFile = fileUploadEvent.getFile();
String fileNameUploaded = uploadedFile.getFileName();
long fileSizeUploaded = uploadedFile.getSize();
// System.out.println(uploadedFile);
String infoAboutFile = "<br/> Arquivo recebido: <b>" + fileNameUploaded + "</b><br/>"
+ "Tamanho do Arquivo: <b>" + fileSizeUploaded + "</b>";
FacesContext facesContext = FacesContext.getCurrentInstance();
facesContext.addMessage(null, new FacesMessage("Sucesso", infoAboutFile));
arquivo = (IOUtils.toByteArray(uploadedFile.getInputstream()));
entradaAcidente.setAttach(arquivo);
nomeArquivo = uploadedFile.getFileName();
}
Entity:
@Entity
@Table(name = "entrada_acidente")
public class EntradaAcidente implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private Date dataCriacao;
private String observacao;
private BigDecimal valorDesconto = BigDecimal.ZERO;
private BigDecimal valorTotal = BigDecimal.ZERO;
private StatusEntradaAcidente status = StatusEntradaAcidente.ORCAMENTO;
private FormaPagamento formaPagamento;
private Usuario vendedor;
private Cliente cliente;
private Ocorrencia ocorrencia1;
private List<ItemDespesa> itens = new ArrayList<>();
@Lob
@Column(columnDefinition = "LONGBLOB")
private byte[] comprovante;
private String fileName;
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
@Id
@GeneratedValue
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Lob
public byte[] getComprovante() {
return comprovante;
}
public void setComprovante(byte[] comprovante) {
this.comprovante = comprovante;
}
@NotNull
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "data_criacao", nullable = false)
public Date getDataCriacao() {
return dataCriacao;
}
public void setDataCriacao(Date dataCriacao) {
this.dataCriacao = dataCriacao;
}
@Column(columnDefinition = "text")
public String getObservacao() {
return observacao;
}
public void setObservacao(String observacao) {
this.observacao = observacao;
}
@NotNull
@Column(name = "valor_desconto", nullable = false, precision = 10, scale = 2)
public BigDecimal getValorDesconto() {
return valorDesconto;
}
public void setValorDesconto(BigDecimal valorDesconto) {
this.valorDesconto = valorDesconto;
}
@NotNull
@Column(name = "valor_total", nullable = false, precision = 10, scale = 2)
public BigDecimal getValorTotal() {
return valorTotal;
}
public void setValorTotal(BigDecimal valorTotal) {
this.valorTotal = valorTotal;
}
@NotNull
@Enumerated(EnumType.STRING)
@Column(nullable = false, length = 20)
public StatusEntradaAcidente getStatus() {
return status;
}
public void setStatus(StatusEntradaAcidente status) {
this.status = status;
}
@NotNull
@Enumerated(EnumType.STRING)
@Column(name = "forma_pagamento", nullable = false, length = 20)
public FormaPagamento getFormaPagamento() {
return formaPagamento;
}
public void setFormaPagamento(FormaPagamento formaPagamento) {
this.formaPagamento = formaPagamento;
}
@NotNull
@ManyToOne
@JoinColumn(name = "vendedor_id", nullable = false)
public Usuario getVendedor() {
return vendedor;
}
public void setVendedor(Usuario vendedor) {
this.vendedor = vendedor;
}
@NotNull
@ManyToOne
@JoinColumn(name = "cliente_id", nullable = false)
public Cliente getCliente() {
return cliente;
}
public void setCliente(Cliente cliente) {
this.cliente = cliente;
}
@ManyToOne
@JoinColumn(name = "ocorrencia_id", nullable = false)
public Ocorrencia getOcorrencia() {
return ocorrencia1;
}
public void setOcorrencia(Ocorrencia ocorrencia) {
this.ocorrencia1 = ocorrencia;
}
@OneToMany(mappedBy = "entradaAcidente", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
public List<ItemDespesa> getItens() {
return itens;
}
public void setItens(List<ItemDespesa> itens) {
this.itens = itens;
}
@Transient
public boolean isNovo() {
return getId() == null;
}
@Transient
public boolean isExistente() {
return !isNovo();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
EntradaAcidente other = (EntradaAcidente) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
@Transient
public BigDecimal getValorSubtotal() {
return this.getValorTotal().subtract(this.getValorDesconto());
}
public void recalcularValorTotal() {
BigDecimal total = BigDecimal.ZERO;
total = total.subtract(this.getValorDesconto());
for (ItemDespesa item : this.getItens()) {
if (item.getDespesa() != null && item.getDespesa().getId() != null) {
total = total.add(item.getValorTotal());
}
}
this.setValorTotal(total);
}
public void adicionarItemVazio() {
if (this.isOrcamento()) {
Despesa despesa = new Despesa();
ItemDespesa item = new ItemDespesa();
item.setDespesa(despesa);
item.setEntradaAcidente(this);
this.getItens().add(0, item);
}
}
@Transient
public boolean isOrcamento() {
return StatusEntradaAcidente.ORCAMENTO.equals(this.getStatus());
}
public void removerItemVazio() {
ItemDespesa primeiroItem = this.getItens().get(0);
if (primeiroItem != null && primeiroItem.getDespesa().getId() == null) {
this.getItens().remove(0);
}
}
@Transient
public boolean isValorTotalNegativo() {
return this.getValorTotal().compareTo(BigDecimal.ZERO) < 0;
}
@Transient
public boolean isEmitido() {
return StatusEntradaAcidente.EMITIDO.equals(this.getStatus());
}
@Transient
public boolean isNaoEmissivel() {
return !this.isEmissivel();
}
@Transient
public boolean isEmissivel() {
return this.isExistente() && this.isOrcamento();
}
@Transient
public boolean isCancelavel() {
return this.isExistente() && !this.isCancelado();
}
@Transient
private boolean isCancelado() {
return StatusEntradaAcidente.CANCELADO.equals(this.getStatus());
}
@Transient
public boolean isNaoCancelavel() {
return !this.isCancelavel();
}
@Transient
public boolean isAlteravel() {
return this.isOrcamento();
}
@Transient
public boolean isNaoAlteravel() {
return !this.isAlteravel();
}
@Transient
public boolean isNaoEnviavelPorEmail() {
return this.isNovo() || this.isCancelado();
}
}
Class where the download method is:
@Named
@ViewScoped
public class PesquisaEntradaAcidentesBean implements Serializable {
private static final long serialVersionUID = 1L;
@Inject
private EntradaAcidentes entradas;
private AcidenteFilter filtro;
private List<EntradaAcidente> entradasFiltradas;
private EntradaAcidente entradaSelecionada;
public PesquisaEntradaAcidentesBean() {
filtro = new AcidenteFilter();
entradasFiltradas = new ArrayList<>();
}
public void pesquisar() {
entradasFiltradas = entradas.filtrados(filtro);
}
public StatusEntradaAcidente[] getStatuses() {
return StatusEntradaAcidente.values();
}
public List<EntradaAcidente> getEntradasFiltradas() {
return entradasFiltradas;
}
public AcidenteFilter getFiltro() {
return filtro;
}
public EntradaAcidente getEntradaSelecionada() {
return entradaSelecionada;
}
public void setEntradaSelecionada(EntradaAcidente entradaSelecionada) {
this.entradaSelecionada = entradaSelecionada;
}
public String downloadComprovante() throws IOException {
String nomeArquivo = "comprovante_" + entradaSelecionada.getId() + ".pdf";
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
externalContext.responseReset();
externalContext.setResponseContentType("application/pdf");
externalContext.setResponseHeader("Content-Disposition", "attachment; filename=\"" + nomeArquivo + "\"");
OutputStream out = externalContext.getResponseOutputStream();
try (InputStream is = new ByteArrayInputStream(entradaSelecionada.getComprovante())) {
int read = -1;
byte[] buffer = new byte[1024];
while ((read = is.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
}
facesContext.responseComplete();
return nomeArquivo;
}
}
jsf:
<ui:composition template="/WEB-INF/template/LayoutPadrao.xhtml"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<ui:define name="titulo">Pesquisa de acidentes</ui:define>
<ui:define name="corpo">
<h:form>
<h1>Pesquisa de acidentes</h1>
<p:toolbar style="margin-top: 20px">
<p:toolbarGroup>
<p:commandButton value="Pesquisar"
action="#{pesquisaEntradaAcidentesBean.pesquisar}" update="@form" />
</p:toolbarGroup>
<p:toolbarGroup align="right">
<p:button value="Novo" outcome="/entradasAcidente/CadastroEntradaAcidente" />
</p:toolbarGroup>
</p:toolbar>
<p:panelGrid columns="2" id="painel"
style="width: 100%; margin-top: 20px" columnClasses="rotulo, campo">
<p:outputLabel value="Número" />
<h:panelGroup>
<p:inputText size="10"
value="#{pesquisaEntradaAcidentesBean.filtro.numeroDe}" />
<p:inputText size="10"
value="#{pesquisaEntradaAcidentesBean.filtro.numeroAte}" />
</h:panelGroup>
<p:outputLabel value="Data de criação" />
<h:panelGroup>
<p:calendar size="10" pattern="dd/MM/yyyy"
value="#{pesquisaEntradaAcidentesBean.filtro.dataCriacaoDe}" />
<p:calendar size="10" pattern="dd/MM/yyyy"
value="#{pesquisaEntradaAcidentesBean.filtro.dataCriacaoAte}" />
</h:panelGroup>
<p:outputLabel value="Responsável" />
<p:inputText size="40"
value="#{pesquisaEntradaAcidentesBean.filtro.nomeVendedor}" />
<p:outputLabel value="Cliente" />
<p:inputText size="40"
value="#{pesquisaEntradaAcidentesBean.filtro.nomeCliente}" />
<p:outputLabel value="Status" />
<p:selectManyCheckbox
value="#{pesquisaEntradaAcidentesBean.filtro.statuses}">
<f:selectItems value="#{pesquisaEntradaAcidentesBean.statuses}"
var="status" itemValue="#{status}" itemLabel="#{status.descricao}" />
</p:selectManyCheckbox>
</p:panelGrid>
<p:dataTable id="acidentesTable"
value="#{pesquisaEntradaAcidentesBean.entradasAcidenteFiltrados}"
var="entrada_acidente" style="margin-top: 20px"
emptyMessage="Nenhum encontrado." rows="20" paginator="true"
paginatorAlwaysVisible="false" paginatorPosition="bottom">
<p:column headerText="Número"
style="text-align: center; width: 100px">
<h:outputText value="#{entrada_acidente.id}" />
</p:column>
<p:column headerText="Cliente">
<h:outputText value="#{entrada_acidente.cliente.nome}" />
</p:column>
<p:column headerText="Ocorrencia">
<h:outputText value="#{entrada_acidente.ocorrencia.descricao}" />
</p:column>
<p:column headerText="Responsável">
<h:outputText value="#{entrada_acidente.vendedor.nome}" />
</p:column>
<p:column headerText="Data de criação"
style="text-align: center; width: 140px">
<h:outputText value="#{entrada_acidente.dataCriacao}">
<f:convertDateTime pattern="dd/MM/yyyy" />
</h:outputText>
</p:column>
<p:column headerText="Valor total"
style="text-align: right; width: 120px">
<h:outputText value="#{entrada_acidente.valorTotal}">
<f:convertNumber type="currency" />
</h:outputText>
</p:column>
<p:column headerText="Status" style="width: 100px">
<h:outputText value="#{entrada_acidente.status.descricao}" />
</p:column>
<p:column headerText="Arquivo">
<h:outputText value="#{entrada_acidente.fileName}" />
</p:column>
<p:column headerText="Download">
<h:commandButton
action="#{pesqusaEntradaAcidentesBean.downloadComprovante}">
<f:setPropertyActionListener
target="#{pesqusaEntradaAcidentesBean.entradaSelecionada}"
value="entrada_acidente.id" />
<f:param name="entrada_acidente" value="#{entrada_acidente.id}" />
</h:commandButton>
</p:column>
<p:column style="text-align: center; width: 50px">
<p:button icon="ui-icon-pencil" title="Editar"
outcome="/entradasAcidente/CadastroEntradaAcidente">
<f:param name="entrada_acidente" value="#{entrada_acidente.id}" />
</p:button>
</p:column>
</p:dataTable>
</h:form>
</ui:define>
</ui:composition>
Update:
Downloadbean:
@ManagedBean
@RequestScoped
public class DownloadBean extends HttpServlet{
/**
*
*/
private static final long serialVersionUID = 1L;
private StreamedContent file;
private int codigo;
public StreamedContent getFile() {
return file;
}
public void setFile(StreamedContent file) {
this.file = file;
}
public int getCodigo() {
return codigo;
}
public void setCodigo(int codigo) {
this.codigo = codigo;
}
public void download() {
ResultSet rs;
try {
byte[] bytes = null;
Class.forName("com.mysql.jdbc.Driver");
java.sql.Connection con = DriverManager.getConnection("jdbc:mysql://localhost/PRODUTOS", "root", "123456");
PreparedStatement ps = con.prepareStatement("select attach from ENTRADA_ACIDENTE where id= (?)");
ps.setInt(1, codigo);
rs = ps.executeQuery();
while (rs.next()) {
bytes = rs.getBytes("attach");
}
ps.close();
con.close();
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();
response.reset();
response.getOutputStream().write(bytes);
response.getOutputStream().flush();
response.getOutputStream().close();
FacesContext.getCurrentInstance().responseComplete();
} catch (Exception e) {
FacesMessage message = new FacesMessage("Erro");
FacesContext.getCurrentInstance().addMessage(null, message);
}
}
}
xhtml download:
<p:column headerText="Download">
<h:commandLink id="getDownload" value="download"
action="#{downloadBean.download()}">
<f:setPropertyActionListener
target="#{downloadBean.codigo}"
value="#{entrada_acidente.id}" />
</h:commandLink>
</p:column>
xhtml upload:
web xml.
<servlet>
<servlet-name>DownloadBean</servlet-name>
<servlet-class>com.rodrigo.acidentes.controller.DownloadBean</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DownloadBean</servlet-name>
<url-pattern>/image/*</url-pattern>
</servlet-mapping>
Update 2:
DownloadBean:
package com.rodrigo.controleacidentes.controller;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletResponse;
import org.primefaces.model.StreamedContent;
@ManagedBean
@SessionScoped
public class DownloadBean extends HttpServlet {
private static final long serialVersionUID = 1L;
private StreamedContent file;
private long codigo;
public StreamedContent getFile() {
return file;
}
public void setFile(StreamedContent file) {
this.file = file;
}
public long getCodigo() {
return codigo;
}
public void setCodigo(long codigo) {
this.codigo = codigo;
}
public void download(Long codigo) {
ResultSet rs;
byte[] bytes = null;
String fileName = "";
try {
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost/acidentes", "root", "123456");
PreparedStatement ps = con
.prepareStatement("select attach,fileName from ENTRADA_ACIDENTE where ENTRADA_ACIDENTE.id=?");
ps.setLong(1, codigo);
rs = ps.executeQuery();
while (rs.next()) {
bytes = rs.getBytes("attach");
fileName = rs.getString("fileName");
}
ps.close();
con.close();
HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext()
.getResponse();
response.setContentType("application/octet-stream");
response.setHeader("Content-disposition", "attachment; filename=" + fileName);
response.getOutputStream().write(bytes);
response.getOutputStream().flush();
response.getOutputStream().close();
FacesContext.getCurrentInstance().responseComplete();
} catch (Exception e) {
FacesMessage message = new FacesMessage("Erro ao realizar download!");
FacesContext.getCurrentInstance().addMessage(null, message);
e.printStackTrace();
}
}
}
xhtml:
<p:column headerText="Download">
<p:commandButton value="Download"
actionListener="#{downloadBean.download(entrada_.id)}"
ajax="false">
<p:fileDownload value="#{downloadBean.file}" />
</p:commandButton>
</p:column>
Rodriho, I think you will need to persist more information about the file, such as the name / extension. With this information you can develop a
Servlet
or something like that configure the return type and write the content ofblob
in stream response. From a look in that reply at Balusc no Soen. You can adapt the query in Servlet to JPA and link the file column of your table to[caminho do servlet/id]
according to your design.– Anthony Accioly
I added the file name in the meantime.
– Rodrigo
@Anthony Accioly I changed the codes in the question, including a method to download, but obviously it is factoring something, or there is something wrong, by clicking the download button just redirects to the search page. If there’s anything I can do, thank you.
– Rodrigo
Try to pass the id or the object itself via el to the download action (I’m suspicious of this combination with
setProperty
+param
). Also make your download method return void and put in some logs to make sure the method is being called (another example of Balusc). Give me a call if it works.– Anthony Accioly
Also lacked the
Content-Length
– Anthony Accioly
I’m trying, but even if I call any other method, the behavior is the same, as if it’s not even triggering the so-called method. Also if you put a " system.out" to print on the console, it does not appear.
– Rodrigo
@Anthony Accioly I was able to upload it, I saw it in my own browser. I added the codes above. However, when downloading from the browser, the image is corrupted, although in the visualization it is "perfect". I am still working on the solutions, but without success. In some moments this error happens:
java.lang.IllegalStateException: getOutputStream() has already been called for this response
.– Rodrigo
See if your download method is not being called multiple times (it is because of problems like this that I always move logic to a Servlet).
– Anthony Accioly
Missing also include Content type and length headers in response.
– Anthony Accioly
I’ll check, thank you.
– Rodrigo
I could see that even when running the search method, before the data appear and then click on the download link runs the download method.
– Rodrigo
@Anthony Accioly I solved the download problem as codes posted in "update 2" I believe it can be improved, (even if someone has suggestions) but it is functional at the moment. In some moments there is still the error of :
getOutputStream() has already been called for this response
, at first if I perform a registration operation and then download . This I have not solved yet.– Rodrigo