CRUD simples com Hibernate e JSF

Introdução

Nos últimos dois Post foi explicado como funciona o Ciclo de Vida do JavaServer Faces e em seguida Como Criar um Projeto JSF, neste Post será abordado como criar um CRUD. O Hibernate será utilizado como provedor de persistência, o C3P0 para fazer o pool de conexões e o JSF para a camada de visualização dos dados. Ao fim deste artigo você saberá:

  • Como instalar o MySQL;
  • O que é um CRUD;
  • O que é Java Persistence API (JPA);
  • O que é e como instalar o Hibernate;
  • O que é e como instalar o C3P0;
  • Criar uma entidade usando as anotações do JPA; e
  • Manipular uma entidade.

Instalando o MySQL

MySQL é um Sistema Gerenciador de Banco de Dados (SGBD) Open Source e está disponível na maioria das distribuições Linux. Sua instalação no Ubuntu é simples, basta executar o seguinte comando:

aptitude update
aptitude install mysql-server

Durante a instalação é solicitado uma senha que será utilizado pelo usuário root (o administrador do banco de dados). Para testar se ele está funcionando você pode acessar o seu console:

mysql -u root

Se aparecer algo como ‘mysql> ‘, é sinal que a instalação foi bem sucedida, ainda é possível efetuar este teste ‘enviando’ um ping para o banco de dados por meio do comando ‘mysqladmin‘ seguido do parâmetro ‘ping‘:

mysqladmin ping
mysqld is alive

Se a mensagem ‘mysqld is alive‘ for exibida em tela, então o banco de dados foi instalado com sucesso. Se ao executar o comando acima for retornado a mensagem abaixo, pode ser que o MySQL apenas não esteja no ar:

mysqladmin: connect to server at 'localhost' failed
error: 'Can't connect to local MySQL server through socket '/var/run/mysql/mysql.sock' (2)'
Check that mysqld is running and that the socket: '/var/run/mysql/mysql.sock' exists!
mysqladmin: connect to server at 'localhost' failederror: 'Can't connect to local MySQL server through socket '/var/run/mysql/mysql.sock' (2)'Check that mysqld is running and that the socket: '/var/run/mysql/mysql.sock' exists!

Sendo assim basta subir o serviço:

sudo /etc/init.d/mysql start

O que é um CRUD

CRUD é uma sigla que significa: Create, Read, Update and Delete. Essas, são as 4 operações básicas efetuadas em um banco de dados: Inserir, Recuperar, Alterar e Remover. Um módulo simples de um software qualquer geralmente possui essas opções sob determinada entidade, devido a isto é comum no dia a dia chamá-lo de CRUD.

Então CRUD é uma maneira rápida de dizer que será possível manipular uma entidade através das funções Inserir, Recuperar, Alterar e Remover.

O que é Java Persistence API (JPA)

Java Persistence API ou simplesmente JPA é uma especificação da Sun escrita pelo grupo de peritos JSR220 que tem por objetivo solucionar os problemas de ORM (Object-Relational Mapping), ou seja, como mapear um objeto em um banco de dados relacional. Visto que uma especificação precisa de uma implementação que tenha sido desenvolvida seguindo todos os parâmetros proposto, neste artigo será utilizado o Hibernate.

Neste tópico é importante que fique claro que JPA nada mais é do que um documento descrevendo como esta tecnologia deve funcionar e o Hibernate é o projeto que implementou a especificação do JPA.

Na verdade isto não aconteceu nesta ordem, pois o Hibernate surgiu antes da especificação, logo a JPA foi escrita baseando-se no Hibernate o que o torna em um framework de facto e conseqüêntemente com muito mais recurssos do que a própria JSR220 propôs. Mais informações sobre o Hibernate será visto à seguir.

O que é e Como Instalar o Hibernate

O Hibernate inicialmente era um projeto pessoal de Gavin King que iniciou em 2001 e era utilizado como alternativa ao EJB2, seu propósito era simplificar a persistência de dados. Desde então ganhou espaço e confiança dos desenvolvedores ao redor do mundo se tornando o framework de persistência mais utilizado.

Com o Hibernate é possível escrever representações das entidades do banco de dados em forma de objetos(esta representação é denominada de Mapeamento), à partir disto pode-se manipular estas entidades inserindo, selecionando, alterando e removendo do banco de dados(lembra do tópico acima CRUD?).

É possível ainda escrever relacionamentos entre entidades do tipo Pessoa e Telefone, validar os atributos por quantidade de caracteres(String) ou valor máximo e mínimo(Números), etc.

Feita a apresentação do framework, partiremos para sua instalação. Se você não sabe como criar um projeto JSF, siga os passos apresentados no artigo Como Criar um Projeto JSF. A instalação do Hibernate consiste em adicionar os JARs em seu projeto e escrever um arquivo de configuração no formato XML. Efetue o download do Core do projeto em:

http://sourceforge.net/projects/hibernate/files/hibernate3/

Descompacte o arquivo baixado, entre no diretório  e copie o jar hibernate3.jar, todas as bibliotecas obrigatórias dentro de lib/required/ e o jar hibernate-jpa-2.0-api-1.0.0.Final.jar dentro de lib/jpa/

cd hibernate-distribution-3.6.0.Final
cp hibernate3.jar ~/workspace/crud/WebContent/WEB-INF/lib/
ls lib/required/
antlr-2.7.6.jar
commons-collections-3.1.jar
dom4j-1.6.1.jar
javassist-3.12.0.GA.jar
jta-1.1.jar
slf4j-api-1.6.1.jar
cp lib/required/*.jar ~/workspace/crud/WebContent/WEB-INF/lib/
cp lib/jpa/hibernate-jpa-2.0-api-1.0.0.Final.jar ~/workspace/crud/WebContent/WEB-INF/lib/

Após a cópia é necessário atualizar o projeto no Eclipse, clique com o botão direito sob o projeto e depois em Refresh. É necessário criar um arquivo de configuração XML denominado persistence.xml, detalhe importante é que este arquivo deve estar dentro de um diretório denominada META-INF que por sua vez deve estar dentro de algum source folder, geralmente ele é criado dentro do src.

No Eclipse, clique com o botão direito sob o diretório src em seguida New > Other e a seguinte janele deve aparecer:

Criando o diretório META-INF dentro de src

Selecione a opção Folder, clique em Next, então navegue até o seu projeto neste caso crud > src, em Folder name: digite META-INF em maiúsculo e clique em Finish:

Criando o diretório META-INF dentro de src

Vamos criar agora o arquivo de configuração, para isto clique com o botão direito do mouse sob o diretório recém criado META-INF em seguida clique na opção New > Other, digite xml no campo Wizards e selecione a opção XML File:

Criando o arquivo persistence.xml dentro do diretório META-INF

Clique em Next, na próxima tela digite o nome persistence.xml em File name, com o diretório crud > src > META-INF selecionado clique em Finish:

Criando o arquivo persistence.xml dentro do diretório META-INF

Abaixo um exemplo de um persistence.xml:

<!--?xml version="1.0" encoding="UTF-8"?-->
<persistence version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">

  <persistence-unit name="crud">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>

    <properties>
      <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
      <property name="hibernate.show_sql" value="true" />
      <property name="hibernate.format_sql" value="true" />
      <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/crud" />
      <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
      <property name="hibernate.connection.username" value="root" />
      <property name="hibernate.connection.password" value="" />
      <property name="hibernate.hbm2ddl.auto" value="update" />
    </properties>
  </persistence-unit>
</persistence>

Abaixo uma breve descrição de alguns parâmetros informados no código acima:

  • persistence-unit name=”crud”: Nome da unidade de persistência, este nome será utilizado ao criar um EntityManagerFactory.
  • hibernate.dialect: Dialeto para conversação entre o banco de dados e o Hibernate.
  • hibernate.show_sql: Exibe a todas as SQLs que forem executadas no banco de dados.
  • hibernate.format_sql: Formata as SQLs que serão exibidas.
  • hibernate.connection.url: URL de conexão com o banco de dados, repare que ela é igual a utilizada no JDBC.
  • hibernate.connection.driver_class: Nome da classe do Driver que faz a conexão com o banco de dados.
  • hibernate.connection.username: Usuário para se conectar ao banco de dados.
  • hibernate.connection.password: Senha do usuário para se conectar ao banco de dados.
  • hibernate.hbm2ddl.auto: Este atributo pode receber 5 valores de acordo com a documentação do Hibernate, esses atributos são utilizados durante a inicialização do EntityManagerFactory, são eles:
    • none: não faz nada;
    • validate: valida as informações e não faz nenhuma mudança no banco de dados;
    • update: atualiza as informações no banco de dados e não apaga nada;
    • create: cria o schema;
    • create-drop: cria o schema durante a inicialização e drop no fim da sessão.

Configure o arquivo de acordo com a sua máquina, é necessário agora criar uma data base no MySQL:

mysql -u root
create database crud;

O Hibernate tem como dependência o log4j da apache, efetue o download do dele no link abaixo:

http://logging.apache.org/log4j/1.2/download.html

Descompacte o pacote e copie o jar log4j-1.2.16.jar para o diretório lib da aplicação

tar zvxf apache-log4j-1.2.16.tar.gz
cd apache-log4j-1.2.16/
cp log4j-1.2.16.jar ~/workspace/crud/WebContent/WEB-INF/lib/

É necessário escrever um arquivo de nome log4j.properties, crie um arquivo texto normal dentro do diretório src clicando com o botão direito sob o diretório src e em seguida New > Other selecione a opção File na janela que se abriu e clique em Next.

Criando o arquivo log4j.properties dentro do diretório src

Selecione o projeto crud e navegue até o diretório src. Em File name digite log4j.properties e clique em Finish.

Criando o arquivo log4j.properties dentro do diretório srcAdicione ao arquivo o conteúdo abaixo:

### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### set log levels - for more verbose logging change 'info' to 'debug' ###

log4j.rootLogger=info, stdout

log4j.logger.org.hibernate=info
#log4j.logger.org.hibernate=debug

### log HQL query parser activity
#log4j.logger.org.hibernate.hql.ast.AST=debug

### log just the SQL
#log4j.logger.org.hibernate.SQL=debug

### log JDBC bind parameters ###
log4j.logger.org.hibernate.type=info
#log4j.logger.org.hibernate.type=debug

### log schema export/update ###
log4j.logger.org.hibernate.tool.hbm2ddl=debug

### log HQL parse trees
#log4j.logger.org.hibernate.hql=debug

### log cache activity ###
#log4j.logger.org.hibernate.cache=debug

### log transaction activity
#log4j.logger.org.hibernate.transaction=debug

### log JDBC resource acquisition
#log4j.logger.org.hibernate.jdbc=debug

### enable the following line if you want to track down connection ###
### leakages when using DriverManagerConnectionProvider ###
#log4j.logger.org.hibernate.connection.DriverManagerConnectionProvider=trace

Para o Hibernate conversar com log4j ele utiliza o slf4j que funciona como uma interface entre a API de log e o Hibernate. Logo se faz necessário o download do slf4j também. No diretório lib/required do Hibernate existe o jar slf4j-api-1.6.1.jar que provavelmente já está no diretório lib de sua aplicação, efetue o download do software em:

http://www.slf4j.org/download.html

Descompacte o arquivo e copie o jar

tar zvxf slf4j-1.6.1.tar.gz
cd slf4j-1.6.1/
cp slf4j-log4j12-1.6.1.jar ~/workspace/crud/WebContent/WEB-INF/lib/

O Hibernate também é capaz de efetuar algumas validações direto nas entidades, de forma que uma vez escrita a validação ela será aplicada sempre que alguém utilizar a entidade. Efetue o download do Hibernate validator no seguinte link:

http://sourceforge.net/projects/hibernate/files/hibernate-validator/

Descompacte o arquivo e copie os JARs hibernate-validator-4.1.0.Final.jar e lib/validation-api-1.0.0.GA.jar para o diretório lib da aplicação

tar zvxf hibernate-validator-4.1.0.Final-dist.tar.gz
cd hibernate-validator-4.1.0.Final/
cp hibernate-validator-4.1.0.Final.jar ~/workspace/crud/WebContent/WEB-INF/lib/
cp lib/validation-api-1.0.0.GA.jar ~/workspace/crud/WebContent/WEB-INF/lib/

Para finalizar é necessário o download do driver do MySQL, efetue o download no seguinte link:

http://dev.mysql.com/downloads/connector/j/

Descompacte e copie o driver para o diretório lib da aplicação:

tar zvxf mysql-connector-java-5.1.13.tar.gz
cd mysql-connector-java-5.1.13/
cp mysql-connector-java-5.1.13-bin.jar ~/workspace/crud/WebContent/WEB-INF/lib/

Não se esqueça de atualizar o projeto no Eclipse clicando com o botão direito do mouse sobre o projeto e em seguida clique em Refresh. JPA configurado, vamos para a explicação e instalação do C3P0.

O que é e Como Instalar o C3P0

C3P0 é um projeto de software livre e está sob a licença LGPL, o objetivo deste software é fazer um Pool de Conexões e Statements com o banco de dados, ou seja, manter uma quantidade de conexões abertas, diminuindo assim o tempo de resposta quando sua aplicação se comunicar com o SGBD.

Na documentação do Hibernate recomenda-se a utilização de um Pool de Conexões externo, por exemplo, o C3P0 explicado neste tópico. E se você reparar no log de inicialização do Hibernate ele exibe a seguinte informação quando não tem um pool de conexões configurado:

INFO DriverManagerConnectionProvider:64 - Using Hibernate built-in connection pool (not for production use!)

Adicione ao arquivo persistence.xml as seguintes propriedades dentro da sessão properties:

<property name="hibernate.connection.provider_class" value="org.hibernate.connection.C3P0ConnectionProvider" />
<property name="hibernate.c3p0.min_size" value="5" />
<property name="hibernate.c3p0.max_size" value="20" />
<property name="hibernate.c3p0.timeout" value="1800" />
<property name="hibernate.c3p0.max_statements" value="50" />
<property name="hibernate.c3p0.idle_test_period" value="3000" />

O significado das propriedades desta configuração pode ser visto abaixo:

  • hibernate.c3p0.min_size: quantidade mínima de conexões que serão mantidas com o banco de dados;
  • hibernate.c3p0.max_size: quantidade máxima de conexões que serão abertas;
  • hibernate.c3p0.timeout: tempo de duração de cada conexão sem utilização, ou seja, depois de determinado tempo de inatividade a conexão é derrubada;
  • hibernate.c3p0.max_statements: quantidade máxima de statements;
  • hibernate.c3p0.idle_test_period: de tempos em tempos o C3P0 irá testar a conexão, de modo que se alguma falhar ele a cria novamente.

A instalação do C3P0 consiste na configuração do persistence.xml e na copia de um JAR para o diretório lib da aplicação, o JAR pode ser encontrado no próprio pacote do Hibernate dentro do diretório lib/optional/c3p0/

cp lib/optional/c3p0/c3p0-0.9.1.jar ~/workspace/crud/WebContent/WEB-INF/lib/

Criar uma entidade usando as anotações do JPA

Para avisar ao Hibernate que determinada classe é uma entidade utilizaremos a anotação @Entity. Para o exemplo será utilizado a classe Pessoa com os atributos: id, nome, sexo e idade. Crie a classe Pessoa dentro do pacote br.com.crud.entity.

package br.com.crud.entity;

import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;

@Entity
public class Pessoa {
  public static enum Sexo {
    Masculino, Feminino
  }

  @Id
  @GeneratedValue(strategy=GenerationType.IDENTITY)
  private Long id;

  private String nome;

  @Enumerated(EnumType.STRING)
  private Sexo sexo;

  @Min(15)
  @Max(130)
  private Integer idade;

  // getters and setters
}

Explicação das anotações:

  • @Entity – Informa ao Hibernate que a classe anotada é uma entidade, esta anotação pode receber o atributo name, caso esse atributo seja definido, sempre que você se referenciar a esta entidade nas consultas é necessário informar esee nome. Como não utilizamos o atributo name, o Hibernate assume o nome da classe como nome para a entidade;
  • @Id – O atributo anotado com o @Id será a chave primária da classe;
  • @GeneratedValue(strategy=GenerationType.IDENTITY) – A estratégia de geração da chave primária será delegada a seu banco de dados;
  • @Enumerated(EnumType.STRING) – define de que forma o seu campo enum será salvo em banco de dados, por padrão é utilizado o EnumType.ORDINAL o que significa que o seu enum será salvo em forma de números no banco de dados. EnumType.STRING força o provedor de persistência a utilizar o nome literal utilizado na declaração do enum, neste caso Masculino e Feminino;
  • @Min(15) e @Max(130) – Utilizado para validar um intervalo de números, ou seja, o usuário poderá digitar um número entre  15 e 130 para este atributo. Cuidado para não confundir com a anotação @Length(max,min) que valida quantidade de caracteres em uma String.

Manipulando a Entidade Pessoa

Para manipular a entidade Pessoa utilizaremos duas classes, a classe PessoaBean que irá fazer o papel de backing bean da nossa aplicação JSF e a classe EntityManagerUtil que nos fornecerá uma instância estática do EntityManagerFactory. Crie a classe EntityManagerUtil dentro do pacote br.com.crud.tool:

package br.com.crud.tool;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class EntityManagerUtil {

  private static final EntityManagerUtil instance = new EntityManagerUtil();

  private static final EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("crud");

  private EntityManagerUtil() {}

  public static EntityManagerUtil getInstance() {
    return instance;
  }

  public EntityManagerFactory getEntityManagerFactory() {
    return entityManagerFactory;
  }

  public EntityManager createEntityManager() {
    return entityManagerFactory.createEntityManager();
  }
}

Repare nesta parte do código Persistence.createEntityManagerFactory(“crud”), para criar o EntityManagerFactory foi definido o nome crud não por coincidência é o mesmo utilizado no persistence-unit name=”crud” de nosso persistence.xml. A instância estática de EntityManagerFactory garante que ele será criado apenas uma vez, este é o cenário ideal pois sua inicialização é demorada e consome muito recursso.

Crie a classe PessoaBean dentro do pacote br.com.crud.bean

package br.com.crud.bean;

import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import org.apache.log4j.Logger;
import br.com.crud.entity.Pessoa;
import br.com.crud.tool.EntityManagerUtil;

public class PessoaBean {

  private static final Logger log = Logger.getLogger(PessoaBean.class);

  private EntityManager entityManager;

  private Pessoa pessoa = new Pessoa();

  private Long id;

  private List<Pessoa> list;

  public String persist() {
    log.info("Cadastrando pessoa: " + pessoa.getNome());
    try {
      EntityTransaction transacao = getEntityManager().getTransaction();

      transacao.begin();
      getEntityManager().persist(pessoa);
      transacao.commit();

      newInstance();
      list = null;

      return "sucesso";
    } catch (Exception e) {
      e.printStackTrace();
      return "falhou";
    }
  }

  public String update() {
    log.info("Alterando pessoa: " + pessoa.getNome());
    try {
      EntityTransaction transacao = getEntityManager().getTransaction();

      transacao.begin();
      getEntityManager().merge(pessoa);
      transacao.commit();

      newInstance();

      return "sucesso";
    } catch (Exception e) {
      e.printStackTrace();
      return "falhou";
    }
  }

  public String remove() {
    log.info("Removendo pessoa: " + pessoa.getNome());
    try {
      EntityTransaction transacao = getEntityManager().getTransaction();

      transacao.begin();
      getEntityManager().remove(pessoa);
      transacao.commit();

      newInstance();
      list = null;

      return "sucesso";
    } catch (Exception e) {
      e.printStackTrace();
      return "falhou";
    }
  }

  @SuppressWarnings("unchecked")
  public List getList() {
    if (list == null) {
      log.info("Buscando lista de pessoas");
      list = getEntityManager().createQuery("FROM Pessoa")
        .getResultList();
    }

    return list;
  }

  public EntityManager getEntityManager() {
    if (entityManager == null) {
      entityManager = EntityManagerUtil.getInstance().createEntityManager();
    }

    return entityManager;
  }

  public void setPessoa(Pessoa pessoa) {
    this.pessoa = pessoa;
  }

  public Pessoa getPessoa() {
    return pessoa;
  }

  public void setId(Long id) {
    this.id = id;
    if (id != null) {
      pessoa = getEntityManager().find(Pessoa.class, id);
    }
  }

  public Long getId() {
    return id;
  }

  public void newInstance() {
    pessoa = new Pessoa();
  }
}

Com esta classe completa o ‘back-end’ do crud, vamos adicionar o Manager Bean e as regras de navegação no faces-config.xml que pode ser encontrado no diretório WebContent/WEB-INF da aplicação:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="1.2" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">

  <managed-bean>
    <managed-bean-name>pessoaBean</managed-bean-name>
    <managed-bean-class>br.com.crud.bean.PessoaBean</managed-bean-class>
    <managed-bean-scope>request</managed-bean-scope>
  </managed-bean>

  <navigation-rule>
    <from-view-id>/cadastrarPessoa.jsp</from-view-id>

    <navigation-case>
      <from-action>#{pessoaBean.persist}</from-action>
      <from-outcome>sucesso</from-outcome>
      <to-view-id>/cadastrarPessoa.jsp</to-view-id>
    </navigation-case>

    <navigation-case>
      <from-outcome>editar</from-outcome>
      <to-view-id>/editarPessoa.jsp</to-view-id>
    </navigation-case>

    <navigation-case
      <from-action>#{pessoaBean.remove}</from-action>
      <from-outcome>sucesso</from-outcome>
      <to-view-id>/cadastrarPessoa.jsp</to-view-id>
    </navigation-case>
  </navigation-rule>

  <navigation-rule>
    <from-view-id>/editarPessoa.jsp</from-view-id>

    <navigation-case>
      <from-action>#{pessoaBean.update}</from-action>
      <from-outcome>sucesso</from-outcome>
      <to-view-id>/cadastrarPessoa.jsp</to-view-id>
    </navigation-case>
  </navigation-rule>
</faces-config>

Agora criaremos as páginas *.jsp, a primeira é o cadastro e listagem da entidade Pessoa, salve o arquivo com o nome cadastrarPessoa.jsp dentro do diretório WebContent.

<%@ page language="java" contentType="text/html; charset=UTF-8"
		pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<f:view>
	<html>
		<head>
			<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
			<title>Cadastro de Pessoa</title>
		</head>
		<body>
			<h:form>
<div align="center">
					<h:panelGrid columns="2">
						<h:outputLabel value="Nome" for="nome" />
						<h:inputText id="nome" value="#{pessoaBean.pessoa.nome}" />

						<h:outputLabel value="Sexo" for="sexo" />
						<h:selectOneRadio id="sexo" value="#{pessoaBean.pessoa.sexo}">
							<f:selectItem itemLabel="Feminino" itemValue="Feminino"/>
							<f:selectItem itemLabel="Masculino" itemValue="Masculino"/>
						</h:selectOneRadio>

						<h:outputLabel value="Idade" for="idade" />
						<h:inputText id="idade" value="#{pessoaBean.pessoa.idade}" />
					</h:panelGrid>

					<h:commandButton value="Cadastrar" action="#{pessoaBean.persist}" /></div>

<hr width="50%"/>

<div align="center">
					<h:dataTable value="#{pessoaBean.list}" var="_pessoa" rendered="#{pessoaBean.list != null}" width="50%" border="1">
						<h:column>
							<f:facet name="header">
								<h:outputText value="Nome" />
							</f:facet>
							<h:outputText value="#{_pessoa.nome}" />
						</h:column>

						<h:column>
							<f:facet name="header">
								<h:outputText value="Sexo" />
							</f:facet>
							<h:outputText value="#{_pessoa.sexo}" />
						</h:column>

						<h:column>
							<f:facet name="header">
								<h:outputText value="Idade" />
							</f:facet>
							<h:outputText value="#{_pessoa.idade}" />
						</h:column>

						<h:column>
							<f:facet name="header">
								<h:outputText value="Opções" />
							</f:facet>

							<h:commandLink value="Editar" action="editar">
								<f:setPropertyActionListener value="#{_pessoa.id}" target="#{pessoaBean.id}"/>
							</h:commandLink>

							<h:commandLink value="Remover" action="#{pessoaBean.remove}">
								<f:setPropertyActionListener value="#{_pessoa.id}" target="#{pessoaBean.id}"/>
							</h:commandLink>
						</h:column>
					</h:dataTable></div>
</h:form>
		</body>
	</html>
</f:view>

E por fim a página de edição da entidade Pessoa, salve o arquivo com o nome editarPessoa.jsp dentro do diretório WebContent.

<%@ page language="java" contentType="text/html; charset=UTF-8"
		pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<f:view>
	<html>
		<head>
			<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
			<title>Editando Registro</title>
		</head>
		<body>
			<h:form>
				<h:inputHidden value="#{pessoaBean.pessoa.id}" />
<div align="center">
					<h:panelGrid columns="2">
						<h:outputLabel value="Nome" for="nome" />
						<h:inputText id="nome" value="#{pessoaBean.pessoa.nome}" />

						<h:outputLabel value="Sexo" for="sexo" />
						<h:selectOneRadio id="sexo" value="#{pessoaBean.pessoa.sexo}">
							<f:selectItem itemLabel="Feminino" itemValue="Feminino"/>
							<f:selectItem itemLabel="Masculino" itemValue="Masculino"/>
						</h:selectOneRadio>

						<h:outputLabel value="Idade" for="idade" />
						<h:inputText id="idade" value="#{pessoaBean.pessoa.idade}" />
					</h:panelGrid>

					<h:commandButton value="Confirmar" action="#{pessoaBean.update}" /></div>
</h:form>
		</body>
	</html>
</f:view>

Inicie o Apache Tomcat e acesse a aplicação no link http://localhost:8080/crud/cadastrarPessoa.jsf. Repare que o primeiro acesso é lento, se você olhar no log que está sendo exibido no Console do Eclipse, você verá que a aplicação está iniciando o EntityManagerFactory.  Lembra do atributo hibernate.hbm2ddl.auto=”update” que configuramos no arquivo persistence.xml? Devido a esta opção o Hibernate cria as tabelas na data base caso ela não exista, repare neste trecho do log:

23:17:56,341  INFO DatabaseMetadata:119 - table not found: Pessoa
23:17:56,342  INFO DatabaseMetadata:119 - table not found: Pessoa
23:17:56,344 DEBUG SchemaUpdate:203 - create table Pessoa (id bigint not null auto_increment, idade integer check (idade&gt;=15), nome varchar(255), sexo varchar(255), primary key (id))

Após a primeira inicialização acesse a página novamente e repare que agora o acesso é instantâneo. Efetue as operações permitidas pela aplicação recém criada e em paralelo acompanhe o log pelo Console do Eclipse para ir se acostumando com os ‘debug’ do Hibernate. A princípio o JPA se demonstra um pouco complexo para quem está começando, no entanto com um pouco de estudo em cima de seus recursos já esclarece bastante o seu funcionamento.

E caso não tenha notado, a documentação do framework está disponível também no idioma pt_BR:

ls hibernate-distribution-3.6.0.Final/documentation/manual/pt-BR/
html  html_single  pdf

Deixe seu comentário ou sugestões =)

24 comentários sobre “CRUD simples com Hibernate e JSF

  1. Muito bom, quebrei a cabeça o dia todo até achar este tutorial, não conseguia configurar o C3p0.

    Muito obrigado, espero q ajude muita gente ainda

    1. Olá,

      eu não possuo nenhuma máquina com esse SO, porém acredito que o projeto seja portável entre plataformas, exatamente qual problema você teve em relação a isto?

      No pior dos casos, você pode baixar o projeto, descompactar e olhar o código em qualquer editor de texto.

      Abraços.

  2. Cara, muito bem explicado, projeto funcionou de boa aqui comigo, aprendi nessa leitura o que não consegui aprender durante 6 meses estudando Hibernate na faculdade. Post D+++++ vlw!!!!

  3. Muito obrigado pela aula! Muito simples e objetivo para um tema com esta magnitude de complexidade! Parabéns pelo excelente trabalho!

  4. João, tenho dúvidas em algumas linhas do código… rodei em SO Win7.
    01) No faces-config tem dois “xsi” e um “xi” (conforme transcrição do código, abaixo)… está correto só “xmlns:xi=…” ?

    02) No código há a declaração de uma variável List, mas o eclipse informa que está cru e pede a declaração de que tipo ele deve ser… eu completei com List , mas ao subir o software, dá erro na construção da página de inserção de novo cadastro e a mesma nem abre e dispara a seguinte tela:

    HTTP Status 500 – /cadastrarPessoa.jsp(37,20) ‘#{pessoaBean.list != null}’ Error reading ‘list’ on type br.com.crud.bean.PessoaBean

    type Exception report

    message /cadastrarPessoa.jsp(37,20) ‘#{pessoaBean.list != null}’ Error reading ‘list’ on type br.com.crud.bean.PessoaBean

    description The server encountered an internal error that prevented it from fulfilling this request.

    exception

    javax.servlet.ServletException: /cadastrarPessoa.jsp(37,20) ‘#{pessoaBean.list != null}’ Error reading ‘list’ on type br.com.crud.bean.PessoaBean
    javax.faces.webapp.FacesServlet.service(Unknown Source)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    root cause

    org.apache.jasper.el.JspELException: /cadastrarPessoa.jsp(37,20) ‘#{pessoaBean.list != null}’ Error reading ‘list’ on type br.com.crud.bean.PessoaBean
    org.apache.jasper.el.JspValueExpression.getValue(JspValueExpression.java:123)
    javax.faces.component.ComponentStateHelper.eval(Unknown Source)
    javax.faces.component.UIComponentBase.isRendered(Unknown Source)
    javax.faces.component.UIComponent.encodeAll(Unknown Source)
    javax.faces.render.Renderer.encodeChildren(Unknown Source)
    javax.faces.component.UIComponentBase.encodeChildren(Unknown Source)
    javax.faces.component.UIComponent.encodeAll(Unknown Source)
    javax.faces.component.UIComponent.encodeAll(Unknown Source)
    com.sun.faces.application.view.JspViewHandlingStrategy.doRenderView(Unknown Source)
    com.sun.faces.application.view.JspViewHandlingStrategy.renderView(Unknown Source)
    com.sun.faces.application.view.MultiViewHandler.renderView(Unknown Source)
    com.sun.faces.lifecycle.RenderResponsePhase.execute(Unknown Source)
    com.sun.faces.lifecycle.Phase.doPhase(Unknown Source)
    com.sun.faces.lifecycle.LifecycleImpl.render(Unknown Source)
    javax.faces.webapp.FacesServlet.service(Unknown Source)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    root cause

    java.lang.NoClassDefFoundError: Could not initialize class br.com.crud.tool.EntityManagerUtil
    br.com.crud.bean.PessoaBean.getEntityManager(PessoaBean.java:91)
    br.com.crud.bean.PessoaBean.getList(PessoaBean.java:82)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    java.lang.reflect.Method.invoke(Unknown Source)
    javax.el.BeanELResolver.getValue(BeanELResolver.java:97)
    com.sun.faces.el.DemuxCompositeELResolver._getValue(Unknown Source)
    com.sun.faces.el.DemuxCompositeELResolver.getValue(Unknown Source)
    org.apache.el.parser.AstValue.getValue(AstValue.java:169)
    org.apache.el.parser.AstNotEqual.getValue(AstNotEqual.java:37)
    org.apache.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:184)
    org.apache.jasper.el.JspValueExpression.getValue(JspValueExpression.java:115)
    javax.faces.component.ComponentStateHelper.eval(Unknown Source)
    javax.faces.component.UIComponentBase.isRendered(Unknown Source)
    javax.faces.component.UIComponent.encodeAll(Unknown Source)
    javax.faces.render.Renderer.encodeChildren(Unknown Source)
    javax.faces.component.UIComponentBase.encodeChildren(Unknown Source)
    javax.faces.component.UIComponent.encodeAll(Unknown Source)
    javax.faces.component.UIComponent.encodeAll(Unknown Source)
    com.sun.faces.application.view.JspViewHandlingStrategy.doRenderView(Unknown Source)
    com.sun.faces.application.view.JspViewHandlingStrategy.renderView(Unknown Source)
    com.sun.faces.application.view.MultiViewHandler.renderView(Unknown Source)
    com.sun.faces.lifecycle.RenderResponsePhase.execute(Unknown Source)
    com.sun.faces.lifecycle.Phase.doPhase(Unknown Source)
    com.sun.faces.lifecycle.LifecycleImpl.render(Unknown Source)
    javax.faces.webapp.FacesServlet.service(Unknown Source)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    note The full stack trace of the root cause is available in the Apache Tomcat/8.0.26 logs.

    Apache Tomcat/8.0.26

    1. Olá Vitor, seguem abaixo as respostas:

      1) Sim, está correto. XI significa XML Include, enquanto que XSI significa XML Schema Instance.

      2) Faltou definir o tipo da lista, nesse caso ficaria assim: private List list. Para entender melhor o que significa declarar depois de uma coleção, pesquise por “tipos parametrizados” (ou Generic Types, em inglês).

      Abraços

  5. Verificando o resultado do console, ele passa pelo método public List getList() identifica que a lista é igual a null e executa o comando ” log.info(“Buscando lista de pessoas”); ” e o erro se dá na passagem da GUI cadastrarPessoa.jsp

  6. Boa tarde, João. Obrigado pelo retorno!
    Enfim, o código funcionou perfeitamente bem aqui no Win7 64bits. Realizei algumas pinceladinhas de leve no código e agora poderei dar continuidade em meu projeto!
    Estou usando a seguinte configuração:
    Win 7 64bits
    Eclipse MARS
    Apache Tomcat 8.0.26 Server
    MySQL Server 5.6
    JRE1.8.0_65
    Hibernate 5.0.2 Final
    Hibernate Validator 4.3.2

Deixe um comentário