Exibir Relatório em um Dialog

Existe a possibilidade de exibir um relatório gerado pelo ireport em um p:dialog, a classe responsável por gerar e produzir que estou utilizando é esse:

import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Locale;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.hibernate.jdbc.Work;

import net.sf.jasperreports.engine.JRParameter;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.export.Exporter;
import net.sf.jasperreports.export.ExporterInput;
import net.sf.jasperreports.export.OutputStreamExporterOutput;
import net.sf.jasperreports.export.PdfExporterConfiguration;
import net.sf.jasperreports.export.PdfReportConfiguration;
import net.sf.jasperreports.export.SimpleExporterInput;
import net.sf.jasperreports.export.SimpleOutputStreamExporterOutput;

public class ExecutorRelatorio implements Work {
    private String caminhoRelatorio;
    private HttpServletResponse response;
    private Map<String, Object> parametros;
    private String nomeArquivoSaida;
    
        private boolean relatorioGerado;
        
    public ExecutorRelatorio(String caminhoRelatorio,
            HttpServletResponse response, Map<String, Object> parametros,
            String nomeArquivoSaida) {
        this.caminhoRelatorio = caminhoRelatorio;
        this.response = response;
        this.parametros = parametros;
        this.nomeArquivoSaida = nomeArquivoSaida;
        
        this.parametros.put(JRParameter.REPORT_LOCALE, new Locale("pt", "BR"));
    }

    @Override
    public void execute(Connection connection) throws SQLException {
        try {
            InputStream relatorioStream = this.getClass().getResourceAsStream(this.caminhoRelatorio);
            
            JasperPrint print = JasperFillManager.fillReport(relatorioStream, this.parametros, connection);
            this.relatorioGerado = print.getPages().size() > 0;
             
            if (this.relatorioGerado) {
                 Exporter<ExporterInput, PdfReportConfiguration, PdfExporterConfiguration, 
                     OutputStreamExporterOutput> exportador = new JRPdfExporter();
                exportador.setExporterInput(new SimpleExporterInput(print));
                exportador.setExporterOutput(new SimpleOutputStreamExporterOutput(response.getOutputStream()));
                
                response.setContentType("application/pdf");
                response.setHeader("Content-Disposition", "inline; filename=\"" 
                        + this.nomeArquivoSaida  + "\"");
                
                exportador.exportReport();
            }
        } catch (Exception e) {
            throw new SQLException("Erro ao executar relatório " + this.caminhoRelatorio, e);
        }
    }

    public boolean isRelatorioGerado() {
        return relatorioGerado;
    }

}

Mudei essa linha: response.setHeader(“Content-Disposition”, “inline; filename=”"
+ this.nomeArquivoSaida + “”"); de attachment para inline para fazer o relatorio abrir na mesma pagina e não com a opção de download do arquivo.

Meu bean que chama a função da geração do relatório é esse:

@Named
@RequestScoped
public class RelatorioFichaEmergenciaBean implements Serializable {

    private static final long serialVersionUID = 1L;
 
    private Long registro;

    @Inject
    private FacesContext facesContext;

    @Inject
    private HttpServletResponse response;

    @Inject
    private EntityManager manager;

    public void emitir(ActionEvent event) {
        
        UIParameter parameter = (UIParameter) event.getComponent().findComponent("registroId");
        registro = Long.parseLong(parameter.getValue().toString());
        
        Map<String, Object> parametros = new HashMap<>();
        parametros.put("registro", registro);
        
        ExecutorRelatorio executor = new ExecutorRelatorio("/relatorios/ficha_emergencia.jasper",
                this.response, parametros,"Ficha de Emergência.pdf");
        
        Session session = manager.unwrap(Session.class);
        session.doWork(executor);
        
        if (executor.isRelatorioGerado()) {
            facesContext.responseComplete();
        } else {
            FacesUtil.addErrorMessage("A execução do relatório não retornou dados.");
        }

    }
    
}

Pensei em usar um ‘p:dialog’ contendo um p:media porém o media não possui atributo do tipo actionListener.

Atualmente faço a chamado do relatório assim:

<p:commandButton value="Ficha de Atendimento" icon="ui-icon-print"
            actionListener="#{relatorioFichaEmergenciaBean.emitir}"
            update="@form" ajax="false">
            <f:param id="registroId" name="registroId"
                value="#{cadastroAtendimentoBean.atendimento.registro}" />
</p:commandButton>

Porém para o usuário ficar salvando arquivo pdf para depois ter que usar o visualizador de pdf para abri-lo e somente assim fazer a impressão acaba por gerar um retrabalho enorme, já vi em sistema que quando o usuário clica no botão impressão, abre-se um dialogo com um visualizador de pdf embutido já dando a opção ou dele imprimir ou salvar.

Alguém poderia me direcionar para alcançar o caminho de fazer isso corretamente.

Olá,

Segue uma alternativa:

Dependência necessária:

<dependency>
    <groupId>org.primefaces.extensions</groupId>
    <artifactId>primefaces-extensions</artifactId>
    <version>VERSAO_QUE_VOCE_DESEJAR</version>
    <scope>compile</scope>
</dependency>

Uma classe utilitária que criei para gerenciar o PDF:

/**
 * 
 * @author Weverton Reis
 *
 */
@ManagedBean
@SessionScoped
public class PdfMB implements Serializable {

	private StreamedContent pdf;
	
	/**
	 * Esse método deixa o arquivo pronto para ser exibido na tela.
	 * 
	 * @param arquivo O arquivo pronto para ser apresentado.
	 * @param nomeArquivo Nome do arquivo.
	 */
	public void gerar(InputStream arquivo, String nomeArquivo) {
		pdf = new DefaultStreamedContent(arquivo, "application/pdf", nomeArquivo);
	}
	
	public StreamedContent getPdf() {
		try {
			if(pdf != null){
				pdf.getStream().reset();
			}		
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		}
		return pdf;
	}

	public void setPdf(StreamedContent pdf) {
		this.pdf = pdf;
	}
	
}

Adicionando o PDF no seu Managed Bean:

@ManagedProperty(value = "#{pdfMB}")
private PdfMB pdfMB;

public PdfMB getPdfMB() {
       return pdfMB;
}

public void setPdfMB(PdfMB pdfMB) {
	this.pdfMB = pdfMB;
}

A ação do Managed bean que gera o arquivo:

byte[] bytesArquivo = SUA_FORMA_DE_GERACAO
InputStream arquivo = new ByteArrayInputStream(bytesArquivo);
arquivo.read();
pdfMB.gerar(arquivo, nomeArquivo.toString());
		

Adicione essa informação na xhtml:

xmlns:pe="http://primefaces.org/ui/extensions"

Na xhtml:

<p:dialog>
   <h:panelGrid>
      <pe:documentViewer style="width:100%; height:100%;"  value="#{pdfMB.pdf}"/>
   </h:panelGrid>
</p:dialog>

Mais informações: http://www.primefaces.org/showcase-ext/sections/documentviewer/basic.jsf

Espero ter ajudado em algo =)

1 curtida

Obrigado pelo ajuda, mas não estou conseguindo inserir a sua resposta no meu projeto. Onde você fala:

Onde você cita “SUA_FORMA_DE_GERACAO”. Vou inserir isso na classe ExecutorRelatorio ou na RelatorioFichaEmergenciaBean?

@Weverton_Reis

Fiz algumas mudanças no meu código para fazer gerar o relatório, aparentemente as mudanças funcionaram, pois o relatório é criado e exibido no navegador porém sempre que coloco na pagina o dialogo do seu exemplo, não funciona, ou seja, não exibi o relatório no navegador e tão pouco abre o dialogo para exibi-lo no componente de visualização.

Boa tarde,

Estranho Fabio.

Se o seu xhtml estiver mais ou menos dessa forma, pelo menos o dialog tem que aparecer:

Botão de ação:

<p:commandButton oncomplete="PF('dialog_Teste').show()"/>

Dialogo:

<p:dialog header="Teste" widgetVar="dialog_Teste">

</p:dialog>

(Código somente de exemplo, alguns atributos removidos)

Posta seu xhtml e ManagedBean atualizado.

O problema de exibir o componente foi devido ao primefaces está gerando alguns conflito, atualizei para a versão mais recente (5.3) e o componente do documentView está sendo exibido.

Porém não está funcionando corretamente nada, como tive que adaptar a função que estava usando para gerar os relatórios que não foi feita por mim e sim ensinada em um curso, de como criar relatórios usando o jasperReport e chama-lo em uma pagina, estava usando o que eles ensinaram, estou postando como está a tentativa de fazer funcionar o exibição do relatório no dialogo, sei que tem algo de errado porém não faço ideia como resolver

Classe que eu chamo de ExecutorRelatorio:

public class ExecutorRelatorio implements Work {

    private String caminhoRelatorio;
    private Map<String, Object> parametros;
    private String nomeArquivoSaida;

    private PdfMB pdfMB = new PdfMB();
 
 
    public ExecutorRelatorio(String caminhoRelatorio, Map<String, Object> parametros, String nomeArquivoSaida) {
        this.caminhoRelatorio = caminhoRelatorio;
        this.parametros = parametros;
        this.nomeArquivoSaida = nomeArquivoSaida;

        this.parametros.put(JRParameter.REPORT_LOCALE, new Locale("pt", "BR"));
    }

    @Override
    public void execute(Connection connection) throws SQLException {
        try {
            JasperReport jasperReport = JasperCompileManager
                    .compileReport(getClass().getResourceAsStream(this.caminhoRelatorio));

            JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parametros, connection);
            byte[] b = JasperExportManager.exportReportToPdf(jasperPrint);

            InputStream arquivo = new ByteArrayInputStream(b);
            arquivo.read();

            pdfMB.gerar(arquivo, nomeArquivoSaida);

        } catch (Exception e) {
            throw new SQLException("Erro ao executar relatório " + this.caminhoRelatorio, e);
        }
    }

    public PdfMB getPdfMB() {
        return pdfMB;
    }

    public void setPdfMB(PdfMB pdfMB) {
        this.pdfMB = pdfMB;
    }

}

Classe que tem a função que chama o executor, ou seja a função que é chamada pelo botão:

@Named
@RequestScoped
public class RelatorioFichaEmergenciaBean implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long registro;

    @Inject
    private FacesContext facesContext;

    @Inject
    private EntityManager manager;
 
    public void emitir(ActionEvent event) {
         
        UIParameter parameter = (UIParameter) event.getComponent().findComponent("registroId");
        registro = Long.parseLong(parameter.getValue().toString());
          
        Map<String, Object> parametros = new HashMap<>();
        parametros.put("registro", registro);
        
        ExecutorRelatorio executor = new ExecutorRelatorio("/relatorios/ficha_emergencia.jrxml",
                parametros,"Ficha de Emergência.pdf");
        
        Session session = manager.unwrap(Session.class);
        session.doWork(executor);
     }
    
}

Alguma Luz!

Boa noite Fabio,

Você esta quase, da uma olhada nisso.


@ManagedBean
@ViewScoped
public class RelatorioFichaEmergenciaBean implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long registro;

    @Inject
    private FacesContext facesContext;

    @Inject
    private EntityManager manager;

    @ManagedProperty(value = "#{pdfMB}")
    private PdfMB pdfMB;
 
    public void emitir(ActionEvent event) {
         
        UIParameter parameter = (UIParameter) event.getComponent().findComponent("registroId");
        registro = Long.parseLong(parameter.getValue().toString());
          
        Map&lt;String, Object&gt; parametros = new HashMap&lt;&gt;();
        parametros.put("registro", registro);
        
        ExecutorRelatorio executor = new ExecutorRelatorio("/relatorios/ficha_emergencia.jrxml",
                parametros,"Ficha de Emergência.pdf");
        
        pdfMB.gerar(executor.getArquivo() , executor.getNomeArquivoSaida());

        Session session = manager.unwrap(Session.class);
        session.doWork(executor);
     }

 public PdfMB getPdfMB() {
        return pdfMB;
    }

    public void setPdfMB(PdfMB pdfMB) {
        this.pdfMB = pdfMB;
    }
    
}

Faz o update no componente panel_Grid_Relatorio

<p:dialog header="Teste" widgetVar="viewRelatorio">
        <h:panelGrid id="panel_Grid_Relatorio">
            <pe:documentViewer value="#{pdfMB.pdf}"/>
        </h:panelGrid>
    </p:dialog>

Atualização dos arquivos

ExecutorRelatorio

public class ExecutorRelatorio implements Work {

    private String caminhoRelatorio;
    private Map<String, Object> parametros;
    private String nomeArquivoSaida;
    InputStream arquivo; 

    public ExecutorRelatorio(String caminhoRelatorio, Map<String, Object> parametros, String nomeArquivoSaida) {
        this.caminhoRelatorio = caminhoRelatorio;
        this.parametros = parametros;
        this.nomeArquivoSaida = nomeArquivoSaida;

        this.parametros.put(JRParameter.REPORT_LOCALE, new Locale("pt", "BR"));
    }

    @Override
    public void execute(Connection connection) throws SQLException {
        try {
            JasperReport jasperReport = JasperCompileManager
                    .compileReport(getClass().getResourceAsStream(this.caminhoRelatorio));

            JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parametros, connection);
            byte[] b = JasperExportManager.exportReportToPdf(jasperPrint);

            arquivo = new ByteArrayInputStream(b);
            arquivo.read();

        } catch (Exception e) {
            throw new SQLException("Erro ao executar relatório " + this.caminhoRelatorio, e);
        }
    }

    public InputStream getArquivo() {
        return arquivo;
    }

    public String getNomeArquivoSaida() {
        return nomeArquivoSaida;
    }

}

RelatorioFichaEmergenciaBean

@Named
@ManagedBean
@SessionScoped
public class RelatorioFichaEmergenciaBean implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long registro;

    @Inject
    private EntityManager manager;

    @Inject
    @ManagedProperty(value = "#{pdfMB}")
    private PdfMB pdfMB;

    public void emitir(ActionEvent event) {

        UIParameter parameter = (UIParameter) event.getComponent().findComponent("registroId");
        registro = Long.parseLong(parameter.getValue().toString());

        Map<String, Object> parametros = new HashMap<>();
        parametros.put("registro", registro);

        ExecutorRelatorio executor = new ExecutorRelatorio("/relatorios/ficha_emergencia.jrxml", parametros,
                "Ficha de Emergência.pdf");

        pdfMB.gerar(executor.getArquivo(), executor.getNomeArquivoSaida());

        Session session = manager.unwrap(Session.class);
        session.doWork(executor);
}

    public PdfMB getPdfMB() {
        return pdfMB;
    }

    public void setPdfMB(PdfMB pdfMB) {
        this.pdfMB = pdfMB;
    }

}

PdfMB

/**
 * 
 * @author Weverton Reis
 * Fórum: GUJ
 *
 */

@ManagedBean
@SessionScoped
public class PdfMB implements Serializable {

    private static final long serialVersionUID = 1L;
    private StreamedContent pdf;

    /**
     * Esse método deixa o arquivo pronto para ser exibido na tela.
     * 
     * @param arquivo O arquivo pronto para ser apresentado.
     * @param nomeArquivo Nome do arquivo.
     */
    public void gerar(InputStream arquivo, String nomeArquivo) {
         pdf = new DefaultStreamedContent(arquivo, "application/pdf", nomeArquivo);
    }

    public StreamedContent getPdf() {
        try {
            if(pdf != null){
                 pdf.getStream().reset();
            }        
        } catch (Exception e) {
            //logger.error(e.getMessage(), e);
            e.printStackTrace();
        }
        return pdf;
    }

    public void setPdf(StreamedContent pdf) {
        this.pdf = pdf;
   }

}

Pagina xHTML

<ui:composition 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"
     xmlns:pe="http://primefaces.org/ui/extensions">

    <p:toolbar style="margin-top: 20px">
        <p:toolbarGroup>
            <p:button value="Novo" icon="ui-icon-circle-plus"
                outcome="/atendimento/Atendimento" />
            <p:commandButton value="Salvar" icon="ui-icon-disk" update="@form"
                action="#{cadastroAtendimentoBean.salvar}" />
            <p:button value="Pesquisar" icon="ui-icon-circle-zoomin"
                outcome="/atendimento/PesquisaAtendimento" />
            <p:commandButton value="Imprimir Fichas" icon="ui-icon-print"
                oncomplete="PF('fichasPaciente').show()" process="@this"
                disabled="#{cadastroAtendimentoBean.atendimento.cancelado}">
            </p:commandButton>
            <p:commandButton value="Imprimir Laudo de AIH" update="@form"
                icon="ui-icon-print"
                 disabled="#{cadastroAtendimentoBean.atendimento.naoInternado}"
                actionListener="#{relatorioLaudoAih.emitir}" ajax="false">
                 <f:param id="registroIdLaudo" name="registroId"
                    value="#{cadastroAtendimentoBean.atendimento.registro}" />
        </p:commandButton>
        </p:toolbarGroup>

         <p:toolbarGroup align="right">
            <p:commandButton value="Realizar Atendimento"
                action="#{atenderAtendimentoBean.mudarParaEmAtendimento}"
                disabled="#{cadastroAtendimentoBean.atendimento.naoAguardandoAtendimento}"
                process="@form" update="@form" />
            <p:commandButton value="Observação" icon="ui-icon-check"
                action="#{observacaoAtendimentoBean.mudarParaObservacao}"
                disabled="#{cadastroAtendimentoBean.atendimento.aguardandoAtendimento}"
                process="@form" update="@form" />
            <p:commandButton value="Internamento" icon="ui-icon-locked"
                oncomplete="PF('subTelaInternamento').show()"
                disabled="#{cadastroAtendimentoBean.atendimento.aguardandoAtendimento}"
                process="@this" />
            <p:button value="Alta" outcome="/saida/Saida" icon="ui-icon-home"
                disabled="#{cadastroAtendimentoBean.atendimento.aguardandoAtendimento}">
                <f:param id="saida" name="atendimento"
                    value="#{cadastroAtendimentoBean.atendimento.registro}" />
            </p:button>
            <p:button value="Transferir" icon="ui-icon-alert"
                outcome="/transferencia/Transferencia"
                disabled="#{cadastroAtendimentoBean.atendimento.aguardandoAtendimento}">
                <f:param id="transferencia" name="atendimento"
                    value="#{cadastroAtendimentoBean.atendimento.registro}" />
            </p:button>

            <p:separator />

            <p:commandButton value="Cancelar" icon="ui-icon-cancel"
                process="@form" update="@form"
                action="#{cancelarAtendimentoBean.mudarParaCancelado}" />

         </p:toolbarGroup>
     </p:toolbar>

    <p:dialog header="Fichas do Paciente" widgetVar="fichasPaciente"
        id="fichasPaciente" modal="true" draggable="false" resizable="false">
        <p:commandButton value="Ficha de Atendimento" icon="ui-icon-print"
            actionListener="#{relatorioFichaEmergenciaBean.emitir}"
            update="@form, pgRelatorio" oncomplete="PF('viewRelatorio').show()">
            <f:param id="registroId" name="registroId"
                value="#{cadastroAtendimentoBean.atendimento.registro}" />
        </p:commandButton>
        <p:commandButton value="Ficha do Paciente" icon="ui-icon-print"
            actionListener="#{relatorioFichaEmissaoAih.emitir}" update="@form"
            ajax="false">
            <f:param id="registroIdFicha" name="registroId"
                value="#{cadastroAtendimentoBean.atendimento.registro}" />
        </p:commandButton>
    </p:dialog>

     <p:dialog header="Tela de Internamento" widgetVar="subTelaInternamento"
         id="subTelaInternamento" modal="true" draggable="false"
        resizable="false" closable="true">
         <p:panelGrid columns="2" style="width: 100%; margin-top: 20px"
            columnClasses="rotulo, campo, rotulo, campo">

            <p:outputLabel value="Tipo da Clínica" for="tipoClinica" />
            <p:selectOneMenu id="tipoClinica"
                value="#{cadastroAtendimentoBean.atendimento.clinica}">
                <f:selectItem itemLabel="Selecione ..." itemDisabled="true" />
                <f:selectItems value="#{cadastroTipoClinicaBean.listaClinicas}"
                    var="clinica" itemValue="#{clinica}"
                    itemLabel="#{clinica.descricao}" />
            </p:selectOneMenu>

              <p:outputLabel value="Tipo do Internamento" for="tipoInternamento" />
              <p:selectOneMenu id="tipoInternamento"
                 value="#{cadastroAtendimentoBean.atendimento.tipoAtendimento}"> 
                <f:selectItem itemLabel="Selecione ..." itemDisabled="true" />
                <f:selectItem itemLabel="Urgência/Emergência" itemValue="02" />
                <f:selectItem itemLabel="Eletivo" itemValue="01" />
            </p:selectOneMenu>

            <p:outputLabel value="Médico Responsável pelo internamento:"
                for="medicoResponsavelExec" />
             <p:autoComplete id="medicoResponsavelExec" size="40" dropdown="true"
                value="#{cadastroAtendimentoBean.atendimento.profissionalMedicoExecutor}"
                  completeMethod="#{cadastroAtendimentoBean.completarProfissional}"
                  var="profissional" itemLabel="#{profissional.nome}"
                  itemValue="#{profissional}" forceSelection="true" />

        </p:panelGrid>

         <p:commandButton value="Internar Paciente"
            action="#{internamentoAtendimentoBean.mudarParaInternamento}"
            process="@form" update="@form"
             onclick="PF('subTelaInternamento').close();" />

     </p:dialog>

    <p:dialog header="Teste" widgetVar="viewRelatorio" width="900px"
        height="100%" id="viewRelatorio">
        <h:panelGrid id="pgRelatorio" columns="1"
            style="width: 100%; margin-top: 20px">
            <pe:documentViewer id="view" style="width:100%; height:100%;"
                value="#{pdfMB.pdf}" />
         </h:panelGrid>
    </p:dialog>
</ui:composition>

Dessa forma que está, não aparece erro algum no console, o dialogo é exibido porem o PDF do relatorio não aparece, fica apenas o componente.

Fabio…
Consegui?

Caso não to fazendo uns testes aqui para ver se consigo. Estou no mesmo lugar q vc, ele abre o dialog mas vem em branco. Amanhã vou tentar mais. Aguenta ai.

Não ainda nada. Já tentei de outras forma mas tb, sem sucesso. Acho que está tendo algum problema ja geração do PDF em Stream, por isso não exibe. Mas não consigo saber onde é e como resolver.

Brother alguma novidade? Bom andei com alguns teste e descobri onde está o problema: Sempre que o arquivo vai para:

public void gerar(InputStream arquivo, String nomeArquivo) {
     pdf = new DefaultStreamedContent(arquivo, "application/pdf", nomeArquivo);
}

Ele está null, então o problema está sendo na geração do arquivo. Ainda procurando uma solução.