Na maioria das vezes é útil utilizar componentes de listas conhecidos como Combobox ou Dropdown para mostrar relacionamentos de dados entre tabelas e de uma forma amigável exibir a descrição dos itens de dados e manipular seu identificador único. Para isto o JavaServer Faces nos disponibiliza componentes e classes no qual nos permite manipular dados através de objetos e persisti-los em um banco de dados relacional usando o Hibernate. Um relacionamento de dados mais simples é criado através de duas tabelas, sendo uma tabela pai que contem os dados mestres e uma filho que contem um ou mais identificadores relacionados ao pai. Um modo de fácil de identificar e tradicional de utilizar relacionamentos em um banco de dados é através de chaves estrangeiras, uma chave estrangeira é um campo, que aponta para a chave primária de outra tabela ou da mesma tabela. Ou seja, passa a existir uma relação entre duas tabelas ou de uma única tabela. A finalidade da chave estrangeira é garantir a integridade dos dados referenciais, pois apenas serão permitidos valores que supostamente vão aparecer na base de dados e estão ligados ao registro mestre.
Exibindo Relacionamentos
1 – Primeiro crie duas tabelas e seus respectivos objetos no banco de dados Oracle, atente-se para a chave estrangeira que cria o relacionamento entre as tabelas usando a chave primaria da tabela pai:
2 – Crie uma aplicação JSF e use o código abaixo, o código é o mesmo dos exemplos anteriores, porem criamos novos objetos e novos modelos para comportar o relacionamento de dados das duas tabelas e exibi-los de uma forma amigável na pagina web. Clicando no botão de enviar, você automaticamente grava os dados no banco de dados:
3 – Assim que os dados forem enviados o Hibernate gravará o conteúdo dos objetos no banco de dados relacional, você pode verificar na pagina que mostramos a descrição do campo cargo toda vez que utilizamos os dados da tabela de Cargos, porem na tabela Participante apenas seu identificador é gravado formando o relacionamento entre as duas tabelas:
Exemplo:
Neste exemplo criamos duas tabelas no banco de dados Oracle e as relacionamos através da chave primaria e uma chave estrangeira. Usamos um elemento JSF para tornar este relacionamento amigável, exibindo assim a descrição do relacionamento mas manipulando seu identificador e os persistindo através do Hibernate.
SQL
-- Cria Sequence Participante CREATE SEQUENCE SEQ_PARTICIPANTE START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE; -- Cria tabela de participantes CREATE TABLE PARTICIPANTE ( ID_PART INTEGER NOT NULL , NOME VARCHAR2(30) NOT NULL , SOBRENOME VARCHAR2(70) NOT NULL , ID_CARGO INTEGER NOT NULL , DATA_ADMISSAO DATE NOT NULL , SALARIO NUMBER(9,2) NOT NULL , GENERO VARCHAR2(20) NOT NULL , ATIVO CHAR(5) NOT NULL , OBSERVACAO VARCHAR2(255) , CONSTRAINT PARTICIPANTE_PK PRIMARY KEY ( ID_PART ) ENABLE ); -- Cria Sequence Cargo CREATE SEQUENCE SEQ_CARGO START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE; -- Cria tabela de cargo Create Table CARGO ( ID_CARGO INTEGER NOT NULL, DESC_CARGO VARCHAR2(50) NOT NULL, CONSTRAINT CARGO_PK PRIMARY KEY ( ID_CARGO ) ENABLE ); -- Alimenta dados na tabela de cargos insert into cargo values (SEQ_CARGO.NEXTVAL , 'Vocalista'); insert into cargo values (SEQ_CARGO.NEXTVAL, 'Guitarrista'); insert into cargo values (SEQ_CARGO.NEXTVAL, 'Baixista'); insert into cargo values (SEQ_CARGO.NEXTVAL, 'Baterista'); -- Cria Contraint chave estrangeira ALTER TABLE PARTICIPANTE ADD CONSTRAINT CARGO_FK FOREIGN KEY (ID_CARGO) REFERENCES CARGO (ID_CARGO);
Java
Hibernate.cfg.xml
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property> <property name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521:xe</property> <property name="hibernate.connection.username">user</property> <property name="hibernate.connection.password">pass</property> <property name="hibernate.connection.pool_size">10</property> <property name="show_sql">true</property> <property name="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</property> <property name="hibernate.current_session_context_class">thread</property> <mapping class="org.desenvolvimento.aberto.Modelo.CargoModelo" /> <mapping class="org.desenvolvimento.aberto.Modelo.ParticipanteModelo" /> </session-factory> </hibernate-configuration>
Participante
package org.desenvolvimento.aberto; import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.faces.bean.ManagedBean; import javax.faces.bean.SessionScoped; import javax.faces.model.SelectItem; import org.desenvolvimento.aberto.Modelo.CargoModelo; import org.desenvolvimento.aberto.Modelo.ParticipanteModelo; import org.desenvolvimento.aberto.dao.ParticipanteDao; // Define decoradores @ManagedBean(name = "Participante") @SessionScoped public class Participante { // Define atributos privados private long id; private String nome; private String sobrenome; private int cargo; private Date data; private double salario; private String genero; private boolean ativo; private String observacao; private List<SelectItem> cargoItem; // Metodos Getter e Setter public long getId() { return id; } public void setId(long id) { this.id = id; } public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } public String getSobrenome() { return sobrenome; } public void setSobrenome(String sobrenome) { this.sobrenome = sobrenome; } public int getCargo() { return cargo; } public void setCargo(int cargo) { this.cargo = cargo; } public Date getData() { return data; } public void setData(Date data) { this.data = data; } public double getSalario() { return salario; } public void setSalario(double salario) { this.salario = salario; } public String getGenero() { return genero; } public void setGenero(String genero) { this.genero = genero; } public boolean isAtivo() { return ativo; } public void setAtivo(boolean ativo) { this.ativo = ativo; } public String getObservacao() { return observacao; } public void setObservacao(String observacao) { this.observacao = observacao; } public List<SelectItem> getCargoItem() { // Cria objeto de modelo Faces cargoItem = new ArrayList<SelectItem>(); // cria objeto DAO ParticipanteDao participante = new ParticipanteDao(); List<CargoModelo> cargo = participante.listacargos(); // Alimenta Modelo for (CargoModelo c : cargo) { SelectItem selecao = new SelectItem(c.getId_cargo(), c.getCargo()); cargoItem.add(selecao); } return cargoItem; } // Grava Dados usando Hibernate // Você pode criar um modelo de dados para este Managed Bean // Optamos por usar o próprio objeto através da referencia This public String enviarDados() { // Cria objeto DAO ParticipanteDao participante = new ParticipanteDao(); // cria objeto Modelo ParticipanteModelo modelo = new ParticipanteModelo(); // Transfere dados ao objeto modelo.setNome(this.getNome()); modelo.setSobrenome(this.getSobrenome()); modelo.setCargo(this.getCargo()); modelo.setData(this.getData()); modelo.setSalario(this.getSalario()); modelo.setGenero(this.getGenero()); modelo.setAtivo(String.valueOf(this.isAtivo())); modelo.setObservacao(this.getObservacao()); // Você pode criar boolean resultado = participante.insereDados(modelo); // Verifica resultado if (resultado) { return "resultado.xhtml?faces-redirect=true"; } else { return null; } } }
IParticipanteDao
package org.desenvolvimento.aberto.dao; import java.util.List; import org.desenvolvimento.aberto.Modelo.CargoModelo; import org.desenvolvimento.aberto.Modelo.ParticipanteModelo; public interface IParticipanteDao { // Define método abstrato boolean insereDados(ParticipanteModelo participante); public List<CargoModelo> listacargos(); }
ParticipanteDao
package org.desenvolvimento.aberto.dao; import java.util.List; import org.hibernate.Session; import org.desenvolvimento.aberto.Factory.*; import org.desenvolvimento.aberto.Modelo.ParticipanteModelo; import org.desenvolvimento.aberto.Modelo.CargoModelo; public class ParticipanteDao implements IParticipanteDao { @Override public boolean insereDados(ParticipanteModelo participante) { // Declara variável de resultado int resultado = 0; // Cria sessão Session session = DBConexaoFactory.getSessionFactory().openSession(); // Cria transação session.beginTransaction(); // Persiste dados resultado = (Integer) session.save(participante); // Confirma e encerra transação session.getTransaction().commit(); // Retorna resultado if (resultado != 0) { return true; } else { return false; } } @Override public List<CargoModelo> listacargos() { List<CargoModelo> itens = null; // Cria sessão Session session = DBConexaoFactory.getSessionFactory().openSession(); // Cria transação session.beginTransaction(); // Recupera dados String sql = "FROM CargoModelo"; itens = session.createQuery(sql).list(); // Confirma e encerra transação session.getTransaction().commit(); return itens; } }
DBConexaoFactory
package org.desenvolvimento.aberto.Factory; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class DBConexaoFactory { private static final SessionFactory sessionFactory = buildSessionFactory(); // Constroi sessão @SuppressWarnings("deprecation") private static SessionFactory buildSessionFactory() { try { // buildSessionFactory não será utilizado em versões superiores // Veremos outros métodos para criar um Factory // Não é necessário incluir o "hibernate.cfg.xml" no configure() // Incluímos somente a nível de fácil entendimento da chamada da // configuração. // Você pode retirar a chamada. return new Configuration().configure("hibernate.cfg.xml") .buildSessionFactory(); } catch (Throwable ex) { // Em caso de erro System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } // Retorna Factory da sessão public static SessionFactory getSessionFactory() { return sessionFactory; } // Encerra Sessão public static void shutdown() { getSessionFactory().close(); } }
CargoModelo
package org.desenvolvimento.aberto.Modelo; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.SequenceGenerator; import javax.persistence.Table; @Entity @Table(name = "CARGO") public class CargoModelo { @Id @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CARGO") @SequenceGenerator(name = "SEQ_CARGO", sequenceName = "SEQ_CARGO") @Column(name = "ID_CARGO") private int id_cargo; @Column(name = "DESC_CARGO") private String cargo; // Métodos Getter & Setter public int getId_cargo() { return id_cargo; } public void setId_cargo(int id_cargo) { this.id_cargo = id_cargo; } public String getCargo() { return cargo; } public void setCargo(String cargo) { this.cargo = cargo; } }
ParticipanteModelo
package org.desenvolvimento.aberto.Modelo; import java.util.Date; import javax.persistence.Column; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Entity; import javax.persistence.SequenceGenerator; import javax.persistence.Table; @Entity @Table(name = "PARTICIPANTE") public class ParticipanteModelo { // Define atributos privados @Id @GeneratedValue(strategy=GenerationType.AUTO, generator="SEQ_PARTICIPANTE") @SequenceGenerator(name="SEQ_PARTICIPANTE", sequenceName="SEQ_PARTICIPANTE") @Column(name = "ID_PART") private int id; @Column(name = "NOME") private String nome; @Column(name = "SOBRENOME") private String sobrenome; @Column(name = "ID_CARGO") private int cargo; @Column(name = "DATA_ADMISSAO") private Date data; @Column(name = "SALARIO") private double salario; @Column(name = "GENERO") private String genero; @Column(name = "ATIVO") private String ativo; @Column(name = "OBSERVACAO") private String observacao; // Metodos Getter e Setter 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 getSobrenome() { return sobrenome; } public void setSobrenome(String sobrenome) { this.sobrenome = sobrenome; } public int getCargo() { return cargo; } public void setCargo(int cargo) { this.cargo = cargo; } public Date getData() { return data; } public void setData(Date data) { this.data = data; } public double getSalario() { return salario; } public void setSalario(double salario) { this.salario = salario; } public String getGenero() { return genero; } public void setGenero(String genero) { this.genero = genero; } public String getAtivo() { return ativo; } public void setAtivo(String ativo) { this.ativo = ativo; } public String getObservacao() { return observacao; } public void setObservacao(String observacao) { this.observacao = observacao; } }
Index.xhtml
<!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:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"> <f:loadBundle basename="resources.application" var="msg" /> <head> <title><h:outputText value="#{msg.welcomeTitle}" /></title> </head> <h:body> <h2>JSF - Desenvolvimento Aberto - Managed Beans -</h2> <h3> <h:outputText id="lnome" value="Java Server Faces- Elementos de Formulário - Hibernate - Oracle Database" /> </h3> <h:form> <fieldset style="padding: 10px"> <legend style="padding: 5px">Cadastro:</legend> <h:panelGrid columns="3" cellpadding="2px"> <h:outputText id="lnome" value="Nome:" /> <h:inputText id="tnome" value="#{Participante.nome}" size="30" required="true" label="Nome" requiredMessage="#{msg['requerido.nome']}"> <f:validateRegex pattern="[a-zA-Z]+" /> </h:inputText> <h:message for="tnome" style="color:red" /> <h:outputText id="lsobrenome" value="Sobrenome:" /> <h:inputText id="tsobrenome" value="#{Participante.sobrenome}" size="40" required="true" label="Sobrenome" requiredMessage="#{msg['requerido.sobrenome']}"> <f:validateRegex pattern="[a-zA-Z]+" /> </h:inputText> <h:message for="tsobrenome" style="color:red" /> <h:outputText id="lcargo" value="Cargo" /> <h:selectOneMenu id="tcargo" style="width:210px" value="#{Participante.cargo}" required="true" requiredMessage="#{msg['requerido.cargo']}"> <f:selectItem itemLabel=" - Selecione uma opção - " itemValue=""/> <f:selectItems value="#{Participante.cargoItem}" /> </h:selectOneMenu> <h:message for="tcargo" style="color:red" /> <h:outputText id="ldata" value="Data de Admissão" /> <h:inputText value="#{Participante.data}" required="true" requiredMessage="#{msg['requerido.data']}"> <f:convertDateTime pattern="dd/mm/yyyy" /> </h:inputText> <h:message for="tdata" style="color:red" /> <h:outputText id="lsalario" value="Salário" /> <h:inputText id="tsalario" value="#{Participante.salario}" required="true" label="Salário" requiredMessage="#{msg['requerido.salario']}" validatorMessage="#{msg['validar.salario']}"> <f:convertNumber currencySymbol="$" type="currency" /> <f:validateDoubleRange minimum="788.00" maximum="9999.99" /> </h:inputText> <h:message for="tsalario" style="color:red" /> <h:outputText id="lgenero" value="Sexo" /> <h:selectOneRadio id="tgenero" value="#{Participante.genero}" required="true" requiredMessage="#{msg['requerido.genero']}"> <f:selectItem itemValue="Masculino" itemLabel="Masculino" /> <f:selectItem itemValue="Feminino" itemLabel="Feminino" /> </h:selectOneRadio> <h:message for="tgenero" style="color:red" /> <h:outputText id="lativo" value="Ativo" /> <h:selectBooleanCheckbox value="#{Participante.ativo}"></h:selectBooleanCheckbox> <br /> <h:outputText id="lobservacao" value="Observação" /> <h:inputTextarea value="#{Participante.observacao}" rows="7" cols="40" /> </h:panelGrid> </fieldset> <br /> <h:commandButton id="submit" action="#{Participante.enviarDados}" value="Enviar Dados" /> </h:form> </h:body> </html>
Resultado.xhtml
<!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:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"> <f:loadBundle basename="resources.application" var="msg" /> <head> <title><h:outputText value="#{msg.welcomeTitle}" /></title> </head> <h:body> <h2>JSF - Desenvolvimento Aberto - Managed Beans -</h2> <h3> <h:outputText id="lnome" value="Java Server Faces- Elementos de Formulário - Hibernate - Oracle" /> </h3> <h:panelGrid columns="2"> <h:outputLabel value="Nome:" /> <h:outputText value="#{Participante.nome}" /> <h:outputLabel value="Sobrenome:" /> <h:outputText value="#{Participante.sobrenome}" /> <h:outputLabel value="Cargo:" /> <h:outputText value="#{Participante.cargo}" /> <h:outputLabel value="Data de Admissão:" /> <h:outputText value="#{Participante.data}"> <f:convertDateTime pattern="dd/mm/yyyy" /> </h:outputText> <h:outputLabel value="Salário" /> <h:outputText value="#{Participante.salario}"> <f:convertNumber currencySymbol="$" type="currency" /> </h:outputText> <h:outputLabel value="Sexo:" /> <h:outputText value="#{Participante.genero}" /> <h:outputLabel value="Ativo:" /> <h:outputText value="#{Participante.ativo}" /> <h:outputLabel value="Observacao" /> <h:outputText value="#{Participante.observacao}" /> </h:panelGrid> </h:body> </html>