Swing + iReport + Hibernate

Pessoal,

Depois de auxiliar uma de nossas companheiras indicando o tópico Swing + iReport + TopLink (em http://www.guj.com.br/posts/list/122379.java), fui abordado por outro amigo querendo saber o que fazer quando é para usar o Hibernate.

Farei a descrição aqui da minha solução para o caso, de maneira semelhante ao que fiz no tópico que escrevi anteriormente.

I. Bibliotecas Utilizadas

Para essa aplicação, estou usando o JDK1.6 e configurei o uso das seguintes bilbiotecas:

beansbinding-1.2.1.jar
mysql-connector-java-5.1.7-bin.jar
commons-beanutils-1.7.jar
commons-digester-1.7.jar
commons-javaflow-20060411.jar
iReport.jar
itext-1.3.1.jar
jasperreports-3.0.0.jar
jcommon-1.0.0.jar
antlr-2.7.6.jar
commons-collections-2.1.jar
dom4j-1.6.1.jar
ehcache-1.6.0-beta3.jar
ejb3-persistence.jar
hibernate-annotations.jar
hibernate-commons-annotations.jar
hibernate-core.jar
hibernate-entitymanager.jar
hibernate3.jar
javassist-3.4.GA.jar
jta-1.1.jar
commons-logging-1.0.2.jar
hibernate-validator.jar
hibernate-search.jar
jms.jar
jsr250-api.jar
lucene-core.jar
solr-common.jar
solr-core.jar
slf4j-simple-1.5.6.jar
slf4j-log4j12-1.5.6.jar
slf4j-api-1.5.6.jar

II. Configurando o Hibernate

Neste caso, como usaremos Hibernate, devemos mudar completamente a “infra-estrutura” para persistência de classes, e usar o que é apropriado para esse framework. Começaremos por descartar qualquer gerenciador de entidade que foi instanciado em qualquer classe e o arquivo application.xml que porventura você criou, e recomeçaremos do zero os ajustes necessários.

A primeira coisa a fazer é criar as classes de persistência e o arquivo hibernate.cfg.xml. Para isso, basta seguir o tutorial do NetBeans que está descrito no link http://www.netbeans.org/kb/docs/java/hibernate-java-se_pt_BR.html

Faça apenas os passos “Adicionando o suporte ao Hibernate ao projeto” e “Gerando arquivos de mapeamento Hibernate e classes Java”.

III. A classe Reports

Agora mostrarei a vocês como é a classe Reports, que chama os formulários .jasper

Observem que as strings QUERY_CLIENTES e QUERY_FORNECEDORES são as consultas chamadas usando a classe Cadastro que mapeia tabela cadastro do banco.

package <nomedoseupacote>;

import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.view.JasperViewer;
import mechoffice.util.HibernateUtil;
import org.hibernate.Query;
import org.hibernate.Session;

/**
 *
 * @author hector
 */
public class Reports {

    private static String QUERY_CLIENTES="from Cadastro c where idpermissao = 5";
    private static String QUERY_FORNECEDORES="from Cadastro c where idpermissao = 6";

    public Reports() {
        
    }

  private InputStream Relatorio(String arquivo){
        InputStream relatorio = Reports.class.getResourceAsStream(arquivo);
        return relatorio;
    }

    private List executeHQLQuery(String hql) {

            Session session = HibernateUtil.getSessionFactory().openSession();
            session.beginTransaction();
            Query q = session.createQuery(hql);
            List resultList = q.list();
            session.getTransaction().commit();
            return resultList;
    }

    private void Execute(String relatorio, String hql) throws JRException{
        JRBeanCollectionDataSource ds = new JRBeanCollectionDataSource(executeHQLQuery(hql));
        JasperPrint jp = JasperFillManager.fillReport(this.Relatorio(relatorio), new HashMap(), ds);
        JasperViewer.viewReport(jp, false);
    }

    public void Clientes(){
        try{            
            this.Execute("Clientes.jasper", QUERY_CLIENTES);
        } catch (Exception e) {
            System.out.print(e.getMessage());
        }
    }

    public void Fornecedores(){
        try{          
            this.Execute("Fornecedores.jasper",QUERY_FORNECEDORES);
        } catch (Exception e) {
            System.out.print(e.getMessage());
        }
    }
}

IV. Abrindo o relatório

Como no outro tópico, eu informei o código fonte do arquivo Clientes.jxml, então não repetirei aqui. Ele deve ser compilado para o formato .jasper, usando o iReport, e salvo na pasta src do seu projeto.

Para abrir o relatório, basta colocar um evento no seu menu ou botão, como esse aqui:

private void mniRClientesActionPerformed(java.awt.event.ActionEvent evt) {                                             

    Reports rclientes = new Reports();
    rclientes.Clientes();
    
}

Muito bom seu post.

Mas como eu configuro o classpath do ireport com hibernate annotations pra criar os relatórios?

V. O arquivo hibernate.cfg.xml e o ehcache.xml

Aqui coloco minha sugestão de configuração para o Hibernate e o EhCache. Logo abaixo do código, colocarei algumas explicações:

  1. hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <!-- <property name="hibernate.show_sql">true</property> -->
    <property name="hibernate.hbm2ddl.auto">update</property>
    <property name="transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
    <property name="hibernate.cache.provider_class">net.sf.ehcache.hibernate.SingletonEhCacheProvider</property>
    <property name="hibernate.cache.provider_configuration">/ehcache.xml</property>
    <property name="hibernate.cache.use_minimal_puts">false</property>
    <property name="hibernate.cache.use_query_cache">true</property>
    <property name="hibernate.cache.use_second_level_cache">true</property>
    <property name="hibernate.cache.use_structured_entries">true</property>
    <property name="hibernate.connection.username">mechoffice</property>
    <property name="hibernate.connection.password">mechoffice</property>
    <mapping resource="mechoffice/entity/Modelo.hbm.xml"/>
    <mapping resource="mechoffice/entity/Cadastro.hbm.xml"/>
    <mapping resource="mechoffice/entity/Cidade.hbm.xml"/>
    <mapping resource="mechoffice/entity/Permissao.hbm.xml"/>
    <mapping resource="mechoffice/entity/Tipops.hbm.xml"/>
    <mapping resource="mechoffice/entity/Tipo.hbm.xml"/>
    <mapping resource="mechoffice/entity/Itensatend.hbm.xml"/>
    <mapping resource="mechoffice/entity/Formapagto.hbm.xml"/>
    <mapping resource="mechoffice/entity/Veiculo.hbm.xml"/>
    <mapping resource="mechoffice/entity/Marca.hbm.xml"/>
    <mapping resource="mechoffice/entity/Estado.hbm.xml"/>
    <mapping resource="mechoffice/entity/Estoque.hbm.xml"/>
    <mapping resource="mechoffice/entity/Menu.hbm.xml"/>
    <mapping resource="mechoffice/entity/Categoria.hbm.xml"/>
    <mapping resource="mechoffice/entity/Atendimento.hbm.xml"/>
    <mapping resource="mechoffice/entity/Prodserv.hbm.xml"/>
  </session-factory>
</hibernate-configuration>
  1. ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd">
  <diskStore path="java.io.tmpdir"/>
  <defaultCache
    maxElementsInMemory="10000"
    eternal="false"
    timeToIdleSeconds="120"
    timeToLiveSeconds="120"
    overflowToDisk="true"
    diskPersistent="true"
    diskExpiryThreadIntervalSeconds="120"
    memoryStoreEvictionPolicy="LRU"
  />
  <cache
    name="org.hibernate.cache.UpdateTimestampsCache"
    maxElementsInMemory="5000"
    eternal="true"
    overflowToDisk="true"/>
  <cache
    name="org.hibernate.cache.StandardQueryCache"
    maxElementsInMemory="5"
    eternal="false"
    timeToLiveSeconds="120"
    overflowToDisk="true"/>
</ehcache>

Os dois arquivos devem ficar dentro da pasta src, mas fora da pasta que é o pacote do seu projeto. Esses arquivos serão chamados pelas classes do Hibernate para configuração.

Observem que no arquivo hibernate.cfg.xml, não existem a linha que informa o nome do servidor e o nome do banco de dados que será conectado. Isso é informado pela configuração hibernate.connection.url, mas eu determino isso no executável que chamará a aplicação. Por exemplo: eu posso criar um arquivo .bat, ou um atalho do Windows, ou um arquivo shell executável no Linux com a seguinte linha:

java -Dhibernate.connection.url=jdbc:mysql://servidor:3306/banco -jar NomeDaSuaAplicacaoJava.jar

Se a aplicação estiver em um computador cliente, e o banco de dados no servidor da rede, então basta definir os parâmetros servidor e banco dessa linha.

Outra detalhe é a linha comentada para hibernate.show_sql. Descomente-a se precisar depurar a query na hora de executar a sua aplicação, para avaliar erros ou velocidade.

Espero que isso possa ajudar.

Abs,

[quote=moacirjava]Muito bom seu post.

Mas como eu configuro o classpath do ireport com hibernate annotations pra criar os relatórios?[/quote]

Moacir,

Isso não é necessário. Apenas crie o relatório no iReport, sem precisar especificar se vai usar Hibernate ou Toplink.

Veja que no tópico Swing + iReport + Toplink, eu apenas coloquei o codigo fonte do jxml criado no iReport, mas sem precisar definir essa classpath.

A configuração do classpath somente é necessária para a sua aplicação, porque ela precisa usar os pacotes do Hibernate, e etc.

Abs,

Não entendi :?

[quote=moacirjava]
Não entendi :? [/quote]

Vou usar como referência o uso do Netbeans.

Quando você define as bibliotecas que serão utilizadas pela sua aplicação, os pacotes que fazem parte dessa biblioteca devem estar em algum lugar (uma pasta no seu computador).

No momento que você define que sua aplicação vai usar o Hibernate, por exemplo, automaticamente o Netbeans chama a biblioteca correspondente e associa ao seu projeto todos os arquivos que estão definidos na classpath da biblioteca Hibernate, e que passaram a ser parte (melhor dizendo: copiados) para a classpath usada pela sua aplicação (diretório lib) [no Netbeans, abra o menu Ferramentas --> Bibliotecas]

Então a única coisa que precisa se preocupar é definir nas bibliotecas que serão utilizadas pela sua aplicação o local dos arquivos que compõem essa biblioteca, caso você faça o download das versões mais recentes. Isso é definir o Classpath.

Ao construir o projeto, o Netbeans analisa as bibliotecas utilizadas e copia cada um dos arquivos que compõem a biblioteca (definida em seu próprios classpath) para a pasta lib do seu projeto compilado.

Abs,

estou usando a classe report como citado acima , esta dessa forma :

package Relatorios;


import Dao.HibernateUtil;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.view.JasperViewer;
import org.hibernate.Query;
import org.hibernate.Session;


public class Reports {
  private static String Query_cidade ="from Cidade";
    

    public Reports() {

    }

  private InputStream Relatorio(String arquivo){
     InputStream relatorio = Reports.class.getResourceAsStream(arquivo);
    
     return relatorio;
    }

    private List executeHQLQuery(String hql) {

            Session session = HibernateUtil.getSessionFactory().openSession();
            session.beginTransaction();
            Query q = session.createQuery(hql);
            List resultList = q.list();
            session.getTransaction().commit();
            return resultList;
    }

    private void Execute(String relatorio, String hql) throws JRException{
        JRBeanCollectionDataSource ds = new JRBeanCollectionDataSource(executeHQLQuery(hql));
        JasperPrint jp = JasperFillManager.fillReport(this.Relatorio(relatorio), new HashMap(), ds);
        JasperViewer.viewReport(jp, false);
    }

    public void Cidade(){
        try{
            this.Execute("C:\\PROJETO\\SysJuri\\Cidade.jasper", Query_cidade);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Esta em trazendo a lista de Cidades normalmente, e meu .jasper só existe campos referente a propia tabela, porem quando vai passa pelo metodo private InputStream Relatorio(String arquivo){ , esta apresentando o seguinte erro :

java.lang.NullPointerException
        at java.io.ObjectInputStream$PeekInputStream.read(ObjectInputStream.java:2266)
        at java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2279)
        at java.io.ObjectInputStream$BlockDataInputStream.readShort(ObjectInputStream.java:2750)
        at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:780)
        at java.io.ObjectInputStream.<init>(ObjectInputStream.java:280)
        at net.sf.jasperreports.engine.util.ContextClassLoaderObjectInputStream.<init>(ContextClassLoaderObjectInputStream.java:53)
        at net.sf.jasperreports.engine.util.JRLoader.loadObject(JRLoader.java:200)
        at net.sf.jasperreports.engine.JasperFillManager.fillReport(JasperFillManager.java:603)
        at Relatorios.Reports.Execute(Reports.java:53)
        at Relatorios.Reports.Cidade(Reports.java:59)

estou fuçando ha alguns dias já, nao sei mais o que fazer :?

Ricardo,

Eu deixei de programar em JAVA já faz algum tempo…mas pelo que parece, esta mensagem de erro refere-se ao acesso ao arquivo.

Verifique duas coisas: primeiro se o .jasper está no caminho correto, e em seguida, se a pasta e o arquivo tem permissão de leitura.

Outra dica: procure usar algo que você possa parametrizar o caminho deste arquivo, de forma que não precise incluir o local no código. Por exemplo: em um arquivo XML coloque um parâmetro “caminhojasper”, e no código coloque algo para ler este parâmetro como uma string e concatenar com o nome do arquivo.

Abs,

agradeço pela dica!

sim, o caminho esta certo e a pasta te permissão…

mas o retorno do metodo é null ;/

tem mais alguma ideia?

att.
abss

Sim, inverta as barras do caminho de \ para /, e não use barras duplas…

Abs,

ja tentei, as “” “/”, somente o nome do arquivo.jasper, coloquei o arquivo em varais pastas, refiz o arquivo em 2 versoes do ireport 3.6.1, 3.7.2…
tentei de 2 computadores…
… as bibliotecas estão ok…
no arquivo jasper apenas inseri os campos dessa form $F{cidadeId};
nao sei mais o que fazer
;/

abs

hector , agradeço sua atenção, resolvi adicionando essa benditaaa bliblioteca

-> * com-jaspersoft-ireport-jasperserver