O Primefaces é um framework desenvolvido principalmente para a camada de apresentação em projetos baseados no padrão MVC. Seu código é uma extensão do JSF e esses dois frameworks convivem bem na criação de páginas Web. O Hibernate é aplicado exclusivamente na camada Model para facilitar a interação com informações armazenadas em banco de dados do tipo SQL.
O projeto exemplo desenvolvido para esse artigo simula o cadastro completo de clientes, que poderia ser parte de uma aplicação para CRM. A primeira providência é baixar o Eclipse do seu site (o tipo que vamos utilizar nesse artigo é a IDE para JEE). A instalação do Eclipse é muito simples: desempacote o arquivo baixado em qualquer pasta do seu computador. Com o Eclipse instalado, podemos baixar o Tomcat que é o servidor JEE da fundação Apache. Da mesma forma que o Eclipse, instale o Tomcat.
O próximo passo é configurar o Eclipse para que chame o Tomcat sempre que quisermos executar nosso projeto. Abra o Eclipse e, após escolher o diretório do seu workspace, acesse Window > Preferences. Na janela nova encontre a opção Server > Runtime Environments, na qual estão listados os servidores já disponíveis na IDE e o botão Add.., onde podemos adicionar um servidor novo. Conforme ilustrado na Figura 1, clicando nesse botão devemos escolher o Tomcat 8 e clicar em Next. Na próxima tela, devemos apontar o diretório raiz da instalação do Tomcat.
Com o Tomcat configurado, devemos criar um novo projeto do tipo Dynamic Web Project. Além disso, já que nesse artigo vamos utilizar o Maven para gerenciar as dependências, necessitamos instalar m2e, um plugin para Eclipse que facilita muito o desenvolvimento. Como em toda instalação de plugin, podemos ir em Help > Install New Software... e na tela de configuração adicionar a URL- http://download.eclipse.org/technology/m2e/releases. Se tudo foi realizado corretamente, podemos transformar nosso projeto em um projeto Maven, clicando no nome do projeto com o botão direito e escolhendo a opção Configure > Convert to Maven Project. Assim, podemos instalar as várias dependências necessárias para nosso projeto.
A Listagem 1 apresenta o arquivo pom.xml do projeto. Esse arquivo adiciona ao projeto as dependências dos seguintes frameworks: JSF, Primefaces, Hibernate e Log4j, além do driver JDBC do Postgres.
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>exemplo-crud-jsf-hibernate</groupId>
<artifactId>exemplo-crud-jsf-hibernate</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<warSourceDirectory>WebContent</warSourceDirectory>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>4.0</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.2.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.common</groupId>
<artifactId>hibernate-commons-annotations</artifactId>
<version>4.0.1.Final</version>
<classifier>tests</classifier>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
<version>1.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.0.1.Final</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.0.0.GA</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.4</version>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.1.0.CR2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.4</version>
</dependency>
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.1-901-1.jdbc4</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</project>
Com isso já poderíamos criar os códigos da aplicação, contudo, para testar ainda necessitamos instalar o Postgres, que pode ser obtido do seu site oficial. Para instalar o Postgres devemos simplesmente seguir as instruções do seu instalador. Para acessar seus dados, podemos usar a ferramenta gráfica PgAdmin, onde devemos criar uma base de dados, que nesse artigo vamos chamar de CRM.
Assim, adotando uma abordagem que vai da camada Model para a View, podemos criar o arquivo hibernate.cfg.xml que definirá como nossa aplicação acessa o Postgres. A Listagem 2 apresenta esse arquivo que tem três definições principais: as propriedades dialect e driver_class definem que usaremos o Postgres para armazenamento de dados; url, usarname e password definem como acessar o Postgres; e em mapping vamos dizer quais são os beans que serão persistidos.
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect
</property>
<property name="hibernate.connection.driver_class">org.postgresql.Drive
</property>
<property name="hibernate.connection.username">devmedia
</property>
<property name="hibernate.connection.password">devmedia
</property>
<property name="hibernate.connection.url">
jdbc:postgresql://localhost:5432/filiais</property>
<property name="connection_pool_size">1</property>
<property name="hbm2ddl.auto">update</property>
<property name="show_sql">true</property>
<mapping class="org.ecjfh.model.Empresa" />
<mapping class="org.ecjfh.model.Filial" />
<mapping class="org.ecjfh.model.Matriz" />
</session-factory>
</hibernate-configuration>
A etapa seguinte será criar os beans que devemos persistir. No nosso exemplo, vamos criar a classe abstrata Empresa, que contém as propriedades das empresas que serão salvos na aplicação CRM, e as classes Matriz e Filial que herdaram da classe cliente as propriedades principais e adicionaram respectivamente propriedades para armazenar: nas filiais o objeto que representa a sua matriz; e na matriz sua lista de filiais. A Listagem 3 apresenta as três classes e é importante ressaltar que cada classe deve estar em um arquivo exclusivo, com o mesmo nome dessa classe.
O principal detalhe que devemos levar em conta entre essas três classes é o mapeamento da é o relacionamento um-para-muitos entre uma matriz e suas filiais. No Hibernate isso é implementado com as anotações @ManyToOne e @OneToMany, por uma decisão de projeto foi escolhido o FetchType.EAGER, que irá buscar e carregar os dados de todas filiais para cada matriz recuperada. Isso deve ser usado com muito cuidado, pois pode levar a problemas no uso de memória, rede e do próprio banco de dados. Em um exemplo, é aceitável.
package org.ecjfh.model;
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public abstract class Empresa {
@Id
private String CNPJ;
private String razaoSocial;
private String logradouro;
private Integer numero;
private String complemento;
private String municipio;
private String uf;
private String telefone;
private String email;
public String getRazaoSocial() {
return razaoSocial;
}
public void setRazaoSocial(String razaoSocial) {
this.razaoSocial = razaoSocial;
}
public String getCNPJ() {
return CNPJ;
}
public void setCNPJ(String cNPJ) {
CNPJ = cNPJ;
}
public String getLogradouro() {
return logradouro;
}
public void setLogradouro(String logradouro) {
this.logradouro = logradouro;
}
public Integer getNumero() {
return numero;
}
public void setNumero(Integer numero) {
this.numero = numero;
}
public String getComplemento() {
return complemento;
}
public void setComplemento(String complemento) {
this.complemento = complemento;
}
public String getMunicipio() {
return municipio;
}
public void setMunicipio(String municipio) {
this.municipio = municipio;
}
public String getUf() {
return uf;
}
public void setUf(String uf) {
this.uf = uf;
}
}
package org.ecjfh.model;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table
public class Filial extends Empresa {
@ManyToOne(fetch = FetchType.EAGER)
private Matriz matriz;
public Matriz getMatriz() {
return matriz;
}
public void setMatriz(Matriz matriz) {
this.matriz = matriz;
}
}
package org.ecjfh.model;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table
public class Matriz extends Empresa {
@OneToMany(fetch=FetchType.EAGER,mappedBy="matriz", orphanRemoval=true)
private Set<Filial> filiais;
public Set<Filial> getFiliais() {
return filiais;
}
public void setFiliais(Set<Filial> filiais) {
this.filiais = filiais;
}
}
Para persistência dessas classes vamos criar uma outra classe que respeita o padrão DAO, chamada EmpresaDAO, que conterá as quatro operações. Para facilitar foi criada também a subclasse HibernateUtils, que cria a sessão do Hibernate. A Listagem 4 ilustra a classe EmpresaDAO.
package org.ecjfh.dao;
import java.util.ArrayList;
import java.util.List;
import org.ecjfh.model.Empresa;
import org.ecjfh.model.Filial;
import org.ecjfh.model.Matriz;
import org.ecjfh.util.HibernateUtil;
import org.hibernate.Session;
import org.hibernate.Transaction;
public class EmpresaDAO {
public void createEmpresa(Empresa empresa) throws Exception{
Transaction trns = null;
Session session = HibernateUtil.getSessionFactory().openSession();
try {
trns = session.beginTransaction();
session.save(empresa);
session.getTransaction().commit();
} catch (RuntimeException e) {
if (trns != null) {
trns.rollback();
}
e.printStackTrace();
throw new Exception("Error ao criar empresa");
} finally {
session.flush();
session.close();
}
}
public Empresa getEmpresa(String cnpj){
Empresa empresa = null;
Session session = HibernateUtil.getSessionFactory().openSession();
try {
empresa = (Empresa) session.get(Empresa.class, new String(cnpj));
} finally {
session.flush();
session.close();
}
return empresa;
}
public void deleteEmpresa(String empresaId) throws Exception{
Transaction trns = null;
Session session = HibernateUtil.getSessionFactory().openSession();
try {
trns = session.beginTransaction();
Empresa empresa = (Empresa) session.load(Empresa.class,
new String(empresaId));
if(empresa instanceof Filial){
((Filial) empresa).setMatriz(null);
}
session.delete(empresa);
session.getTransaction().commit();
} catch (RuntimeException e) {
if (trns != null) {
trns.rollback();
}
e.printStackTrace();
throw new Exception("Error ao excluir empresa");
} finally {
session.flush();
session.close();
}
}
@SuppressWarnings("unchecked")
public List<Empresa> listEmpresas(){
List<Empresa> empresas = new ArrayList<Empresa>();
Session session = HibernateUtil.getSessionFactory().openSession();
try {
empresas = session.createQuery("from Empresa").list();
} catch (RuntimeException e) {
e.printStackTrace();
} finally {
session.flush();
session.close();
}
return empresas;
}
@SuppressWarnings("unchecked")
public List<Matriz> listMatrizes(){
List<Matriz> matrizes = new ArrayList<Matriz>();
Session session = HibernateUtil.getSessionFactory().openSession();
try {
matrizes = session.createQuery("from Matriz").list();
} catch (RuntimeException e) {
e.printStackTrace();
} finally {
session.flush();
session.close();
}
return matrizes;
}
public void updateEmpresa(Empresa empresa) throws Exception{
Transaction trns = null;
Session session = HibernateUtil.getSessionFactory().openSession();
try {
trns = session.beginTransaction();
session.update(empresa);
session.getTransaction().commit();
} catch (RuntimeException e) {
if (trns != null) {
trns.rollback();
}
e.printStackTrace();
throw new Exception("Error ao atualizar empresa");
} finally {
session.flush();
session.close();
}
}
}
Nesse ponto, o ideal seria criar testes unitários para a classe EmpresaDAO, assim poderíamos garantir que a conexão, criação, recuperação, alteração e exclusão de dados estão sendo executadas corretamente.
Com o Hibernate configurado e suas classes já criadas, podemos avançar para a camada Controller. Para essa camada, devemos criar um Managed Bean, ou bean gerenciado, que terá como função controlar o uso dos dados entre a camada Model e a View. Para tal, devemos criar um arquivo chamada faces-config.xml, que deve estar contida na pasta WEB-INF do nosso projeto. Esse arquivo é apresentado na Listagem 5. Ele define um ManagedBean chamado EmpresaManagedBean, que será do tipo session, ou seja, os dados serão armazenados nesse bean durante todo o uso de um usuário especifico. Apenas quando o usuário fechar seu navegador e voltar a acessar essa aplicação, que essa sessão será reiniciada. Além disso, o faces-config define como a aplicação irá passar de uma página Web para outra.
<?xml version="1.0" encoding="UTF-8"?>
<faces-configa
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
version="2.2">
<managed-bean
<managed-bean-name>empresa</managed-bean-name>
<managed-bean-class>org.ecjfh.bo.EmpresaManagedBean
</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
<navigation-rule>
<from-view-id></from-view-id>
<navigation-case>
<from-outcome>index</from-outcome>
<to-view-id>index.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>insert</from-outcome>
<to-view-id>insert.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>update</from-outcome>
<to-view-id>update.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>
Com isso, podemos criar a classe EmpresaManagedBean. Essa classe será utilizada como um background das páginas Web criadas posteriormente. Na Listagem 6 está ilustrada essa classe, que contém como principal elemento um objeto do tipo empresa, sobre o qual vamos realizar as operações de inserção, deleção, alteração e listagem, que foram definidas na camada DAO.
package org.ecjfh.bo;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import org.ecjfh.dao.EmpresaDAO;
import org.ecjfh.model.Empresa;
import org.ecjfh.model.Matriz;
public class EmpresaManagedBean implements java.io.Serializable{
private static Logger log = Logger.getLogger(EmpresaManagedBean.class);
private static final long serialVersionUID = 1L;
private String selectedCNPJ;
private Empresa empresa;
private List<Empresa> empresas;
private List<Matriz> matrizes;
public Empresa getEmpresa() {
return empresa;
}
public void setEmpresa(Empresa empresa) {
this.empresa = empresa;
}
public List<Empresa> getEmpresas() {
return empresas;
}
public void setEmpresas(List<Empresa> empresas) {
this.empresas = empresas;
}
public List<Matriz> getMatrizes() {
return matrizes;
}
public void setMatrizes(List<Matriz> matrizes) {
this.matrizes = matrizes;
}
private String getSelectedCNPJ() {
return selectedCNPJ;
}
private void setMsg(String message) {
// TODO Auto-generated method stub
}
public void limparEmpresa() {
log.info("Limpando empresa");
this.empresa.setRazaoSocial("");
this.empresa.setCNPJ("");
this.empresa.setComplemento("");
this.empresa.setLogradouro("");
this.empresa.setMunicipio("");
this.empresa.setUf("");
this.empresa.setNumero(null);
}
public String editEmpresa() {
log.info("Editando empresa "+this.getSelectedCNPJ());
EmpresaDAO empresaDAO = new EmpresaDAO();
Empresa empresa = empresaDAO.getEmpresa(this.getSelectedCNPJ());
if(empresa!=null){
this.empresa.setCNPJ(empresa.getCNPJ());
this.empresa.setRazaoSocial(empresa.getRazaoSocial());
this.empresa.setMunicipio(empresa.getMunicipio());
this.empresa.setUf(empresa.getUf());
this.empresa.setLogradouro(empresa.getLogradouro());
this.empresa.setComplemento(empresa.getComplemento());
this.empresa.setNumero(empresa.getNumero());
}else{
this.setMsg("Empresa nao encontrada!");
log.error("Empresa nao encontrada!");
}
return "update";
}
public String createEmpresa() {
String str = "index";
try{
EmpresaDAO empresaDAO = new EmpresaDAO();
empresaDAO.createEmpresa(this.empresa);
limparEmpresa();
this.setMsg("Empresa cadastrada!");
}catch(Exception e){
this.setMsg(e.getMessage());
str = "insert";
log.error(e);
}
return str;
}
public String deleteEmpresa(){
log.info("Excluindo empresa "+this.getSelectedCNPJ());
String str = "index";
try{
EmpresaDAO empresaDAO = new EmpresaDAO();
empresaDAO.deleteEmpresa(this.getSelectedCNPJ());
limparEmpresa();
this.setMsg("Excluído com sucesso!");
}catch(Exception e){
this.setMsg(e.getMessage());
log.error(e);
}
return str;
}
public List<EmpresaManagedBean> getListaMatrizes(){
log.info("Listando matrizes");
List<EmpresaManagedBean> empresas =
new ArrayList<EmpresaManagedBean>();
try{
EmpresaDAO empresaDAO = new EmpresaDAO();
for(Matriz matriz:empresaDAO.listMatrizes()){
EmpresaManagedBean bean = new EmpresaManagedBean();
bean.setEmpresa(matriz);
empresas.add(bean);
}
}catch(Exception e){
this.setMsg(e.getMessage());
log.error(e);
}
return empresas;
}
public List<EmpresaManagedBean> getListaEmpresas(){
limparEmpresa();
log.info("Listando empresa");
List<EmpresaManagedBean> empresas =
new ArrayList<EmpresaManagedBean>();
try{
EmpresaDAO empresaDAO = new EmpresaDAO();
for(Empresa empresa:empresaDAO.listEmpresas()){
EmpresaManagedBean bean = new EmpresaManagedBean();
bean.setEmpresa(empresa);
empresas.add(bean);
}
}catch(Exception e){
this.setMsg(e.getMessage());
log.error(e);
}
return empresas;
}
public String updateEmpresa(){
String str = "index";
try{
EmpresaDAO empresaDAO = new EmpresaDAO();
empresaDAO.updateEmpresa(this.empresa);
limparEmpresa();
this.setMsg("Atualizado com sucesso!");
}catch(Exception e){
this.setMsg(e.getMessage());
str = "deleteUpdate";
log.error(e);
}
return str;
}
}
O passo seguinte é criar os arquivos da camada View, que nesse exemplo consistem exclusivamente de documentos XHTML. O primeiro a ser criado é o insert.xhtml, que contém um formulário para cadastro de clientes na aplicação. Essa página tem os seguintes campos e requisitos de validação:
- Razão Social (input text, até 100 caracteres), preenchimento obrigatório;
- CNPJ (utilizar máscara de validação), preenchimento obrigatório;
- Logradouro (input text, até 150 caracteres), preenchimento obrigatório;
- Número (input text, validação para números inteiros, até 10 caracteres), preenchimento obrigatório;
- Complemento (input text, até 150 caracteres), preenchimento opcional
- Município (input text, até 150 caracteres), preenchimento obrigatório;
- UF (input text, até 2 caracteres), preenchimento obrigatório;
- Matriz ou Filial (select box);
- Se Filial, apresentar campo de consulta para selecionar uma empresa matriz pré-cadastrada, com consulta por razão social ou CNPJ;
- Telefone de contato (máscara de telefone com DDI, DDD, Prefixo e Sufixo), preenchimento obrigatório;
- E-mail (validação de máscara *@*.* ou *@*.*.*), preenchimento opcional.
A Listagem 7 ilustra como criar esse formulário utilizando Primefaces, que é uma biblioteca de tags, cujo prefixo e o “p”. Para utilizá-la em uma página, adicione . Para implementar as regras de validação vamos adicionar a tag required="true" nos campos obrigatórios, e regras de validação usando expressões regulares. Para CNPJ esse tipo de regra deve ser implementada da seguinte forma:
<?xml version='1.0' encoding='UTF-8' ?>
<!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:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:head>
</h:head>
<h:body>
<p:outputLabel value="#{empresa.msg}" id="msg1" styleClass="msg" />
<h:form id="empresaForm" enctype="multipart/form-data" prependId="false">
<p:panelGrid id="panel1" columns="3" border="3" cellpadding="5"
cellspacing="1">
<f:facet name="header">
<h:outputText value="Criar empresa" />
</f:facet>
<p:outputLabel value="Tipo:" />
<p:selectOneRadio id="matrizFilial" value="#{empresa.matrizFilial}">
<f:selectItem itemValue="true" itemLabel="Matriz" />
<f:selectItem itemValue="false" itemLabel="Filial" />
<f:ajax event="change" execute="@this" render="panel1" />
</p:selectOneRadio>
<p:message for="matrizFilial" />
<p:outputLabel value="Selecionar matriz:"
rendered="#{empresa.matrizFilial eq 'false'}" />
<p:selectOneMenu id="matrizes" value="#{empresa.matriz}"
rendered="#{empresa.matrizFilial eq 'false'}">
<f:selectItems value="#{empresa.listaMatrizes}" var="e"
itemLabel="#{e.CNPJ}" itemValue="#{e.CNPJ}" />
</p:selectOneMenu>
<p:message for="matrizes"
rendered="#{empresa.matrizFilial eq 'false'}" />
<p:outputLabel value="Razao social:" />
<p:inputText value="#{empresa.razaoSocial}" id="razaoSocial"
maxlength="100" required="true"
requiredMessage="Campo obrigatório" />
<p:message for="razaoSocial" />
<p:outputLabel value="CNPJ:" />
<p:inputText value="#{empresa.CNPJ}" required="true"
id="CNPJ" validatorMessage="CNPJ mal formatado"
requiredMessage="Campo obrigatório">
<f:validateRegex pattern="^[0-9]{2,3}\.[0-9]{3}
\.[0-9]{3}\/[0-9]{4}-[0-9]{2}$" />
</p:inputText>
<p:message for="CNPJ" />
<p:outputLabel value="Logradouro:" required="true" />
<p:inputText value="#{empresa.logradouro}" id="logradouro"
maxlength="150" required="true"
requiredMessage="Campo obrigatório" />
<p:message for="logradouro" />
<p:outputLabel value="Número:" />
<p:inputText value="#{empresa.numero}" id="numero" required="true"
requiredMessage="Campo obrigatório" maxlength="10">
<f:convertNumber integerOnly="true" type="number" />
</p:inputText>
<p:message for="numero" />
<p:outputLabel value="Complemento:" />
<p:inputText value="#{empresa.complemento}" id="complemento" />
<p:message for="complemento" />
<p:outputLabel value="Município:" />
<p:inputText value="#{empresa.municipio}" id="municipio"
maxlength="150" required="true"
requiredMessage="Campo obrigatório" />
<p:message for="municipio" />
<p:outputLabel value="UF:" />
<p:inputText value="#{empresa.uf}" id="uf" maxlength="2"
required="true" requiredMessage="Campo obrigatório" />
<p:message for="uf" />
<p:outputLabel value="Telefone:" />
<p:inputText value="#{empresa.telefone}" id="telefone1"
required="true" requiredMessage="Campo obrigatório"
validatorMessage="Telefone mal formatado. Ex. (99) 9999-9999">
</p:inputText>
<p:message for="telefone" />
<p:outputLabel value="Telefone 2:" />
<p:inputText value="#{empresa.telefone2}" id="telefone2"
validatorMessage="Telefone mal formatado. Ex. (99) 9999-9999">
<f:validateRegex
pattern="^[+][9][0-9]{2}(\(11\) [9][0-9]
{4}-[0-9]{4})|(\(1[2-9]\) [5-9][0-9]{3}-[0-9]{4})|
(\([2-9][1-9]\) [5-9][0-9]{3}-[0-9]{4})$" />
</p:inputText>
<p:message for="telefone2" />
<p:outputLabel value="Email" />
<p:inputText id="email" value="#{empresa.email}" label="email"
size="40" validatorMessage="Email mal formatado">
<f:validateRegex
pattern="^[_A-Za-z0-9-\+]+(\.[_A-Za-z0-9-]+)*
@[A-Za-z0-9-]+(\.[A-Za-z0-9]+)*(\.[A-Za-z]{2,})$" />
</p:inputText>
<p:message for="email" />
<f:facet name="footer">
<h:commandButton value="Salvar"
action="#{empresa.createEmpresa}"
update="empresaForm">
</h:commandButton>
</f:facet>
</p:panelGrid>
</h:form>
</h:body>
</html>
O próximo passo a ser criado é o index.xhtml, que contém uma tabela que lista todos clientes já cadastrados na aplicação. O principal comando dessa página é o p:dataTable, um dos componentes mais interessantes do Primefaces. Esse componente renderiza uma tabela HTML que contém também comandos para ordenar as colunas, ordenar os valores, editar e excluir seus valores, representados na Listagem 8. Por exemplo, para que o CNPJ possa ser ordenado e buscado, sortBy="#{e.CNPJ}"filterBy="#{e.CNPJ}". Além disso, essa tabela faz paginação automática, adicionando simplesmente o atributo paginator="true". Outro ponto importante são os botões para edição e exclusão. O primeiro chamará a página update.xhtml apresentada na sequência (usando o método editEmpresa) enquanto o segundo irá executar o código para exclusão da empresa de acordo com a linha selecionada (usando o método deleteEmpresa), esses dois métodos recebem como parâmetro o CNPJ da empresa selecionada.
<?xml version='1.0' encoding='UTF-8' ?>
<!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:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:head>
</h:head>
<h:body>
<p:outputLabel value="#{empresa.msg}" id="msg1" styleClass="msg" />
<p:dataTable emptyMessage="Não há empresas cadastradas"
value="#{empresa.listaEmpresas}" var="e" styleClass="order-table"
headerClass="order-table-header"
rowClasses="order-table-odd-row,order-table-even-row" paginator="true"
rows="20">
<p:column headerText="CNPJ" sortBy="#{e.CNPJ}" filterBy="#{e.CNPJ}"
filterMatchMode="exact">
<h:outputText value="#{e.CNPJ}" />
</p:column>
<p:column headerText="Razão Social" sortBy="#{e.razaoSocial}"
filterBy="#{e.razaoSocial}" filterMatchMode="exact">
<h:outputText value="#{e.razaoSocial}" />
</p:column>
<p:column headerText="UF" sortBy="#{e.uf}" filterBy="#{e.uf}"
filterMatchMode="exact">
<h:outputText value="#{e.uf}" />
</p:column>
<p:column headerText="Município" sortBy="#{e.municipio}"
filterBy="#{e.municipio}" filterMatchMode="exact">
<h:outputText value="#{e.municipio}" />
</p:column>
<p:column>
<f:facet name="header">
Filial
</f:facet>
#{e.tipo}
</p:column>
<p:column>
<h:form id="commandForm">
<h:commandButton value="Delete" styleClass="fs-button-portfolio"
action="#{empresa.deleteEmpresa}" ajax="false">
<f:setPropertyActionListener
target="#{empresa.selectedCNPJ}"
value="#{e.CNPJ}" />
</h:commandButton>
<h:commandButton value="Edit" styleClass="fs-button-portfolio"
action="#{empresa.editEmpresa}" ajax="false">
<f:setPropertyActionListener
target="#{empresa.selectedCNPJ}"
value="#{e.CNPJ}" />
</h:commandButton>
</h:form>
</p:column>
</p:dataTable>
</h:body>
</html>
A última parte desse projeto é a página update.xhtml. Essa página é bastante parecida com o insert.xhtml. A principal diferença está no método chamado por seu commandButton, nesse caso updateEmpresa, conforme apresentado na Listagem 9.
<f:facet name="footer">
<h:commandButton value="Atualizar"
update="empresaForm"
action="#{empresa.updateEmpresa}">
<f:ajax
render="razaoSocial CNPJ logradouro numero complemento
municipio uf telefone1 telefone2 fax"
execute="@form" />
</h:commandButton>
</f:facet>
Esse exemplo pode ser expandido as ferramentas já apresentadas. Além disso, a interface pode receber um tratamento mais fino em relação a usabilidade e estética. O código do exemplo está salvo como um projeto do Eclipse e disponível para download nesse post.