Social Icons


Pages

quinta-feira, 23 de agosto de 2012

Como exibir um PDF numa página JSF a partir de um campo BLOB/CLOB

Eis o cenário: Uma aplicação JSF, onde numa determinada página seja necessário exibir documentos PDF. Estes ficam armazenados em banco de dados, num campo BLOB/CLOB de uma tabela. A pergunta: Como implemento isto?

Vamos lá, hora da diversão. Começamos criando uma Entity para mapear a tabela que armazena o documento PDF:

DocumentoPdf.java:
@Entity
public class DocumentoPdf implements Serializable {

   @Id
   private int id;
 
   //Este atributo corresponde ao campo BLOB/CLOB que armazena 
   //o conteudo do documento PDF (Note a anotação @Lob)
   @Lob
   @Column
   private byte[] conteudo;
 
   //... Gets e Sets ...
}

Agora, precisamos de uma forma de buscar os objetos desta Entity no banco de dados. Vamos criar um DAO, deixando o código de acesso ao banco fora do escopo do nosso exemplo:

Dao.java:
public class Dao {

   public DocumentoPdf buscarDocumento() {
      //Implemente aqui para retornar o objeto DocumentoPdf do Banco de Dados
   }
}

Com o DAO pronto, vamos para o principal: um método no ManagedBean que pegue o array de bytes e envie para o navegador como um arquivo de documento PDF:

Control.java:
@ManagedBean
public class Control implements Serializable {

   //Apenas para simplificar: carrega automaticamente a Entity através do DAO
   private DocumentoPdf documentoPdf = new Dao().buscarDocumento();

   public void visualizarPdf() {

      FacesContext fc = FacesContext.getCurrentInstance();

      // Obtem o HttpServletResponse, objeto responsável pela resposta do
      // servidor ao browser
      HttpServletResponse response = (HttpServletResponse) fc
            .getExternalContext().getResponse();

      // Limpa o buffer do response
      response.reset();

      // Seta o tipo de conteudo no cabecalho da resposta. No caso, indica que o
      // conteudo sera um documento pdf.
      response.setContentType("application/pdf");

      // Seta o tamanho do conteudo no cabecalho da resposta. No caso, o tamanho
      // em bytes do pdf
      response.setContentLength(documentoPdf.getConteudo().length);

      // Seta o nome do arquivo e a disposição: "inline" abre no próprio navegador
      // Mude para "attachment" para indicar que deve ser feito um download
      response.setHeader("Content-disposition",
            "inline; filename=arquivo.pdf");
      try {

         // Envia o conteudo do arquivo PDF para o response
         response.getOutputStream().write(documentoPdf.getConteudo());

         // Descarrega o conteudo do stream, forçando a escrita de qualquer byte
         // ainda em buffer
         response.getOutputStream().flush();

         // Fecha o stream, liberando seus recursos
         response.getOutputStream().close();

         // Sinaliza ao JSF que a resposta HTTP para este pedido já foi gerada
         fc.responseComplete();
      } catch (IOException e) {
         e.printStackTrace();
      }
   }
}

Por fim, vamos criar a página JSF para testar. O atributo target="_blank" no h:commandLink indica ao browser que o PDF deve ser aberto em uma nova aba. Retire este atributo caso queira exibir na aba atual:

index.xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:h="http://java.sun.com/jsf/html">
<h:head />
<h:body>
  <h:form>
    <h:commandLink value="Visualizar PDF" action="#{control.visualizarPdf}" 
          target="_blank" />
  </h:form>
</h:body>
</html>

Leia também:

6 comentários:

  1. Respostas
    1. Deve funcionar sim, desde que no IE haja algum aplicativo configurado para ler PDF, como o Adobe Reader, por Exemplo.
      Nas versões mais recentes do Firefox, já há um leitor PDF nativo, mesmo que não existem nenhum aplicativo leitor de PDF instalado.

      Excluir
  2. Boa Tarde, estou com o seguinte problema, tenho meu arquivo pdf armazenado no banco de dados PostgreSQL. Fiz conforme exemplo acima, mas não estou conseguindo implementar para retornar o objeto DocumentoPdf do Banco de Dados na minha classe DAO. Poderia me ajudar?

    ResponderExcluir