Sempre Java

agosto 16, 2010

Exportando relatorio iReport/Jasper para PDF

Filed under: Desenvolvimento Web — Tags:, , , , — semprejava @ 2:18 pm

Olá pessoal, boa tarde.
Estou novamente por aqui, dessa vez para publicar como exportar o relatório gerado no iReport para PDF.
Primeiramente deveremos ter as seguintes libs em nossa app (WEB-INF/lib):

iText-2.1.0.jar
jasperreports-3.7.4.jar
jasperreports-applet-3.7.4.jar
jasperreports-fonts-3.7.4.jar
jasperreports-javaflow-3.7.4.jar
poi-3.0.1-FINAL.jar
commons-beanutils-1.8.3.jar
commons-collections-2.1.1.jar
commons-javaflow-20060411.jar
commons-logging-1.1.1.jar
commons-logging-api-1.1.1.jar

Algumas libs não são obrigatórias, mas coloquei-as para evitar erros posteriores.

Abaixo o XHTML reponsável por invocar o Managed Bean e preencher a query desejada. No meu caso trata-se de um relatório de pedidos do cliente, onde usuário poderá informar o nome do cliente, data início e data fim, ou pode simplesmente não preencher o filtro.

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:p="http://primefaces.prime.com.tr/ui"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">
    <ui:composition template="/resources/template.xhtml">

        <ui:define name="login">
            <ui:include src="/resources/usuarioAutenticado.xhtml" />
        </ui:define>

        <ui:define name="javascript">
            <script type="text/javascript" src="${facesContext.externalContext.requestContextPath}/js/jquery.maskedinput-1.2.2.js"></script>
            <script type="text/javascript" src="${facesContext.externalContext.requestContextPath}/js/jquery.validate.js"></script>
            <script type="text/javascript" src="${facesContext.externalContext.requestContextPath}/js/funcoes.js"></script>
        </ui:define>

        <ui:define name="centro">

            <p:messages />

            <p:outputPanel id="oplDialog" layout="block">
                <p:dialog id="dlgMsg" header="#{msg['modalPanel.msgAlerta']}"
                          position="center" minWidth="300" width="300" visible="true"
                          resizable="false" modal="true" rendered="#{relatorioPedidosClienteController.exibeDialog}">
                    <h:panelGrid columns="1" cellspacing="5px">
                        <h:outputLabel id="oplMensagem" value="#{relatorioPedidosClienteController.mensagem}" styleClass="fonteAlerta" />
                        <p:commandButton  id="cbtOk" value="#{msg['botao.ok']}" action="/index?faces-redirect=true" immediate="true" />
                    </h:panelGrid>
                </p:dialog>
            </p:outputPanel>

            <p:panel id="pnlCorpoRelatorioCliente" style="position: relative; margin: auto; margin-top: 20px; width: 900px;">
                <f:facet name="header">
                    <h:outputText value="Detalhes do Relatório de Pedidos do Cliente" />
                </f:facet>

                <h:panelGrid columns="3" columnClasses="col1, col2, col3">
                    <h:outputLabel styleClass="fontePadrao" value="#{msg['pedido.cliente.nome']}" />
                    <h:inputText id="iptNomeClientePesq" size="70" maxlength="100"
                                 onkeyup="this.value = somenteCaracteres(this.value)"
                                 value="#{relatorioPedidosClienteController.cliente.nmCliente}" />
                    <p:commandButton  value="Pesquisar" action="#{relatorioPedidosClienteController.carregaClientesPeloNome}"
                                      update="tabClientes" />
                </h:panelGrid>

                <p:outputPanel layout="block">
                    <p:dataTable id="tabClientes" value="#{relatorioPedidosClienteController.listaClientes}" var="cliente" rows="3"
                                 width="700px" emptyMessage="#{msg['tabela.nenhumRegistroEncontrado']}" paginator="true"
                                 paginatorPosition="bottom" style="position: relative; margin: auto; text-decoration: none; font-size: 12px;"
                                 firstPageLinkLabel="#{msg['tabela.primeiroRegistro']}" nextPageLinkLabel="#{msg['tabela.proximoRegistro']}"
                                 previousPageLinkLabel="#{msg['tabela.anteriorRegistro']}" lastPageLinkLabel="#{msg['tabela.ultimoRegistro']}"
                                 selectionMode="single">
                        <p:column>
                            <f:facet name="header">
                                <h:outputText value="#{msg['cliente.tabela.cpf']}" />
                            </f:facet>
                            <h:outputText value="#{cliente.nuCpf}" />
                        </p:column>
                        <p:column>
                            <f:facet name="header">
                                <h:outputText value="#{msg['cliente.tabela.cnpj']}" />
                            </f:facet>
                            <h:outputText value="#{cliente.nuCnpj}" />
                        </p:column>
                        <p:column sortBy="#{cliente.nmCliente}">
                            <f:facet name="header">
                                <h:outputText value="#{msg['cliente.tabela.nome']}" />
                            </f:facet>
                            <h:outputText value="#{cliente.nmCliente}" />
                        </p:column>
                        <p:column>
                            <f:facet name="header">
                                <h:outputText value="#{msg['cliente.tabela.cep']}" />
                            </f:facet>
                            <h:outputText value="#{cliente.nuCep}" />
                        </p:column>
                        <p:column>
                            <p:commandLink id="cdlSelecionaCliente" update="iptNomeClientePesq">
                                <h:graphicImage url="/img/tick.png" title="#{msg['botao.consultar']}" />
                                <f:setPropertyActionListener value="#{cliente}" target="#{relatorioPedidosClienteController.cliente}" />
                            </p:commandLink>
                        </p:column>
                    </p:dataTable>
                </p:outputPanel>

                <h:panelGrid columns="2" columnClasses="col1, col2">
                    <h:outputLabel styleClass="fontePadrao" value="Data Inicial:" />
                    <p:inputMask id="iptDataEmissao" mask="99/99/9999" maxlength="10" size="11" value="#{relatorioPedidosClienteController.dataInicio}">
                        <f:convertDateTime pattern="dd/MM/yyyy" timeZone="#{relatorioPedidosClienteController.timeZone}" />
                    </p:inputMask>

                    <h:outputLabel styleClass="fontePadrao" value="Data Final:" />
                    <p:inputMask id="iptDataVencimento" mask="99/99/9999" maxlength="10" size="11" value="#{relatorioPedidosClienteController.dataFim}">
                        <f:convertDateTime pattern="dd/MM/yyyy" timeZone="#{relatorioPedidosClienteController.timeZone}" />
                    </p:inputMask>
                </h:panelGrid>

                <f:facet name="footer">
                    <p:commandButton  value="#{msg['botao.fechar']}" action="/index?faces-redirect=true"
                                      immediate="true" />
                    <h:outputText value=" " />
                    <p:commandButton  id="cbtGerarRelatorio" value="Gerar Relatório" action="#{relatorioPedidosClienteController.geraRelatorio}"
                                      ajax="false" >
                        <p:ajax event="complete" update="oplDialog" />
                    </p:commandButton>

                </f:facet>
            </p:panel>

        </ui:define>
    </ui:composition>
</html>

Agora o ManagedBean responsável por passar os parâmetros para o relatório (arquivo .jasper) gerado durante a compilação do mesmo, e exportá-lo para pdf.

package br.com.notaroberto.controller;

import br.com.notaroberto.model.Cliente;
import br.com.notaroberto.util.Funcoes;
import br.com.notaroberto.util.HibernateUtil;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.TimeZone;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletResponse;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;

@ManagedBean(name = "relatorioPedidosClienteController")
@ViewScoped
public class RelatorioPedidosClienteController {

    private TimeZone timeZone = TimeZone.getDefault();
    private JasperPrint impressao;
    private HashMap<String, Serializable> parametroMap;
    private FacesContext context;
    private ServletContext servletContext;
    private String mensagem, caminhoRelatorio;
    private Date dataInicio, dataFim;
    private boolean exibeDialog, exibeTabelaCliente;
    private Cliente cliente;
    private List<Cliente> listaClientes;

    @PostConstruct
    public void init() {
        // Chamando ao instanciar o escopo de visao 
        cliente = new Cliente();
    }

    @PreDestroy
    public void destroy() {
        // A chamada eh realizada quando a pagina eh alterada 
    }

    public String getMensagem() {
        return mensagem;
    }

    public void setMensagem(String mensagem) {
        this.mensagem = mensagem;
    }

    public boolean isExibeDialog() {
        return exibeDialog;
    }

    public void setExibeDialog(boolean exibeDialog) {
        this.exibeDialog = exibeDialog;
    }

    public boolean isExibeTabelaCliente() {
        return exibeTabelaCliente;
    }

    public void setExibeTabelaCliente(boolean exibeTabelaCliente) {
        this.exibeTabelaCliente = exibeTabelaCliente;
    }

    public Date getDataInicio() {
        return dataInicio;
    }

    public void setDataInicio(Date dataInicio) {
        this.dataInicio = dataInicio;
    }

    public Date getDataFim() {
        return dataFim;
    }

    public void setDataFim(Date dataFim) {
        this.dataFim = dataFim;
    }

    public TimeZone getTimeZone() {
        return timeZone;
    }

    public Cliente getCliente() {
        return cliente;
    }

    public void setCliente(Cliente cliente) {
        this.cliente = cliente;
    }

    public List<Cliente> getListaClientes() {
        return listaClientes;
    }

    public void setListaClientes(List<Cliente> listaClientes) {
        this.listaClientes = listaClientes;
    }

    public void carregaClientesPeloNome() {
        ClienteController clienteController = new ClienteController();
        clienteController.carregaClientesPeloNome(cliente.getNmCliente());
        setListaClientes(clienteController.getListaClientes());
    }

    public String montaSQL(Integer idCliente, String dataInicio, String dataFim) {
        String sql = " 1 = 1";

        if (!dataInicio.isEmpty() && !dataFim.isEmpty()) {
            sql += " AND ( ped.DATA_EMISSAO BETWEEN STR_TO_DATE('" + dataInicio + "', '%d/%m/%Y') AND STR_TO_DATE('" + dataFim + "', '%d/%m/%Y') )";
        }

        if (idCliente != null) {
            sql += " AND cli.ID_CLIENTE = '" + idCliente + "'";
        }

        sql += " GROUP BY cli.ID_CLIENTE, ped.ID_PEDIDO, prod.ID_PRODUTO, pp.ID_PED_PROD";

        return sql;
    }

    public void geraRelatorio() {
        context = FacesContext.getCurrentInstance();
        servletContext = (ServletContext) context.getExternalContext().getContext();

        caminhoRelatorio = servletContext.getRealPath("/relatorios/jasper/RelatorioPedidosCliente.jasper");
        mensagem += "Caminho do relatório: " + caminhoRelatorio + "\n ";

        mensagem += "Sistema Operacional: " + Funcoes.retornaSistemaOperacional().toLowerCase() + "\n ";

        parametroMap = new HashMap<String, Serializable>();
        String sql = montaSQL(cliente.getIdCliente(),
                dataInicio != null ? Funcoes.formataDataEmString(dataInicio) : "",
                dataFim != null ? Funcoes.formataDataEmString(dataFim) : "");
        parametroMap.put("sql", sql);

        /* criando novo cliente apos passagem de parametro para nova pesquisa */
        cliente = new Cliente();
        String dataIni = dataInicio != null ? Funcoes.formataDataEmString(dataInicio) : "00/00/0000";
        String dataF = dataFim != null ? Funcoes.formataDataEmString(dataFim) : "00/00/0000";
        String periodo = "Período de: " + dataIni + " a " + dataF;
        parametroMap.put("periodo", periodo);
        setExibeDialog(true);
        enviarPdf();
    }

    public void enviarPdf() {
        // Carrega o xml de definição do relatório
        try {
            HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
            // Configura o response para suportar o relatório
            response.setContentType("application/pdf");
            // response.addHeader("Content-disposition", "inline; filename=\"arquivo.pdf\"");
            response.addHeader("Content-disposition", "attachment; filename=\"arquivo.pdf\"");

            // Preenche o relatório com os parametros e o data source
            impressao = JasperFillManager.fillReport(caminhoRelatorio, parametroMap, HibernateUtil.recuperaConexao());
            // Exporta o relatório
            JasperExportManager.exportReportToPdfStream(impressao, response.getOutputStream());
            // Salva o estado da aplicação no contexto do JSF
            context.getApplication().getStateManager().saveView(context);
            // Fecha o stream do response
            context.responseComplete();
        } catch (Exception e) {
            setExibeDialog(true);
            mensagem += e;
        }
    }
}

Espero ter ajudado. Tive vários problemas para geração de relatórios em PDF, e pesquisando aqui e ali fui reunindo as informações e consegui montar algo que realmente funcionasse.
Abs,
Lessandro

30 Comentários »

  1. Você pode me explicar porque é necessária a linha

    context.getApplication().getStateManager().saveView(context)? O que acontecerá se esta linha for omitida esta linha?

    Abraço

    Comentário por Eduardo Estudante — novembro 16, 2010 @ 12:22 pm

    • Olá amigo.
      Ele salva uma cópia do pdf que está sendo exibido no cliente.
      Abs,
      Lessandro

      Comentário por semprejava — novembro 16, 2010 @ 10:35 pm

  2. olá amigo, belo post…aliás, todos eles. é importante que exista essa troca de informações entre nós programadores…

    seguinte: tenho um na minha pagina, quando mando imprimir um relatório, não aparece nenhuma mensagen que foi impresso com sucesso. estou mandando atualizar a mensagem após a impressao do relatorio. se não imprimo o relatorio, aparece a mensagem…o q pode ser??

    Comentário por vitor — janeiro 13, 2011 @ 9:16 am

    • Olá amigo, é isso mesmo… A troca de informações enriquece o crescimento de todos nós.
      Então, se foi o que entendi, então existe um problema justamente no método de impressão do seu relatório.
      Possivelmente algum parâmetro que você está passando para ele, que por algum motivo está causando alguma exceção.
      Tente colocar dentro do método um:

      try { 
         Monta relatório, enfim, preenche parâmetros e exibe  
      } catch(Exception e) {
         System.out.println('Ocorreu um erro ': + e);
      } 
      

      Com isso você consegue capturar que tipo de erro está acontecendo e possivelmente
      resolver o seu problema.
      Abs,
      Lessandro

      Comentário por semprejava — janeiro 13, 2011 @ 5:46 pm

  3. Entendi que você passou a query para jasper reporter pelo parametro sql.
    Agora é a minha duvida. Como vc usa esse paraemtro la no jasper?

    obrigado

    Comentário por Marcelo — fevereiro 23, 2011 @ 11:06 pm

  4. Olá Lessandro, tudo bem ?
    Gostaria de parabeniza-lo pelo blog, esta me ajudando muito !
    Estou com dificuldades na hora de implementar os cods acima, seria possivel voce disponibilizar o projeto ?
    []s

    Comentário por Reinaldo — outubro 10, 2011 @ 12:09 pm

    • Fala Reinaldo, td bem?
      Então, esse projeto foi desenvolvido a algum tempo atrás, e estava hospedado num servidor particular meu.
      Como tive problemas com o servidor, não tive tempo ainda de colocá-lo novamente no ar.
      Tenho um projeto no Git que pode te ajudar, o link está aqui mesmo no blog. Se o link estiver quebrado
      envie novamente uma mensagem que vou disponibilizá-lo novamente.
      Abs,
      Lessandro

      Comentário por semprejava — outubro 11, 2011 @ 10:34 am

  5. Lessandro, achei seu projeto la no Git, fiz o download pra estudar melhor o codigo, so que estou com problemas na hora de importar, tanto para o eclipse quanto para o NetBeans, ele da um erro no repositorio do PrimeFaces, fiz as devidas mudanças de acordo com o site no pom.xml mais ele continua dando erro nos imports. Teria como voce me ajudar ?
    Obrigado
    []s

    Comentário por Reinaldo — outubro 14, 2011 @ 1:46 pm

  6. Isso, era do Git msm… Possivelmente porque o pom.xml encontra-se desatualizado. Algum repositório deve ter sido alterado desde então.
    Me informe os erros, quais repositórios estão ocorrendo que faço os testes pra vc, ou manualmente vc pode ir checando se as url’s
    estão ainda no ar.
    Abs,
    Lessandro

    Comentário por semprejava — outubro 14, 2011 @ 1:54 pm

  7. Ok, revisei tds os repositórios, o do prime e do maven estavam desatualizados ai substitui o do maven pelo (http://mirrors.ibiblio.org/pub/mirrors/maven/) e do prime (http://repository.primefaces.org) … Mais mesmo assim, ainda da os seguintes erros nas classes :

    FaseListener -> import org.primefaces.component.PartialViewRoot; import org.primefaces.context.RequestContextImpl;

    ViewExpiredExceptionExceptionHandler -> import org.primefaces.component.PartialViewRoot; import org.primefaces.context.RequestContextImpl;

    Não faz diferença se eu abrir o projeto no eclipse e usar o tomcat faz ?

    []s

    Comentário por Reinaldo — outubro 15, 2011 @ 7:51 am

    • Pelo erro não…Esses dois imports: import org.primefaces.component.PartialViewRoot; import org.primefaces.context.RequestContextImpl; se não me engano
      são duas classes que estão presentes nessa versão do primefaces. Se você estiver usando no maven uma versão mais nova do primefaces, essas classes
      foram removidas, no momento o redirecionamento lá no FaseListener pode ser feito de outra forma, através de um redirect normal pelo FacesContext.
      Abs

      Comentário por semprejava — outubro 15, 2011 @ 9:16 pm

      • Consegui resolver o problema Lessandro, mudei a versão do prime …
        So que agora nao consigo compilar o projeto, é que nunca trabalhei com maven e estou com um pouco de dificuldades …
        Ja coloquei o maven no path e ao executar o comando compiler:compile ele da uma exception de nullpointer, existe outra forma de compilá-lo ?
        Abraço

        Comentário por Reinaldo — outubro 16, 2011 @ 9:23 pm

  8. Obs.: Ja troquei o jar do prime para o 2.1, 2.2, 2.2.1, mais o erro persiste …

    Comentário por Reinaldo — outubro 15, 2011 @ 8:14 am

    • Esse erro de nullpointer está parecendo ocorrer com o eclipse. Se não me engano o projeto que está no git é para o
      Netbeans. Já tive esse problema de nullPointer em outros projetos durante o deploy, ocorre geralmente com a versão
      ganymede ou galileo Tente o indigo. Outra coisa, faça um teste com o Glassfish ao invés do tomcat. Abs, Lessandro

      Comentário por semprejava — outubro 16, 2011 @ 10:02 pm

      • Consegui executar o projeto, fiz o que vc me falou, usei o NetBeans com o Glassfish deu certo :-D.
        Vai me ajudar muito no tcc …
        Obrigado pela ajuda.

        Comentário por Reinaldo — outubro 17, 2011 @ 12:52 am

      • Que isso, precisando estamos aí.
        Abs,
        Lessandro

        Comentário por semprejava — outubro 17, 2011 @ 7:58 am

  9. Cara, seu artigo salvou a nossa vida aqui… rs

    Valeu

    Comentário por Douglas C. R. Paes — novembro 8, 2011 @ 11:22 pm

    • Que isso, precisamos estamos aqui.
      Fico feliz que tenha lhe ajudado,
      Abs,
      Lessandro

      Comentário por semprejava — novembro 8, 2011 @ 11:49 pm

  10. Santo Lessandro.

    Tava me quebrando pra gerar essa porra. e de vários tutoriais, esse foi o que me salvou.

    Valeu ai

    Comentário por Marcel Morais Luna — janeiro 17, 2012 @ 9:59 am

  11. valeu amigo, muito obrigado pelas dicas acima… eu precisava setar ajax como false no botão e salvar o estado do context… valeu mesmo !!!

    Comentário por ricardo — abril 16, 2012 @ 10:43 am

  12. Amigo usted me ha salvado. Muchas gracias.
    solo tube que quitar el evento ajax complete y colocarlo en la propiedad oncomplete del comandbutton y listo.

    Comentário por Yovany Suarez — março 8, 2013 @ 1:58 am

  13. O seu tutorial é realmente muito bom mas meu problema persiste como algo externo. Onde trabalho preciso gerar um relatório com os dados de um processo. No momento está ocorrendo um bug nessa geração. Quando se cria um processo novo e manda imprimí-lo ele retorna vários campos null… se eu fechar o processo salvo e abrí-lo de novo o relatório gerado vem completo, porém no ato da criação, após salvo o processo, o sistema parece pegar um objeto incompleto ou inexistente no banco de dados, tornando impossível a criação de um processo e impressão de seu conteúdo sem antes ter de reabrí-lo. Tem alguma idéia de como resolver isso?

    Comentário por Vítor Leite — maio 6, 2013 @ 9:44 am

    • Olá Vítor, bom dia.
      Então, será que após a gravação seu objeto está sendo atualizado, ou seja, o hibernate está trazendo
      o seu objeto com Id? Talvez vc precise realizar nesse método que captura o objeto após a gravação
      um flush, para carregá-lo atualizado na memória. Qualquer coisa, tente colocar o erro aqui, que posso
      tentar lhe ajudar…
      Abs,
      Att,
      Lessandro

      Comentário por semprejava — maio 8, 2013 @ 12:03 pm

  14. Olá, Lessandro.

    Eu precisava de uma ajuda sua. Talvez possa me ajudar. É o seguinte:
    Eu tenho uma aplicação que gera relatórios em pdf perfeitamente, mas ela tem um problema: quando eu rodo ela localmente pelo servidor tomcat, ela consegue gerar um relatório grande com mais de mil páginas em +- 5min. Até aí tudo bem, entretanto, quando eu mando gerar este relatório no ambiente de desenvolvimento ou produção (servidor websphere), quando dá 3 min, a sessão cai e vai para uma pagina de erro padrão da aplicação.

    Como que eu faço para ele gerar o relatório no ambiente de desenvolvimento sem cair a sessão??? Uso backing bean. As tecnologias que uso: richface, maven, ireport, jboss seam.

    Obrigado pela atenção.

    Comentário por Renan — agosto 21, 2013 @ 11:04 pm

    • Olá amigo, boa noite.
      Essa chamada está dentro de uma transação? Possivelmente a sua sessão está sendo fechada após esse tempo “standby”. No seu web.xml
      verifique também o timeout da aplicação. Não sei as suas configurações específicas, mas nesse caso é necessário dar uma avaliada
      nessas questões.
      Abraços

      Comentário por semprejava — agosto 21, 2013 @ 11:50 pm

      • No meu web.xml ele não tem nada de timeout.

        Estava pensando em colocar

        20

        Só não sei se é a melhor solução.

        Comentário por Renan — agosto 22, 2013 @ 9:43 am

      • Como lhe disse, essa é uma das configs que você tem que fazer em sua app. A mesma também precisa ter uma arquitetura transacional muito bem configurada.

        Comentário por semprejava — agosto 22, 2013 @ 9:46 am

      • Colocar session config e session timeout

        Comentário por Renan — agosto 22, 2013 @ 9:44 am

      • Entendi. Obrigado pela a atenção.

        Comentário por Renan — agosto 22, 2013 @ 9:57 am

  15. valeu cara, me ajudou bastante aqui

    Comentário por Danilo — janeiro 21, 2015 @ 10:16 am


RSS feed for comments on this post. TrackBack URI

Deixe um comentário

Blog no WordPress.com.