Thursday, September 2, 2010

CRUD Seam

CRUD Seam
1 – Introdução
Agora que já vimos o projeto rodando.
Vamos acrescentar algumas funcionalidades ao sistema de locação de carros (locar).
Basicamente, nós temos uma empresa de locação de veículos.
O sistema precisa fazer o seguinte:
- Cadastrar os veículos disponíveis nas cidades
- Buscar e reservar veículos em uma cidade
- Locação de um veículo


2 – Modelo
Crie uma classe que usaremos como ancestral para nossas entidades persistentes.
Selecione o projeto locar-ejb.
File -> New -> Class
Package: br.com.locar.entity
Name: AppEntity
Abstract: yes (marcado)
Interfaces: java.io.Serializable
Finish

Adicione 2 atributos:
- Long id
- int versao

Adicione as anotações de JPA:
- @Id @GeneratedValue
- @Version

A classe fica assim:

package br.com.locar.entity;

import java.io.Serializable;

import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Version;

@MappedSuperclass
public abstract class AppEntity implements Serializable {

private static final long serialVersionUID = 3267491073682419272L;

private Long id;
private int versao;

@Id
@GeneratedValue
public Long getId() {
return id;
}

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

@Version
public int getVersao() {
return versao;
}

public void setVersao(int versao) {
this.versao = versao;
}
}

Crie uma classe Cidade.
Selecione o projeto locar-ejb.
File -> New -> Class
Package: br.com.locar.entity
Name: Cidade
Superclass: AppEntity
Finish

Adicione 1 atributo:
- nome : String

Adicione as anotações de JPA:
- @Entity
- @NotNull
- @Length(min = 3, max = 30)

Gere os get e set
Gere o serial version

A classe fica assim:

package br.com.locar.entity;

import javax.persistence.Entity;

import org.hibernate.validator.Length;
import org.hibernate.validator.NotNull;

@Entity
public class Cidade extends AppEntity {

private static final long serialVersionUID = -4275579483864354167L;

private String nome;

@NotNull
@Length(min = 3, max = 30)
public String getNome() {
return nome;
}

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

}

3 – Controle
Crie uma classe CidadeAction.
A classe CidadeAction terá uma cidade e uma lista de cidades.
O atributo cidade servirá para ligarmos aos campos de cadastro e edição de cidades na tela.
A lista de cidades servirá para montar uma tabela com as cidades na tela.
Usaremos um Entity Manager para trabalharmos com a persistencia.
E uma classe Log para gerarmos o log da aplicação.

Selecione o projeto locar-ejb.
File -> New -> Class
Package: br.com.locar.session
Name: CidadeAction
Finish

Adicione os atributos:
- cidade : Cidade
- cidades: List<cidade>
- cidadeSelecionada: Cidade
- log : Log
- entityManager : EntityManager

Adicione as anotações do Seam
- @Name(“cidadeAction”)
- @DataModel
- @DataModelSelection
- @Logger
- @In

A classe fica assim:

package br.com.locar.session;

import java.util.List;

import javax.persistence.EntityManager;

import org.jboss.seam.annotations.Factory;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.datamodel.DataModel;
import org.jboss.seam.annotations.datamodel.DataModelSelection;
import org.jboss.seam.log.Log;

import br.com.locar.entity.Cidade;

@Name("cidadeAction")
public class CidadeAction {

private Cidade cidade = new Cidade();

@DataModel
private List<cidade> cidades;

@DataModelSelection
private Cidade cidadeSelecionada;

@Logger
private Log log;

@In
private EntityManager entityManager;

public Cidade getCidade() {
return cidade;
}

@Factory("cidades")
public void inicializaCidades() {
log.info("Inicializa cidades");
this.cidades = entityManager.createQuery("from Cidade").getResultList();
}

public String salvar() {
log.info("Salver cidade nome = #", cidade);
entityManager.merge(cidade);
this.cidade = new Cidade();
inicializaCidades();
return "cidade.xhtml";
}

public String remover() {
log.info("Remover cidade id = #", cidadeSelecionada.getId());
entityManager.remove(cidadeSelecionada);
inicializaCidades();
return "cidade.xhtml";
}

public void editar() {
this.cidade = cidadeSelecionada;
}
}

4 – Visão
Vamos criar agora uma página para o cadastro e exibição das cidades.
Crie uma página xhtml.
Para vacilitar vamos copiar a home.xhtml e colar ela com o nome cidade.xhtml.

Remova o rich panel todo:
<rich:panel> até </rich:panel> (inclusive)

Coloque um formulário:
<h:form> </h:form>

Dentro do formulário coloque um grid com 3 colunas:
<h:panelgrid columns="”3”"> </h:panelgrid>

Dentro do grid insira um campo oculto com o id da cidade, um campo para o nome da cidade e um botão para salvar:

<h:inputhidden value="#{cidadeAction.cidade.id}">

<s:decorate template="/layout/edit.xhtml">
<ui:define name="label">Nome:</ui:define>
<h:inputtext value="#{cidadeAction.cidade.nome}" required="true">
</h:inputtext></s:decorate>

<h:commandbutton value="Salvar" actionlistener="#{cidadeAction.salvar}">


Aqui usamos um componente decorate apontando para o template edit.xhtml.
Depois falarei mais sobre o facelets e como criar componentes.
Mas vale a penda dar uma olhada nesse arquivo.
Ele é um componente formado por um label e um espaço para incluir o componente de entrada de dados.
Que facilita na criação de um componente de entra e nos estilos e validações.
Podemos observar que este componente tem estilo para quando marcado com required que é o nosso caso.
Ele faz a validação integrada com as nossas anotações no modelo.
Como podemos ver tentando cadastrar usando o campo nome em branco ou digitando menos de 3 caracteres.
E já exibe a mensagem de erro ao cliente.

Para verificarmos se o registro foi gravado vamos colocar em baixo na página uma tabela com as cidades gravadas no banco.
Usando o componente <rich:datatable> vamos recuperar as cidades.
<rich:datatable value="#{cidades}" var="c" style="width: 60%">

Preenchemos as colunas com o componente <rich:column>.
Colocamos um titulo na coluna usamos <f:face name="”header”">
<rich:column>
<f:facet name="header">ID</f:facet>
<h:outputtext value="#{c.id}">
</h:outputtext></rich:column>

E dois link, um para edição e outro para remoção do registro.
<rich:column>
<f:facet name="header">Editar</f:facet>
<h:commandlink action="#{cidadeAction.editar}">
<h:outputtext value="Editar">
</h:outputtext></h:commandlink>
</rich:column>
<rich:column>
<f:facet name="header">Remover</f:facet>
<h:commandlink action="#{cidadeAction.remover}">
<h:outputtext value="Remover">
</h:outputtext></h:commandlink>
</rich:column>

A pagina cidade.xhtml fica o seguinte:


<ui:composition xmlns="http://www.w3.org/1999/xhtml" s="http://jboss.com/products/seam/taglib" ui="http://java.sun.com/jsf/facelets" f="http://java.sun.com/jsf/core" h="http://java.sun.com/jsf/html" rich="http://richfaces.org/rich" template="layout/template.xhtml">

<ui:define name="body">

<h1>Cidade</h1>

<h:form>

<h:panelgrid columns="3">

<h:inputhidden value="#{cidadeAction.cidade.id}">

<s:decorate template="/layout/edit.xhtml">
<ui:define name="label">Nome:</ui:define>
<h:inputtext value="#{cidadeAction.cidade.nome}" required="true">
</h:inputtext></s:decorate>

<h:commandbutton value="Salvar" actionlistener="#{cidadeAction.salvar}">

</h:commandbutton></h:inputhidden></h:panelgrid>




<rich:datatable value="#{cidades}" var="c" style="width: 60%">
<rich:column>
<f:facet name="header">ID</f:facet>
<h:outputtext value="#{c.id}">
</h:outputtext></rich:column>
<rich:column>
<f:facet name="header">Nome</f:facet>
<h:outputtext value="#{c.nome}">
</h:outputtext></rich:column>
<rich:column>
<f:facet name="header">Editar</f:facet>
<h:commandlink action="#{cidadeAction.editar}">
<h:outputtext value="Editar">
</h:outputtext></h:commandlink>
</rich:column>
<rich:column>
<f:facet name="header">Remover</f:facet>
<h:commandlink action="#{cidadeAction.remover}">
<h:outputtext value="Remover">
</h:outputtext></h:commandlink>
</rich:column>
</rich:datatable>

</h:form>

</ui:define>
</ui:composition>


E para completar vamos colocar um link para nossa página no menu.
Abra o arquivo menu.xhtml e acrescente um link para a nossa página.
<rich:toolbargroup>
<h:outputtext value="#{projectName}:">
<s:link id="menuHomeId" view="/home.xhtml" value="Home" propagation="none">
<s:link view="/cidade.xhtml" value="Cidade">
</s:link></s:link></h:outputtext></rich:toolbargroup>

5 – Testando
Vamos ver como reiniciar a aplicação sem precisar reiniciar todo o servidor.
Servers -> Jboss 5.1 -> Clean -> OK
Pronto a aplicação vai ser reiniciada.
Aguarde alguns segundos.
Abra o browser e acese:
http://localhost:8080/locar/
Clique no link Cidade no menu.
Pronto o primeiro CRUD com o Seam.</f:face></rich:column></rich:datatable></rich:datatable></h:commandbutton></h:inputhidden></cidade></cidade>