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();
}
}
}
