GARANTIR DESCONTO

Fórum iReport + JSF classes para gerar relatório na página jsf #389723

30/10/2010

0

Pessoal Boa Tarde,   Estou com dúvidas no meu projeto, como desenvolver as classes para chamar o meu arquivo .jasper. Instalei o plugin do iReport no Netbeans esta funcionando normalmente ja estou com um relato.jasper compilando normalmente. A dúvida é como desenvolver as classes para chamar esse arquivo nas páginas jsf?   Se for possível indicar uma fonte de pesquisa alem do google eu agradeço.   Além dessa classe de conexão abaixo eu tenho que desenvolver um servlet ou manager Bean?  
 package jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class ConnectionFactory {
    
    private Connection conexao;
 public ConnectionFactory() throws ClassNotFoundException, SQLException {
  criaConexao();
 }
 public void criaConexao() throws ClassNotFoundException, SQLException {
  String endereco = "localhost";
  String porta = "5432";
  String banco = "secretarias";
  String usuario = "postgres";
  String senha = "post";
  try {
   Class.forName("org.postgresql.Driver");
   conexao = DriverManager.getConnection("jdbc:postgresql://" + endereco
     + ":" + porta + "/" + banco + "?user=" + usuario
     + "&password=" + senha);
  } catch (ClassNotFoundException ex) {
   throw ex;
  } catch (SQLException ex) {
   throw ex;
  }
 }
     
 public void fechaConexao() throws SQLException {
  conexao.close();
  conexao = null;
 }
 public boolean isFechada() {
  try {
   return conexao.isClosed();
  } catch (SQLException ex) {
   return false;
  }
 }
 public Connection getConexao() {
  return conexao;
 }
}
  
Roberto Rodrigues.

Roberto Rodrigues.

Responder

Posts

30/10/2010

Davi Costa

Roberto seguinte,
qual estratégia usar, se vai usar servlet ou um managedbean,
vai depender bastante da tua arquitetura. Mas não há necessidade alguma de nenhum dos dois.
Gosto bastante da estratégia de criar uma classe só para chamar relatório (por exemplo RelatorioUtils),
nela eu coloco métodos estáticos (para diminuir acoplamento e para reaproveitamento de código... pode haver mais de um caso de uso que utilize relatório) que recebem só os parâmetros necessários para executar o relatório. Essa classe utilitária pode ser chamada do seu bean ou do seu servlet dependendo do que vc estiver usando.
O código com uma pequena pesquisa vc acha rapidim alguns exemplos, posso até te passar depois caso vc não ache. Só complementando existem essencialmente duas formas de executar relatórios do jasper, um é passando a conexão e deixando o ireport executar a consulta no banco, mas vc também opde fazer a consulta nas próprias classes java e passar o datasource com os dados para executar o relátorio. Espero ter ajudado.

Att Davi
Responder

Gostei + 0

31/10/2010

Roberto Rodrigues.

Davi a possibilidade me enviar um exemplo? pois não conseguir achar um exemplo com uma só classe. Estou usando (Hibernet e Jsf).
Responder

Gostei + 0

31/10/2010

Davi Costa

Ok,

public class ReportUtil {
   
    private static String ERRO_MENSAGEM_REPORT = "Um erro ocorreu quando o relatório estava sendo executado.";
   
    //executa o relatório através de um JRBeanCollectionDataSource
    public static void executarRelatorio(String caminhoRelatorio, Map<String, Object> parametros, String nomeRel, JRBeanCollectionDataSource fonteDados) throws ReportException{
       
        FacesContext context = FacesContext.getCurrentInstance();
        HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
       
        //pega o caminho do arquivo .jasper da aplicação
        InputStream reportStream = context.getExternalContext().getResourceAsStream(caminhoRelatorio);

        /*//envia a resposta com o MIME Type
        if(tipoFormatoRelatorio.equals(TipoFormatoRelatorio.ACROBAT_PDF)){
            response.setContentType("application/pdf");
        }else if(tipoFormatoRelatorio.equals(TipoFormatoRelatorio.PAGINA_HTML)){
            response.setContentType("application/html");
        }
        */
        response.setHeader("Content-Disposition", "attachment; filename="+ nomeRel +".pdf");
        response.setContentType("application/download");
        response.setHeader("Pragma", "no-cache");
        try {
            ServletOutputStream servletOutputStream = response.getOutputStream();
           
            //envia parametros para o relatório
            if (parametros == null){
                parametros = new HashMap<String, Object>();
            }
       
            //envia para o navegador o PDF gerado
            JasperRunManager.runReportToPdfStream(reportStream, servletOutputStream, parametros, fonteDados);
            servletOutputStream.flush();
            servletOutputStream.close();
       
        } catch (JRException e) {
            e.printStackTrace();
            throw new ReportException(ERRO_MENSAGEM_REPORT);
        } catch (IOException e) {
            e.printStackTrace();
            throw new ReportException(ERRO_MENSAGEM_REPORT);
        }finally{
            context.responseComplete();
        }
    }
   
    //executa o relatorio através de uma Connection
    public static void executarRelatorio(String caminhoRelatorio, Map<String, Object> parametros, TipoFormatoRelatorio tipoFormatoRelatorio, Connection conn) throws ReportException{
       
        FacesContext context = FacesContext.getCurrentInstance();
        HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
       
        //pega o caminho do arquivo .jasper da aplicação
        InputStream reportStream = context.getExternalContext().getResourceAsStream(caminhoRelatorio);

        //envia a resposta com o MIME Type
        if(tipoFormatoRelatorio.equals(TipoFormatoRelatorio.ACROBAT_PDF)){
            response.setContentType("application/pdf");
        }else if(tipoFormatoRelatorio.equals(TipoFormatoRelatorio.PAGINA_HTML)){
            response.setContentType("application/html");
        }
       
        try {
            ServletOutputStream servletOutputStream = response.getOutputStream();
           
            //envia parametros para o relatorio
            if (parametros == null){
                parametros = new HashMap<String, Object>();
            }
       
            //envia para o navegador o PDF gerado
            JasperRunManager.runReportToPdfStream(reportStream, servletOutputStream, parametros, conn);
            servletOutputStream.flush();
            servletOutputStream.close();
       
        } catch (JRException e) {
            e.printStackTrace();
            throw new ReportException(ERRO_MENSAGEM_REPORT);
        } catch (IOException e) {
            e.printStackTrace();
            throw new ReportException(ERRO_MENSAGEM_REPORT);
        }finally{
            context.responseComplete();
        }
    }
}

Nesta classe, vai exemplo como havia citado antes, passando a conexão e já os resultados da consulta via JRBeanCollectionDataSource, esse TipoFormatoRelatorio, foi um enum que criei para dizer o tipode relatório, simplesmente só isso, como também o ReportException é só uma classe de exceção criada tb que tranquilamente vc pode adaptar para a sua necessidade.

Att Davi
Responder

Gostei + 0

01/11/2010

Roberto Rodrigues.

Davi estou com dúvidas em que incluir nesses campos abaixo:  
public static void executarRelatorio(String "/report/relatoriosecretaria.jasper" , Map parametros, String "relatoriosecretaria.jasper", JRBeanCollectionDataSource fonteDados) throws ReportException{  
 
  if (parametros == null){
                parametros = new HashMap();
            } 
 
JasperRunManager.runReportToPdfStream(reportStream, servletOutputStream, parametros, fonteDados); 
 
public static void executarRelatorio(String caminhoRelatorio, Map parametros, TipoFormatoRelatorio tipoFormatoRelatorio, Connection conn) throws ReportException{ 
             
Responder

Gostei + 0

02/11/2010

Davi Costa

Abaixo segue um exemplo de chamada de código para aquela classe que te passei.

@SuppressWarnings("unchecked")
    public void executarRelatorioUnidade() throws SgpException {
       
        List dados = new ArrayList();
         Map record = null;
         
         //varre a consulta e separa os objetos
         for (Unidade unidade : findAll()) {
   
             
             record = new HashMap();
             //coloca em um Map cada um dos campos criados
             //manualmente pelo relatorio
             record.put("cd_unidade", unidade.getId());
             record.put("ds_unidade", unidade.getDescricao());
             record.put("nm_gestor", unidade.getNomeGestor());
             record.put("ds_email_gestor", unidade.getEmailGestor());
             
             //adiciona o List dados
             dados.add(record);
         
         }
   
        //cria uma fonte de dados para coleções
        JRBeanCollectionDataSource fonteDados =
            new JRBeanCollectionDataSource(dados);
        Map<String, Object> parametros = new HashMap<String, Object>();
        parametros.put("PARAMETRO_TITULO_RELATORIO", "RELATÓRIO DE UNIDADES");
       
        ReportUtil.executarRelatorio("/relatorios/emitirUnidade/emitirUnidadesReport.jasper", parametros, TipoFormatoRelatorio.ACROBAT_PDF, fonteDados);
       
    }

Agora o código que chama uma conexão vai depender do seu projeto, pq aí vc passa a conexão para o relatório ser executado, e se usar como esse que fiz acima vai ter que ter o campos (fields) no teu relatório conforme esse trecho de código entre aspas:
 record.put("cd_unidade", unidade.getId());
 record.put("ds_unidade", unidade.getDescricao());
  record.put("nm_gestor", unidade.getNomeGestor());
  record.put("ds_email_gestor", unidade.getEmailGestor());

Att Davi
Responder

Gostei + 0

02/11/2010

Roberto Rodrigues.

Davi me desculpe mais não estou entendendo o que esta querendo me passar.   Detalhe do meu projeto:   1- Instalei o plugin iReport 3.7.5 no meu Netbeans 6.9.1; 2- Fiz a conexão do iReport com a minha base de dados Postgres; 3- Fiz um modelo de relatório no plugin relatório e salvei em um diretório report na minha aplicação;   Dúvida:   Aminha dúvida é desenvolver um padrão de classe para gerar os relatórios na página jsf! Qual proximo passo a ser feito? O que você quer de informação do me projeto pra facilitar a ajuda?    Ao pesquisar na net vi que cada um faz de uma maneira, ou seja uns ultilizão Servlet, outros uma classe conforme esta me auxiliando assim ficando confuso pra mim. Como é primeira vez que estou desenvolvedo classes pra relatórios estou confuso em que passo fazer e o que ultilizar.   Se for possivel postar um fluxo completo das classes ou enviar por email agradeço e muito mesmo ou ate mesmo uma fonte de pesquisa.
Responder

Gostei + 0

02/11/2010

Davi Costa

Roberto, a escolha vai depender muito da sua arquitetura,
nesses exemplos que te passei, a classe utilitária junto com o enum para dizer  tipo de relatório fica em um pacote util, junto com outras classes utilitária como uma DataUtil que faz formatações de data e moeda...
E no meu serviço é que chamo o relatório, deixando isso abstraído do meu bean, realmente a chamada do relatório fica no meu serviço, mas nada te impede de chamar teu relatório de dentro do próprio bean.
Eu particularmente não gosto, pois em uma das formas de chamar já podemos passar o resultado da pesquisa para o relatório e sempre envolve alguma regra de negócio, por isso gosto de fazer tudo em um serviço na minha regra de negócio.

Att Davi
Responder

Gostei + 0

02/11/2010

Roberto Rodrigues.

Davi, a minha dúvida esta no preenchimento daqueles campos que sitei acima, infelizmente não conseguir entender a sua indicação.   A possibilidade de alguem postar uma video aula mostrando essas classes pra gerar relatório?
Responder

Gostei + 0

02/11/2010

Roberto Rodrigues.

Davi fiz essa classe simples mais esta dando erro ao execulta- lá a possibilidade de ajudar?   Erro no console  
Exception in thread "main" net.sf.jasperreports.engine.JRException: java.io.FileNotFoundException: relatoriosecretaria.jasper
        at net.sf.jasperreports.engine.util.JRLoader.loadObject(JRLoader.java:84)
        at net.sf.jasperreports.engine.JasperFillManager.fillReport(JasperFillManager.java:536)
        at jdbc.ConnectionFactory.gerarRelatorio(ConnectionFactory.java:63)
        at jdbc.ConnectionFactory.main(ConnectionFactory.java:71)
Caused by: java.io.FileNotFoundException: relatoriosecretaria.jasper
        ... 4 more
Java Result: 1
CONSTRUÍDO COM SUCESSO (tempo total: 3 segundos) 
    Codigo da Classe  
 public class ConnectionFactory {
    /* Driver do banco de dados, URL, usuário e senha do banco de dados */
    static final String JDBC_DRIVER = "org.postgresql.Driver";
    static final String DATABASE_URL = "jdbc:postgresql://localhost:5432/secretarias";//localhost:5432/secretarias”;
    static final String USER = "postgres";
    static final String PASSWORD = "post";
    /* Conecta-se ao banco de dados e retorna o objeto da conexão */
    private static Connection getConnection() throws
            ClassNotFoundException, SQLException {
        /* Carrega o driver do postgreSQL */
        Class.forName(JDBC_DRIVER);
        /* Cria um objeto de conexão */
        Connection connection = DriverManager.getConnection(DATABASE_URL, USER, PASSWORD);
        return connection;
    }
    /* Gera relatório */
    public void gerarRelatorio() throws
            JRException, Exception {
        /* Chama o método getConnection para obter um objeto Connection,
        utiliza-o para obter um objeto Statement e realiza uma consulta
        armazendo o resultado em um ResultSet
         */
        Connection connection = getConnection();
        Statement statement = connection.createStatement();
        ResultSet result = statement.executeQuery("select *from cadsecretaria;");
        /* Cria um JRResultSetDataSource com o resultado da consulta */
        JRResultSetDataSource jrrs = new JRResultSetDataSource(result);
        /* Cria um HashMap com parâmetros do relatório.
        Caso não seja atribuído algum valor aos parâmetros estes
        assumem o valor padrão.
         */
        Map parametros = new HashMap();
        /* Cria um arquivo .jrprint (relatório preenchido) utilizando o
        Relatorio.jasper (design), os parâmetros e o
        JRResultSetDataSource que é o resultado da consulta.
         */
        JasperPrint jp = JasperFillManager.fillReport("relatoriosecretaria.jasper", parametros, jrrs);
        /* Exibe o relatório */
        JasperViewer.viewReport(jp);
    }
    public static void main(String[] args) throws
            JRException, Exception {
        new ConnectionFactory().gerarRelatorio();
    }
}
 
Responder

Gostei + 0

02/11/2010

Davi Costa

Roberto, esse erro fala que não está achando o arquivo.
Primeira coisa passa o caminho dele completo.... por exemplo "C:\.....",
se for uma aplicação web passa a pasta que deve estar em web-inf e coloca a hierarquia a partir dessa
pasta por exemplo: "reports\relatoriosecretaria.jasper".
E caso não tenha feito quando tiver usando o ireport ou o plugin na sua IDE tecla com o botão direito no arquivo e escolhe a opção compile, para compilar seu relatório e até bom que se seu relatório tiver algum problema na hr de compilar ele tb faz uma verificação.

Att Davi
Responder

Gostei + 0

03/11/2010

Dyego Carmo

Opa !

Conseguiu resolver colega ?

ValeuZ !
Responder

Gostei + 0

03/11/2010

Roberto Rodrigues.

Pessoal a menssagem de erro no console mudou após inserir co caminho indicado,  segue abaixo a menssagem de erro e código atualizado.:  
 log4j:WARN No appenders could be found for logger (net.sf.jasperreports.extensions.ExtensionsEnvironment).
log4j:WARN Please initialize the log4j system properly.
Exception in thread "main" net.sf.jasperreports.engine.JRException: Unknown column name : cadsecretaria_codigosecretaria
        at net.sf.jasperreports.engine.JRResultSetDataSource.getColumnIndex(JRResultSetDataSource.java:355)
        at net.sf.jasperreports.engine.JRResultSetDataSource.getFieldValue(JRResultSetDataSource.java:112)
        at net.sf.jasperreports.engine.fill.JRFillDataset.setOldValues(JRFillDataset.java:821)
        at net.sf.jasperreports.engine.fill.JRFillDataset.next(JRFillDataset.java:785)
        at net.sf.jasperreports.engine.fill.JRBaseFiller.next(JRBaseFiller.java:1482)
        at net.sf.jasperreports.engine.fill.JRVerticalFiller.fillReport(JRVerticalFiller.java:126)
        at net.sf.jasperreports.engine.fill.JRBaseFiller.fill(JRBaseFiller.java:946)
        at net.sf.jasperreports.engine.fill.JRBaseFiller.fill(JRBaseFiller.java:864)
        at net.sf.jasperreports.engine.fill.JRFiller.fillReport(JRFiller.java:84)
        at net.sf.jasperreports.engine.JasperFillManager.fillReport(JasperFillManager.java:624)
        at net.sf.jasperreports.engine.JasperFillManager.fillReport(JasperFillManager.java:540)
        at jdbc.ConnectionFactory.gerarRelatorio(ConnectionFactory.java:64)
        at jdbc.ConnectionFactory.main(ConnectionFactory.java:74)
Java Result: 1 
  Código da classe;  
 public class ConnectionFactory {
    /* Driver do banco de dados, URL, usuário e senha do banco de dados */
    static final String JDBC_DRIVER = "org.postgresql.Driver";
    static final String DATABASE_URL = "jdbc:postgresql://localhost:5432/secretarias";//localhost:5432/secretarias”;
    static final String USER = "postgres";
    static final String PASSWORD = "post";
    /* Conecta-se ao banco de dados e retorna o objeto da conexão */
    private static Connection getConnection() throws
            ClassNotFoundException, SQLException {
        /* Carrega o driver do postgreSQL */
        Class.forName(JDBC_DRIVER);
        /* Cria um objeto de conexão */
        Connection connection = DriverManager.getConnection(DATABASE_URL, USER, PASSWORD);
        return connection;
    }
    /* Gera relatório */
    public void gerarRelatorio() throws
            JRException, Exception {
        /* Chama o método getConnection para obter um objeto Connection,
        utiliza-o para obter um objeto Statement e realiza uma consulta
        armazendo o resultado em um ResultSet
         */

        Connection connection = getConnection();
        Statement statement = connection.createStatement();
        ResultSet result = statement.executeQuery("select *from cadsecretaria");
        /* Cria um JRResultSetDataSource com o resultado da consulta */
        JRResultSetDataSource jrrs = new JRResultSetDataSource(result);
        /* Cria um HashMap com parâmetros do relatório.
        Caso não seja atribuído algum valor aos parâmetros estes
        assumem o valor padrão.
         */

        Map parametros = new HashMap();
        
        /* Cria um arquivo .jrprint (relatório preenchido) utilizando o
        Relatorio.jasper (design), os parâmetros e o
        JRResultSetDataSource que é o resultado da consulta.
         */

        JasperPrint jp = JasperFillManager.fillReport("relatorios/report/relatoriosecretaria.jasper", parametros, jrrs);
        JasperExportManager.exportReportToPdfFile(jp, "relatoriosecretaria.pdf");
        /* Exibe o relatório */

       // JasperViewer.viewReport(jp);
JasperViewer.viewReport( "relatoriosecretaria.pdf", false );
    }
 
    public static void main(String[] args) throws
            JRException, Exception {
        new ConnectionFactory().gerarRelatorio();
    }
}
     
Responder

Gostei + 0

03/11/2010

Davi Costa

Roberto, é isso aí, na sua classe java agora está tudo ok.
Esse erro que está dando aí é no ireport.
Dando uma olhada por cima, parece, que vc não tem esses campos no relatório (cadsecretaria_codigosecretaria).
Não sei se fez essa classe para testar, mas ela está muito acoplada, tenta rever akela estratégia de deixar uma clase que receba todos os parametros para vc passar para o relátório, pq da forma que está todos seus casos de uso que precisarem de relatório vai repetir bastante código.

Att Davi

Responder

Gostei + 0

03/11/2010

Roberto Rodrigues.

Davi esse é ´o meu primeiro campo do relatório, eu não entendir a sua estratégia.
Responder

Gostei + 0

03/11/2010

Davi Costa

OK,
seu relatório executa só c om Ireport né?
Se funcionar, um teste que vc pode fazer é remover todos os seus fields que vem na consulta.
è criar os fields com os mesmos nomes do resultset, e dando para eles seus tipos corretos de retorno, String ou integer.. e por aí vai, testa primeiro só com uma coluna para quando vc deixar rodando tudo ok sem erro, adiciona os outros.


A respeito da estratégia já até te expliquei, vou tentar ser mais claro.
Caso vc tenha outro caso de uso que chame outro relatório vc vai ter que repetir meio mundo de código dnovo.
Vc pode criar uma classe utilitária como a que te passei, mas obviamente que atenda a sua necessidade. E nesa classe cria um método estático e passa como parâmtros todos os dados para montar o relátório, parecido com a classe que te passei. de cara um parâmetro é o caminho do relatório, outro pode ser o ResultSet  outro os parâmetros.Dessa forma, vc tem um único método que chama os relatórios que atenda a todas a necessidades.
Caso vc tenha usar ese seu factory, é só passar para ele os parâmetros necessários para ele também para que ele chame essa classe c o método estático para gerar relatório que eu tenho tanto falado. de repente pode ter ummétodo na Factory, que receba o caminho do relatório, talvez a query a ser executada para gerar o ResulSet e os parametros do relatório.  A respeito do parametro do relatorio percebi q está só dando um new, o Ireport precisa pq no relatório pode ter alguns parametros, mas se no seucaso não tiver não tem problema dá sempre um new nele.
Mas ainda acho melhor no próprio código desse método que fica na classe utilitária vc pode colocar:

if(parametros == null){
        parametros = new HashMap();
}

Já diminui tb algumas linhas de código instanciando esse atributo desnecessariamente, se não me engano  vc até havia me perguntando o pq desse trecho de código no método q te enviei.

att Davi
Responder

Gostei + 0

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar