Início > programação > Como forçar download de arquivo em JSF / Struts

Como forçar download de arquivo em JSF / Struts

Estou implementando uma aplicação em JSF que gera um arquivo texto em uma pasta da aplicação. Esse arquivo deve ser baixado para a máquina do usuário para que ele faça sua importação no servidor.

Para forçar o usuário a baixar o arquivo – e não deixar que o conteúdo dele aparecesse na tela do browser – desenvolvi uma solução muito simples que gira em torno de uma única JSP. O legal é que ela serve para JSF, Struts e Servlets (acredito que com o Seam também funcione), a extensão do arquivo a ser baixado pode ser qualquer uma e ele pode inclusive estar em qualquer pasta do servidor (dentro ou não do contexto web).

O código da página JSP downloadArquivo.jsp que efetuará todo o processo de download está logo abaixo:

<%@ page import="java.io.*"%>
<%
   File arquivo = new File ("/usr/local/", request.getParameter("arquivo"));
   if (!arquivo.exists()) {
%>
      <script language="javascript">
         alert('Arquivo desejado não encontrado. Comunique a coordenação da Semana Universitária.');	
      </script>
<%		
   } else {
      response.setContentType("application/octet-stream");
      // comento a linha abaixo para não forçar o download. vai abrir na própria janela.
      response.setHeader ("Content-Disposition", "attachment; filename=" +  request.getParameter("arquivo"));
		
      InputStream in = new FileInputStream(arquivo);
      PrintWriter output = response.getWriter();
		
      int bit = 256;
	
      try {
         while ((bit) >= 0) {
            bit = in.read();
            output.write(bit);
         }
	
      } catch (IOException e) {
         e.printStackTrace(System.out);
      }
      
      output.flush();
      output.close();
      in.close();
   }
%>

Em JSF, para chamarmos a página acima devermos usar um h:outputLink, conforme abaixo:

<h:outputLink target="_blank" value="#{facesContext.externalContext.requestContextPath}/downloadArquivo.jsp?arquivo=teste.txt" />
   <h:outputText value="baixar arquivo" />
</h:outputLink>

Pronto! Agora podemos baixar o arquivo sem problemas.

Muitas pessoas que utilizam esse tipo de solução para download de arquivos em JSP substituem a linha:

PrintWriter output = response.getWriter();

por:

ServletOutputStream output = response.getOutputStream();

Esse tipo de abordagem, utilizando ServletOutputStream para obter um stream de saída pode gerar a seguinte exceção, caso exista um espaço ou quebra de linha no conteúdo da página:

java.lang.IllegalStateException: getOutputStream() has already been called for this response
	at org.apache.catalina.connector.Response.getWriter(Response.java:610)
	at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:198)
	at org.apache.jasper.runtime.JspWriterImpl.initOut(JspWriterImpl.java:125)
	at org.apache.jasper.runtime.JspWriterImpl.flushBuffer(JspWriterImpl.java:118)
	at org.apache.jasper.runtime.PageContextImpl.release(PageContextImpl.java:188)
	at org.apache.jasper.runtime.JspFactoryImpl.internalReleasePageContext(JspFactoryImpl.java:118)
	at org.apache.jasper.runtime.JspFactoryImpl.releasePageContext(JspFactoryImpl.java:77)
	at org.apache.jsp.downloadDocumento_jsp._jspService(downloadDocumento_jsp.java:104)
	at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
	at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:374)
	at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
	at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
	at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
	at java.lang.Thread.run(Unknown Source)

Isso acontece porque o response gera um OutputStream anteriormente para “escrever” a linha ou o espaço na página, impossibilitando a geração de um ServletOutputStream. A solução? Pegar um PrintWriter, ao invés de um ServletOutputStream, conforme meu exemplo.

Anúncios
  1. 19/04/2009 às 22:31

    Parabêns pelo tutorial amigo, ficou muito bom. Será de grande utilizade.

  2. Guilherme
    13/03/2010 às 23:01

    Valeu!!! Muita ajuda

  3. JPinheiro
    06/05/2011 às 16:23

    Cara, ajudou mesmo.
    Porém eu implementei aqui e ele sempre gera um ? ao fim do arquivo.
    Estou baixando um arquivo .TXT

    Sabe me informar o pq isso acontece?

    • 06/05/2011 às 17:21

      Não passei por esse tipo de problema. Pelo menos que eu tenha percebido, não. Vou dar uma olhada aqui com mais calma e se descobrir algo te aviso.

      Abraço,

      Pablo.

  4. Alison Sousa
    20/08/2015 às 17:21

    Implementei o código porém meu arquivo fica vazio, não entendi pq, teoricamente ele está lendo o arquivo normalmente. mas quando baixo e abro, não tem nada.

  1. No trackbacks yet.

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

w

Conectando a %s

%d blogueiros gostam disto: