Confesso: tentei encontrar um título menor pra descrever esta situação, mas não encontrei... Resumindo, o problema é este: se uma página JSF tivesse que exibir um documento PDF que já estivesse dentro do WebContent, era moleza: bastava criar um link apontando pra ele e ponto final. Mas, e se o arquivo estiver, por exemplo, em um servidor da rede cujo o usuário final não tenha acesso?
Uma solução é: importar o conteúdo deste arquivo PDF em um array de bytes e, com isto, enviá-lo para o Response
do JSF.
Vamos simular esta solução: criaremos uma aplicação simples, onde o usuário indica em qual caminho está o arquivo PDF, importa e visualiza o PDF no navegador. Ficará assim:
Para isto, basta umManagedBean
e uma página JSF. Sem mais delongas, eis o código, devidamente comentado:
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:panelGrid columns="2"> <h:outputText value="Arquivo:" /> <h:inputText value="#{control.arquivo}" /> <h:commandButton value="Importar Arquivo" action="#{control.importarArquivo}" /> <h:commandLink value="Visualizar PDF" action="#{control.visualizarPdf}" target="_blank" /> </h:panelGrid> </h:form> </h:body> </html>
Control.java:
@ManagedBean @SessionScoped public class Control implements Serializable { // Array de bytes que armazenará o conteúdo do arquivo PDF private byte[] conteudoPdf; // Caminho completo do arquivo informado pelo usuário. // Ex: C:\Meus Documentos\boletim.pdf private String arquivo; public String getArquivo() { return arquivo; } public void setArquivo(String arquivo) { this.arquivo = arquivo; } public void importarArquivo() { try { // Cria um objeto File a partir do caminho especificado File file = new File(arquivo); // Inicializa o array bytes com o tamanho do arquivo especificado. // Note a conversao para int, restringindo a capacidade maxima do // arquivo em 2 GB conteudoPdf = new byte[(int) file.length()]; // Cria um InputStream a partir do objeto File InputStream is = new FileInputStream(file); // Aqui o InputStream faz a leitura do arquivo, transformando em um // array de bytes is.read(conteudoPdf); // Fecha o InputStream, liberando seus recursos is.close(); } catch (Exception e) { e.printStackTrace(); } } 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(conteudoPdf.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(conteudoPdf); // 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(); } } }