Mostrando postagens com marcador hibernate. Mostrar todas as postagens
Mostrando postagens com marcador hibernate. Mostrar todas as postagens

domingo, 22 de junho de 2008

Eliminando o XML de configuração do Hibernate

Olá amiguinhos,

Você ainda usa o arquivo hibernate.cfg.xml? Pois é, eu também usava, até uns dias atrás. Vou explicar como é fácil usar a classe Configuration do Hibernate.

Suponho que você esteja usando um construtor para iniciar as configurações do Hibernate. Veja só como ficaria o construtor.

 public HibernateInitialize() {
Configuration cfg = new AnnotationConfiguration()
.addAnnotatedClass(SuaClasseAnotada.class)
.setProperty(Environment.HBM2DDL_AUTO, "update")
.setProperty(Environment.SHOW_SQL, "false")
.setProperty(Environment.DIALECT,
"org.hibernate.dialect.MySQLInnoDBDialect")
.setProperty("hibernate.connection.driver_class",
"com.mysql.jdbc.Driver")
.setProperty("hibernate.connection.url",
"jdbc:mysql://localhost:3306/test")
.setProperty("hibernate.connection.username", "test")
.setProperty("hibernate.connection.password", "test")
.setProperty("hibernate.connection.pool_size", "10");

SessionFactory sf = cfg.buildSessionFactory();
session = sf.openSession();
tx = session.beginTransaction();
}


Dispensa comentários né? Você acaba de montar a mesma estrutura do XML mas dentro da classe que faz a inicialização do Hibernate.

Nesse link você encontra todas as propriedades para JDBC do Hibernate.

Enjoy...

quinta-feira, 12 de junho de 2008

Salvando fotos no banco de dados com Hibernate

Olá amiguinhos,

Vi nos fóruns por ae que muita gente tem dúvida quanto a isso. Eu particularmente, prefiro salvar no banco de dados, se forem fotos simples de um cadastro. Acho que evita muitos problemas futuramente.

O arquivo com todos os arquivos do projeto pode ser baixado nesse link: Download

Nesse exemplo que vou ensinar é bem simples, nem me dei ao luxo de fazer uma mega interface com o Swing, usei o FlowLayout como padrão mesmo e taquei os componentes lá. A beleza do negócio está no Hibernate hehe. Bom, vamos lá, vou ensinar passo a passo. Estou usando o Maven como gerenciador de projetos, que na minha opinião, é perfeito. Mas se você não quiser usar o Maven, basta adicionar no Classpath as bibliotecas do Hibernate e MySQL. Antes de começar, verifique se você possui o MySQL instalado na sua máquina, e então crie um database com o nome de hibernate_object:

CREATE DATABASE 'hibernate_object';


Crie um usuário para esse database agora com o seguinte comando:

GRANT ALL ON hibernate_object.* TO 
'hibernate'@localhost IDENTIFIED BY 'hibernate123';


Perfeito!!! Agora pode fechar o MySQL que agora vamos só trabalhar com Java. Se você não for usar o Maven, crie um projeto com o nome de HibernateObject. Se estiver usando Maven, crie um archtype padrão e adicione as dependências do Hibernate e MySQL:

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>br.org.hibernateobject</groupId>
<artifactId>HibernateObject</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>HibernateObject</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.3.1.GA</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
</dependencies>
</project>


Para criar a estrutura de diretórios padrão do Maven, basta usar esse comando (Se você estiver usando Linux é claro ;) ):

$ mkdir -p src/{main,test}/{java,resources}


Agora basta dar o comando do Maven para atualiza o projeto para o Eclipse:

$ mvn eclipse:eclipse


Vamos botar a mão na massa agora. Vamos precisar da seguinte estrutura de classes:

Cadastro
CadastroDao
Hibernateinitialize
Principal


E o arquivo XML do Hibernate:

hibernate.cfg.xml


Primeiro, vamos criar a classe Cadastro, que terá a seguinte estrutura:

package br.org.hibernateobject;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Table;

@Entity
@Table(name = "cadastro")
public class Cadastro {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id_cadastro")
private int id;

@Column(length = 100)
private String nome;

@Lob
private byte[] foto;

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public byte[] getFoto() {
return foto;
}

public void setFoto(byte[] foto) {
this.foto = foto;
}

public String getNome() {
return nome;
}

public void setNome(String nome) {
this.nome = nome;
}
}


O segredo pra funcionar esse esquema é o annotation @Lob, que cria um campo no banco de dados do tipo Blob ou Clob. Eu não testei em outros bancos, somente no MySQL, mas creio que essa mesma annotation dá pra ser usada em outros tipos.

Agora vamos criar a classe CadastroDao, onde fará toda a mágica do negócio:

package br.org.hibernateobject;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.swing.JOptionPane;

import org.hibernate.HibernateException;

public class CadastroDao {

public void save(String txt) {
if (txt.equals("") || txt == null) {
JOptionPane.showMessageDialog(null, "Campo obrigatório!");
} else {
try {
String nome = null;
File f = new File(txt);

// Converte o arquivo em um array de bytes
byte[] buffer = new byte[(int) f.length()];
DataInputStream ds = new DataInputStream(new FileInputStream(f));
ds.readFully(buffer);
ds.close();

// Pega o nome do arquivo
nome = f.getName();

Cadastro c = new Cadastro();
c.setNome(nome);
c.setFoto(buffer);

// Finaliza a transacao com o hibernate
Principal.getHi().getSession().save(c);
Principal.getHi().getTx().commit();

JOptionPane.showMessageDialog(null,
"Arquivo cadastrado com sucesso!");
} catch (HibernateException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}


public void get(int id) {
try {
Cadastro c;
c = (Cadastro)Principal.getHi().getSession()
.get(Cadastro.class, id);

String arquivo = "/tmp/" + c.getNome();

FileOutputStream fos = new FileOutputStream(arquivo);
byte[] buffer = c.getFoto();

fos.write(buffer);
fos.flush();
fos.close();

JOptionPane.showMessageDialog(null,
"Arquivo resgatado com sucesso em: " + arquivo);
} catch (HibernateException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}


O método save(String txt) pega o caminho absoluto de onde está o arquivo da foto, depois passa para um DataInputStream que passa para um array de bytes. Feito isso, basta apenas passar para nosso método lá da classe Cadastro setFoto(byte[] foto). O método get(int id) faz o processo contrário, salvando a foto do banco para o diretório /tmp conforme foi setado na variável arquivo.

Vamos criar a classe HibernateInitialize, que vai ser responsável em criar a fábrica de sessão do Hibernate e iniciar as transações:

package br.org.hibernateobject;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;

public class HibernateInitialize {

private Session session;
private Transaction tx;


public HibernateInitialize() {
Configuration cfg = new AnnotationConfiguration()
.addAnnotatedClass(Cadastro.class)
.setProperty(Environment.HBM2DDL_AUTO, "update");

cfg.configure("/br/org/hibernateobject/hibernate.cfg.xml");

SessionFactory sf = cfg.buildSessionFactory();
session = sf.openSession();
tx = session.beginTransaction();
}


public Session getSession() {
return session;
}

public void setSession(Session session) {
this.session = session;
}

public Transaction getTx() {
return tx;
}

public void setTx(Transaction tx) {
this.tx = tx;
}

}


Dispensa comentários. Eu ainda uso XML para configurações, se você usa annotations, pode fazer essa classe do jeito que preferir. O arquivo hibernate.cfg.xml tem a seguinte estrutura:

<?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>
<!-- properties -->
<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<property name="connection.url">
jdbc:mysql://localhost:3306/hibernate_object
</property>
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name="show_sql">false</property>
<property name="connection.username">hibernate</property>
<property name="connection.password">hibernate123</property>
<property name="connection.pool_size">10</property>
<!-- mapping classes -->
<mapping class="br.org.hibernateobject.Cadastro" />
</session-factory>
</hibernate-configuration>


Agora vamos fazer a classe Principal, que vai ser a interface gráfica e dispensa comentário também. Com uma interface simples usando Swing e chamando os métodos do CadastroDao:

package br.org.hibernateobject;

import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class Principal extends JFrame {

private static final long serialVersionUID = 1L;
private static HibernateInitialize hibernate;

public Principal() {
super("Hibernate Salvando Objetos");

setSize(400,100);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);

// Centraliza a janela
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
int w = getSize().width;
int h = getSize().height;
int x = (dim.width-w) / 2;
int y = (dim.height-h) / 2;
setLocation(x, y);

final JTextField txtFoto = new JTextField(30);
final JButton btOK = new JButton("Salvar");
final JButton btGet = new JButton("Resgatar");

// Acao do click do botao
btOK.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) {
String txt = txtFoto.getText();
CadastroDao cdao = new CadastroDao();
cdao.save(txt);
}

});

btGet.addActionListener(new ActionListener(){

public void actionPerformed(ActionEvent e) {
int id = Integer.parseInt(JOptionPane
.showInputDialog("Informe o ID do cadastro:"));

CadastroDao cdao = new CadastroDao();
cdao.get(id);
}

});

JPanel p = new JPanel();
p.add(txtFoto);
p.add(btOK);
p.add(btGet);

getContentPane().add(p);
}

public static void main(String[] args) {
new Principal().setVisible(true);
hibernate = new HibernateInitialize();
}


public static HibernateInitialize getHi() {
return hibernate;
}


public static void setHi(HibernateInitialize hi) {
Principal.hibernate = hi;
}
}


Execute o seu programa e digite o caminho completo de algum arquivo de foto e clique no botão Salvar, se aparecer a mensagem 'Arquivo cadastrado com sucesso!', parabéns, senão, verifique seu código.

É isso, espero ter ajudado com esse pequeno conhecimento. O Hibernate é muito poderoso, dá pra fazer muita coisa com ele sem ao menos mexer no banco.

Enjoy...

quinta-feira, 5 de junho de 2008

Utilizando o Hibernate no GWT

Olá amiguinhos.

Vou mostrar um simples exemplo de como fazer um cadastro no GWT utilizando Hibernate. Eu achei muito trabalhoso pelo fato de não poder utilizar os recursos do Java 5. Mas em breve teremos a possibilidade de utilizar o Java 5 no GWT.

Primeiro, vamos fazer uma interface bem tosca, só com os campos necessários para nosso teste. Detalhe, esse esquema também funciona com o MyGWT, basta mudar os componentes. Vou evitar falar sobre a configuração do Hibernate, eu utilizo xml ainda, então não vou entrar em tantos detalhes.

Crie o projeto do GWT e crie uma classe chamada Principal, como segue abaixo:


package org.cadastrogwt.client;

public class Principal implements EntryPoint {

public void onModuleLoad() {
// Cria o formulario para cadastro
final FormPanel form = new FormPanel();
final VerticalPanel p = new VerticalPanel();
form.setWidget(p);
final Label lbNome = new Label("Nome");
p.add(lbNome);
final TextBox txtNome = new TextBox();
txtNome.setName("txtNome");
p.add(txtNome);
final Label lbCidade = new Label("Cidade");
p.add(lbCidade);
final TextBox txtCidade = new TextBox();
txtCidade.setName("txtCidade");
p.add(txtCidade);

// Cria um botao e define um evento para ele
Button btCadastrar = new Button("Cadastrar");
p.add(btCadastrar);

RootPanel.get().add(form);
}
}



Lembrando que eu não estou me preocupando muito com a aparência, e essa vai ficar muito feia hehe. Após isso, temos que criar as interfaces que vão controlar os dados e trabalhar RPC e a classe de "entidade". Devido ao problema do código do GWT ser compatível com o Java 1.4, vamos ter que duplicar essa classe de entidade no lado do server, com suas devidas annotations. Criamos então a classe Cadastro:


package org.cadastrogwt.client;

import com.google.gwt.user.client.rpc.IsSerializable;

public class Cadastro implements IsSerializable {

private String nome;
private String cidade;
private String estado;

public String getNome() {
return nome;
}

public void setNome(String nome) {
this.nome = nome;
}

public String getCidade() {
return cidade;
}

public void setCidade(String cidade) {
this.cidade = cidade;
}

public String getEstado() {
return estado;
}

public void setEstado(String estado) {
this.estado = estado;
}
}



Depois criamos duas interfaces, uma para o método que retornará alguma coisa do servidor e outra que enviará alguma coisa para o servidor. Simples não? Criamos a interface CadastroService:


package org.cadastrogwt.client;

import com.google.gwt.user.client.rpc.RemoteService;

public interface CadastroService extends RemoteService {
public String cadastrar(Cadastro c);
}



E a interface CadastroServiceAsync:


package org.cadastrogwt.client;

import com.google.gwt.user.client.rpc.AsyncCallback;

public interface CadastroServiceAsync {
public void cadastrar(Cadastro c, AsyncCallback callback);
}



Um detalhe muito importante e que é regra no GWT, apanhei muito no começo pra descobrir isso hehe. Essas duas interfaces, precisam obrigatóriamente conter Service e ServiceAsync nos nomes delas. Então crie um padrão, por exemplo, eu quero trabalhar com a classe Cidadao com o RPC, então eu vou criar as interfaces CidadaoService e CidadaoServiceAsync.

Bom, está quase pronto, agora precisamos criar um pacote no mesmo nível dos pacotes org.cadastrogwt.client e org.cadastrogwt.public. Crie um pacote chamado org.cadastrogwt.server. Tudo que ficar neste pacote é livre pra usar qualquer recurso do Java, Hibernate, Struts, tudo mesmo, pois ele será executado no servidor e não no cliente. Então criamos uma classe chamada CadastroServiceImpl (Mesma regra das interfaces também):


package org.cadastrogwt.server;

import org.cadastrogwt.client.Cadastro;
import org.cadastrogwt.client.CadastroService;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class CadastroServiceImpl extends RemoteServiceServlet
implements CadastroService {

private static final long serialVersionUID = 1L;

public String cadastrar(Cadastro c) {
// Valores definidos pelo cliente
String nome = c.getNome();
String cidade = c.getCidade();
String estado = c.getEstado();
String retorno = null;

// Hibernate
CadastroServerDao cdao = new CadastroServerDao();
cdao.insert(nome, cidade, estado);

retorno = "Cadastro efetuado com sucesso!!!";

return retorno;
}

}



Esta classe pega tudo que foi setado na classe Cadastro e passa para o Dao. Se pudesse usar annotations, eu poderia pegar o objeto c e já mandar para o Dao, mas vamos aguardar a versão 1.5 :)

Bom, agora para dar certo, vamos criar uma classe igual a classe Cadastro, mas mapeando-a. Criamos a classe CadastroServer:


package org.cadastrogwt.server;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "cadastro")
public class CadastroServer {

@Id
@Column(name = "id_cadastro")
private int id;

@Column(length = 100)
private String nome;

@Column(length = 50)
private String cidade;

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getNome() {
return nome;
}

public void setNome(String nome) {
this.nome = nome;
}

public String getCidade() {
return cidade;
}

public void setCidade(String cidade) {
this.cidade = cidade;
}
}



Beleza, agora é só criar o Dao. Criamos a classe CadastroServerDao:


package org.cadastrogwt.server;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;

public class CadastroServerDao {

private Session session;
private Transaction tx;

public CadastroServerDao() {
Configuration cfg = new AnnotationConfiguration();
cfg.configure("/org/cadastrogwt/server/hibernate.cfg.xml");

SessionFactory sf = cfg.buildSessionFactory();

session = sf.openSession();
tx = session.beginTransaction();
}


public void insert(String nome, String cidade, String estado) {
CadastroServer cad = new CadastroServer();
cad.setCidade(cidade);
cad.setEstado(estado);
cad.setNome(nome);

session.save(cad);
tx.commit();
session.close();
}

}



Fica a critério de cada um como usar o Configuration. Pronto, a parte do server está pronta. Agora vamos voltar para a parte do client novamente, para preparar a classe Principal para trabalhar com o AsyncCallback que faz a mesma coisa que o Ajax. Modifique a classe Principal para que fique com a mesma aparência que esta:


package org.cadastrogwt.client;

import *****;

public class Principal implements EntryPoint, AsyncCallback {

private CadastroServiceAsync service;

private void asyncCadastro(Cadastro c) {
this.service.cadastrar(c, this);
}

public void onModuleLoad() {
// Inicia a sincronizacao com o servlet
service = (CadastroServiceAsync)
GWT.create(CadastroService.class);
ServiceDefTarget target = (ServiceDefTarget) service;
target.setServiceEntryPoint(GWT.getModuleBaseURL() +
"cadastro");

// Cria o formulario para cadastro
final FormPanel form = new FormPanel();
final VerticalPanel p = new VerticalPanel();
form.setWidget(p);
final Label lbNome = new Label("Nome");
p.add(lbNome);
final TextBox txtNome = new TextBox();
txtNome.setName("txtNome");
p.add(txtNome);
final Label lbCidade = new Label("Cidade");
p.add(lbCidade);
final TextBox txtCidade = new TextBox();
txtCidade.setName("txtCidade");
p.add(txtCidade);

// Cria um botao e define um evento para ele
Button btCadastrar = new Button("Cadastrar",
new ClickListener() {
public void onClick(Widget sender) {
Cadastro cad = new Cadastro();
cad.setCidade(txtCidade.getText());
cad.setNome(txtNome.getText());

asyncCadastro(cad);
}
});
p.add(btCadastrar);

RootPanel.get().add(form);
}

public void onFailure(Throwable caught) {
// Joga uma mensagem de erro caso ocorra
Window.alert(caught.getMessage());
}

public void onSuccess(Object result) {
// Retorna a resposta do servidor
Window.alert(result.toString());
}
}



Pronto, agora antes de testar, é necessário criar uma linha no xml do projeto GWT, que seria Principal.gwt.xml. Adicione depois da tag entry-point:



<servlet path="/cadastro"
class="org.cadastrogwt.server.CadastroServiceImpl" />



Pronto, rode o projeto e tente fazer um cadastro e depois olhe no banco de dados se foi corretamente. Eu não vou explicar como faz a listagem, porque seria legal se desse pra retornar do servidor um ArrayList mas não consegui, vou fazer mais testes. Mas fica ae pra diversão de vocês. Usei como base os exemplos que vem no pacote do GWT, lá tem o pacote DynamTable que usa recursos do RPC.

Enjoy...