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

domingo, 29 de setembro de 2013

A camada de visão - o managed bean do JSF

Este post faz parte de uma série sobre Spring, JPA e JSF. Caso algum assunto abordado aqui não esteja claro, consulte este link: Spring + JPA.

Finalizando essa série de posts sobre Spring, JPA e JSF, vou mostrar finalmente como juntar todas as camadas e executar uma pequena aplicação para testar tudo o que foi feito até aqui.

Relembrando que a integração do JSF ocorre sem problemas desde que sejam feitas as alterações no obsoleto arquivo faces-config.xml, como já foi dito aqui: A camada de visão - Business Delegate.

Antes de executar o exemplo, é interessante deixar o arquivo persistence.xml configurado para apagar e criar as entidades, pois assim o teste pode ser refeito quantas vezes forem necessárias.

Vamos usar uma classe Pessoa,  como foi mostrado aqui: Criando entidades de bancos de dados e uma classe Autor conforme o código a seguir:

package entidades;

import java.io.Serializable;
import javax.persistence.Entity;

@Entity
public class Autor extends Pessoa implements Serializable {

    public Autor() {
    }
}

É apenas uma herança direta, já que a classe Pessoa é abstrata e não pode ser instanciada. Em seguida criamos um pacote chamado controle e dentro dele uma classe Controlador.java conforme o código abaixo:

package controle;

import delegate.FacadeBD;
import entidades.Entidade;
import entidades.Autor;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;

@ManagedBean(name = "controlador")
@ViewScoped
public class Controlador implements Serializable {

    @ManagedProperty(value = "#{facadeBD}")
    private FacadeBD facadeBD;

    public Controlador() {
    }

    public String listaGravada() {
        String retorno = "";
        List<Autor> la = facadeBD.listar(Autor.class);
        retorno += "\n\nLista gravada:\n\n";
        if (la != null) {
            for (Autor autor : la) {
                retorno += "("+autor.getId()+") "+autor.getNome() + "\n";
            }
        }
        return retorno;
    }

    public String getResultado() {
        String retorno = "";
        Autor autor1 = new Autor();
        autor1.setNome("Stephen King");
        Autor autor2 = new Autor();
        autor2.setNome("Dan Brown");
        List<Entidade> listaAutores = new ArrayList<Entidade>();
        listaAutores.add(autor1);
        listaAutores.add(autor2);
        retorno += "\nInserindo dois autores\n";
        facadeBD.salvarLista(listaAutores);
        retorno += listaGravada();
        autor1.setFlagRemover(Boolean.TRUE);
        facadeBD.salvar(autor1);
        retorno += "\nExcluindo ("+autor1.getId()+") "+autor1.getNome()+"\n";
        retorno += listaGravada();
        Autor autor3 = new Autor();
        autor3.setNome("ray bradbury");
        listaAutores.add(autor3);
        retorno += "\nInserindo novo autor "+autor3.getNome()+"\n";
        facadeBD.salvarLista(listaAutores);
        retorno += listaGravada();
        retorno += "\nAlterando "+autor3.getNome()+"\n";
        autor3.setNome("Ray Bradbury");
        facadeBD.salvarLista(listaAutores);
        retorno += listaGravada();
        return retorno;
    }

    public FacadeBD getFacadeBD() {
        return facadeBD;
    }

    public void setFacadeBD(FacadeBD facadeBD) {
        this.facadeBD = facadeBD;
    }
}

Esta classe possui um atributo facadeBD, injetado pelo JSF, ou seja, é uma instância da classe FacadeBD. Podemos verificar na linha 13 que essa classe é colocada no contexto do JSF com o nome "controlador" (em minúsculas), e é como será referenciada logo a seguir, no página que será construída. Temos ainda um método listaGravada para recuperar o conteúdo do banco de dados correspondente à tabela pessoas. Podemos observar, na linha 25, o uso do método listar.

Finalmente, um método acessor getResultado na linha 35. Apesar de não termos um atributo resultado, verificamos aqui que o JSF só precisa do método acessor, e não do atributo, como já era esperado. Esse método faz várias chamadas aos métodos DAO por meio de facadeBD. É importante ressaltar que não há preocupação com conexões, transações, etc.. Vemos também que para excluir um registro do banco de dados, mudamos o atributo flagRemover para true e salvamos. No final do processamento, temos uma String com o histórico das operações, que vai ser acessada na página a seguir:

<?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">
    <h:head>
        <title>Livraria</title>
    </h:head>
    <h:body>
        <h:inputTextarea cols="100" rows="50" value="#{controlador.resultado}" />
    </h:body>
</html>

Na linha 9, temos a referência ao "atributo" resultado, acessado por meio do método getResultado do managed bean controlador. Ao executar essa aplicação, há um redirecionamento para a página de autenticação, e em seguida, ocorre o processamento nas camadas e o histórico de operações é exeibido no inputTextArea:

Inserindo dois autores


Lista gravada:

(1) Stephen King
(2) Dan Brown

Excluindo (1) Stephen King


Lista gravada:

(2) Dan Brown

Inserindo novo autor ray bradbury


Lista gravada:

(2) Dan Brown
(3) ray bradbury

Alterando ray bradbury


Lista gravada:

(2) Dan Brown
(3) Ray Bradbury

Outra observação importante é que também não há uma preocupação com as classes que vão ser gravadas. Pode ser uma lista com apenas um tipo de classe (autores) ou com mais de um tipo (autores mesclados com publicações, por exemplo). A única restrição é que as classes devem ser subclasses de Entidade.

Ainda, se observarmos as chamadas que foram feitas ao método salvarLista, veremos que em nenhum momento removemos da lista listaAutores o autor que foi excluído do banco. A classe GenericDAO já prevê tudo isso, justamente para que a camada de visão fique ainda mais desacoplada da camada de serviços, deixando para o desenvolvedor apenas a preocupação com o fluxo da aplicação e a disposição dos dados nas páginas.

E assim termina a série de posts sobre uso de JPA, Spring, JSF, MVC. Temos um projeto básico completo que será usado na próxima série de posts, ode serão abordados os relacionamentos entre entidades e como utilizar o Primefaces para construção de uma aplicação completa.

quinta-feira, 26 de setembro de 2013

A camada de visão - Business Delegate

Este post faz parte de uma série sobre Spring, JPA e JSF. Caso algum assunto abordado aqui não esteja claro, consulte este link: Spring + JPA.

Quando utilizamos Business Delegate (BD), temos como principal objetivo reduzir o acoplamento entre a camada de visão propriamente dita e os serviços. Neste exemplo que venho construindo desde alguns posts anteriores essa abordagem talvez não seja necessária, mas a aplicação já ficará preparada para evoluir, se for necessário.

Vamos criar um pacote chamado delegate e duas classes semelhantes às classes da camada de controle (ou serviços):

package delegate;

import entidades.Entidade;
import java.io.Serializable;
import java.util.List;
import service.AbstractService;

public abstract class AbstractBD<T extends Entidade> {

    protected AbstractService<T> service;

    public abstract void setService(AbstractService<T> service);

    public void salvar(T entidade) {
        service.salvar(entidade);
    }

    public void salvarLista(List<T> lista) {
        service.salvarLista(lista);
    }

    public T carregar(Class classe, Serializable codigo) {
        return service.carregar(classe, codigo);
    }

    public List<T> listar(Class classe) {
        return service.listar(classe);
    }

    public List<T> consultaPersonalizada(String consulta) {
        return service.consultaPersonalizada(consulta);
    }

    public List<T> consultaNativa(String consulta) {
        return service.consultaNativa(consulta);
    }

}

package delegate;

import java.io.Serializable;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import service.AbstractService;

@Component(value = "bd")
public class GenericBD extends AbstractBD implements Serializable {

    @Override
    @Value("#{genericService}")
    public void setService(AbstractService service) {
        this.service = service;
    }
}

Não temos muito o que comentar aqui. Como aconteceu com as classes "Service", temos os métodos que serão utilizados, injeção de dependências dos componentes do Spring que serão necessários, e só. O único ponto relevante é o baixo acoplamento. Mudanças podem ocorrer nos serviços sem que a camada de visão sofra qualquer alteração, e vice-versa. Além do fato de que a camada de serviços trabalha com transações e a camada de visão não percebe isso. Esse é mais um motivo para ressaltar a importância da programação voltada a interfaces (ou voltada a classes abstratas).

Com essa tecnologia, podemos ter mais de um tipo de serviço (serviços para bancos de dados e serviços para arquivos xml, por exemplo) controlados por vários business delegates. Isso permitiria mudar a maneira como se faz a persistência dos dados sem modificar nada na camada de visão. Mas é preciso ainda mais um nível de desacoplamento que pode ser obtido implementando um facade (fachada), que será responsável por reduzir a complexidade dos BDs e fornecer uma classe com métodos que a camada de visão pode entender com maior facilidade. Por exemplo, com base em uma escolha do usuário ou por meio de um arquivo de configuração, o facade poderia decidir se o método "salvar" deve instanciar a gravação em arquivos xml ou em bancos de dados, mas a visão continuaria pedindo apenas para "salvar" os dados, sem saber como isto seria feito.

Vou mostrar a seguir o meu modelo de classe facade, que já é utilizado em vários projetos. No mesmo pacote delegate, criamos a classe facadeBD:

package delegate;

import entidades.Entidade;
import java.io.Serializable;
import java.util.List;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import org.primefaces.context.RequestContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component("facadeBD")
@ManagedBean(name = "facadeBD")
@ViewScoped
public class FacadeBD implements Serializable {

    public static final short SALVAR = 1;
    public static final short SALVARLISTA = 2;
    public static final short LISTAR = 3;
    public static final short CARREGAR = 4;
    public static final short CONSULTAPERSONALIZADA = 5;
    public static final short CONSULTANATIVA = 6;
    private Class classe;
    private Serializable chavePrimaria;
    private Entidade objetoRetorno;
    private Entidade entidade;
    private List listaRetorno;
    private String consulta;
    private List listaEntidades;
    @Autowired
    private GenericBD bd;

    public FacadeBD() {
    }

    public void salvar(Entidade entidade) {
        this.entidade = entidade;
        executar(SALVAR);
    }

    public void salvarLista(List listaEntidades) {
        this.listaEntidades = listaEntidades;
        executar(SALVARLISTA);
    }

    public List listar(Class classe) {
        this.classe = classe;
        executar(LISTAR);
        return listaRetorno;
    }

    public Entidade carregar(Class classe, Serializable chavePrimaria) {
        this.classe = classe;
        this.chavePrimaria = chavePrimaria;
        executar(CARREGAR);
        return objetoRetorno;
    }

    public List consultaPersonalizada(String consulta) {
        this.consulta = consulta;
        executar(CONSULTAPERSONALIZADA);
        return listaRetorno;
    }

    public List consultaNativa(String consulta) {
        this.consulta = consulta;
        executar(CONSULTANATIVA);
        return listaRetorno;
    }

    public Boolean mensagemNova(FacesMessage mensagem) {
        Boolean adicionar = true;
        List<FacesMessage> lm = FacesContext.getCurrentInstance().getMessageList();
        if (lm != null && lm.size() > 0) {
            for (FacesMessage fm : lm) {
                if (fm.getDetail().trim().equals(mensagem.getDetail().trim())) {
                    adicionar = false;
                }
            }
        }
        return adicionar;
    }

    public void executar(short metodo) {
        FacesMessage mens;
        String mensagem = "";
        try {
            if (metodo == SALVAR) {
                bd.salvar(entidade);
            }
            if (metodo == SALVARLISTA) {
                bd.salvarLista(listaEntidades);
            }
            if (metodo == LISTAR) {
                listaRetorno = bd.listar(classe);
            }
            if (metodo == CARREGAR) {
                objetoRetorno = bd.carregar(classe, chavePrimaria);
            }
            if (metodo == CONSULTAPERSONALIZADA) {
                listaRetorno = bd.consultaPersonalizada(consulta);
            }
            if (metodo == CONSULTANATIVA) {
                listaRetorno = bd.consultaNativa(consulta);
            }
        } catch (Exception e) {
            System.out.println("===== erro ====");
            if (classe != null) {
                System.out.println("Classe: " + classe.getSimpleName());
            } else {
                System.out.println("Classe: null");
            }
            System.out.println("Método: " + metodo);
            System.out.println("Consulta: " + consulta);
            System.out.println("Chave: " + chavePrimaria);
            e.printStackTrace();
            System.out.println("===============");
            mens = new FacesMessage(FacesMessage.SEVERITY_FATAL, "Erro!", e.getMessage());
            if (mensagemNova(mens)) {
                FacesContext.getCurrentInstance().addMessage(null, mens);
            }
            RequestContext.getCurrentInstance().update("growl");
        } finally {
            if (!mensagem.isEmpty()) {
                mens = new FacesMessage(FacesMessage.SEVERITY_INFO, "Sucesso", mensagem);
                if (mensagemNova(mens)) {
                    FacesContext.getCurrentInstance().addMessage(null, mens);
                }
                RequestContext.getCurrentInstance().update("growl");
            }
        }
    }

    public GenericBD getBd() {
        return bd;
    }

    public void setBd(GenericBD bd) {
        this.bd = bd;
    }

}

  • Como podemos ver na anotação da linha 15, facadeBD é um managed bean, e poderá ser injetado por meio do JSF em outro managed bean com o mesmo escopo (@ViewScoped).
  • facadeBD também é um componente no contexto do Spring, e pode receber uma injeção do GenericBD (linhas 32 e 33). Aqui cabe uma observação: para integrar o Spring com o JSF permitindo injeção de dependências entre os contextos, utilizamos uma pequena configuração no arquivo faces-config.xml:

<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="2.0"
    xmlns="http://java.sun.com/xml/ns/javaee"
    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_2_0.xsd">
    <application>
        <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
    </application>
</faces-config>

  • No trecho compreendido entre as linhas 38 e 71, temos a implementação dos métodos que serão utilizados pela camada de visão. Para salvar uma entidade que foi instanciada no objeto autor, por exemplo, a visão só saberá invocar "salvar(autor)". Todo o processamento de transações, conexão com o banco de dados, decisão sobre inserir ou atualizar, e outros detalhes, serão processados em suas respectivas camadas, de maneira transparente.
  • O método executar que inicia na linha 86, desvia para o business delegate bd que foi injetado pelo Spring, todo o restante do processamento.
O restante do código resume-se aos gets e sets e processamento de mensagens do JSF.

No próximo post, a criação de um controlador do JSF que fará a integração entre as páginas e o facadeBD.

quarta-feira, 25 de setembro de 2013

Transações e a camada de controle

Este post faz parte de uma série sobre Spring, JPA e JSF. Caso algum assunto abordado aqui não esteja claro, consulte este link: Spring + JPA.

Como foi mostrado nos dois posts anteriores, Temos um pacote entidades onde serão descritas as tabelas do banco de dados e um pacote dao, onde estão as classes que fazem o acesso aos dados do banco, por meio de JPA+Hibernate. Esses dois pacotes formam uma camada que frequentemente é chamada de camada de Modelo (o M do MVC).

Manter essa camada separada das demais facilita a mudança de uma tecnologia para outra. Por exemplo, suponhamos que o desenvolvedor precisar mudar de Hibernate para EclipseLink. Somente essa camada precisará ser alterada, além de algumas bibliotecas e configurações do Spring, sem afetar o restante do sistema.

Da mesma maneira, uma camada de Controle (o C do MVC) onde as transações são configuradas, deve ser implementada separadamente das outras camadas, para que se possa jogar para ela toda essa responsabilidade. A camada de controle muitas vezes é citada como camada de serviço, por isso as denominações "service" que acrescentaremos a seguir.

Vamos ao código de uma classe abstrata que vai direcionar como os métodos DAO da camada de modelo devem ser controlados:

package service;

import dao.InterfaceDAO;
import java.io.Serializable;
import java.util.List;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
public abstract class AbstractService<T> {

    protected InterfaceDAO<T> dao;

    public void setDao(InterfaceDAO<T> dao) {
        this.dao = dao;
    }

    public void salvar(T entity) {
        dao.salvar(entity);
    }

    public void salvarLista(List<T> lista) {
        dao.salvarLista(lista);
    }

    @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
    public T carregar(Class classe, Serializable chave) {
        return dao.carregar(classe, chave);
    }

    @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
    public List<T> listar(Class classe) {
        return dao.listar(classe);
    }


    @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
    public List<T> consultaPersonalizada(String consulta) {
        return dao.consultaPersonalizada(consulta);
    }

    @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
    public List<T> consultaNativa(String consulta) {
        return dao.consultaNativa(consulta);
    }
}

Foi criado um pacote chamado service e uma classe chamada AbstractService. Nela está centralizado todo o controle das transações que ocorrerão. É óbvio que isso só funciona se todas as operações relativas ao CRUD das entidades passar por essa camada.

Atenção para as linhas 9 e 26. Na linha 9 determinamos que todos os métodos descritos na classe exigirão uma transação, a menos que outra anotação interna determine outra configuração. Já na linha 26, estamos dizendo que o método carregar, em particular, suporta a utilização de uma transação já em andamento, mas não precisa de uma transação para ser utilizado. Não vou entrar em detalhes sobre esse assunto, mas a documentação do Spring explica muito bem essas anotações.

As outras linhas com anotações semelhantes servem para o mesmo propósito. Dessa maneira, nenhuma outra parte do sistema deve abordar controle de transações. Essa classe é a única responsável por essa tarefa, e deve interceptar todas as operações de CRUD.

Em seguida, no mesmo pacote service, criamos uma classe GenericService (agora concreta) para disponibilizar esse serviço, já que a classe abstrata não pode ser instanciada:

package service;

import dao.InterfaceDAO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service("genericService")
public class GenericService extends AbstractService {

    @Override
    @Value("#{genericDAO}")
    public void setDao(InterfaceDAO dao) {
        this.dao = dao;
    }

}

Esta classe é bastante simples, e tem poucas coisas relevantes para se comentar. Ela utiliza uma injeção de dependência na linha 11, trazendo ao atributo chamado de dao (que foi herdado de AbstractService - linha 12) o objeto genericDAO (identificador reconhecido pelo Spring - confira a linha 11 da classe no post anterior). Podemos notar também que há uma anotação na linha 7, nomeando essa classe no contexto (do mesmo modo que foi feito na classe GenericDAO) para que o Spring possa injetar uma instância dessa classe em outra camada, como veremos no próximo post.

Essa construção possibilita que a camada seguinte dependa apenas da classe GenericService. Qualquer mudança no contexto transacional será feita na classe abstrata, sem atingir o restante das classes da aplicação!

Uma observação a respeito da injeção de dependências: se o atributo dao e o identificador genericDAO tiverem uma correspondência única, ou seja, se houver apenas um objeto no contexto do Spring do tipo AbstractDAO, podemos utilizar uma abordagem com anotação @Autowired, e basta definir um atributo com os mesmos nome e tipo da classe desejada, anotá-lo com @Autowired e declarar seus get e set. Essas variações dependem do objetivo da classe - uma classe que vai manipular vários componentes do contexto do Spring que tenham o mesmo tipo mas nomes de classe diferentes, pode ser implementada para trabalhar strings, obter em tempo de execução o nome da classe e instanciá-la. Nesse caso, utiliza-se @value referenciando uma EL com o nome da classe, como foi feito aqui. Mas se os objetos forem únicos, pode-se utilizar apenas a abordagem com @Autowired. Já foi utilizada uma abordagem dessas quando foi implementada a classe GenericDAO, com o atributo jpaTemplate (Como criar uma camada DAO).

No próximo post, a camada de Visão.

segunda-feira, 23 de setembro de 2013

Criando entidades de bancos de dados

Este post faz parte de uma série sobre Spring, JPA e JSF. Caso algum assunto abordado aqui não esteja claro, consulte este link: Spring + JPA.

Uma boa alternativa para quem está desenvolvendo um projeto e precisa agilizar os testes durante a modelagem dos dados e a criação da camada DAO é deixar a unidade de persistência e o Hibernate se encarregarem da criação das tabelas das entidades no banco de dados.

Para que isso ocorra, é necessária uma propriedade no arquivo persistence.xml, mais precisamente na linha 13, mostrada abaixo:


  
    org.hibernate.ejb.HibernatePersistence
    java:/fonteDeDados
    entidades.Pessoa
    false
    
      
      
      
      
      
      
    
  


Essa propriedade indica ao Hibernate para apagar todas as tabelas e recriá-las, a cada vez que a aplicação for executada. Depois que todos os testes terminarem, a propriedade pode ser deixada com o valor update, que atualiza ou cria automaticamente qualquer atributo novo ou tabela que for acrescentada ao projeto.


  
    org.hibernate.ejb.HibernatePersistence
    java:/fonteDeDados
    entidades.Pessoa
    false
    
      
      
      
      
      
      
    
  


Caso não haja mais necessidade de alterar a estrutura do banco de dados, a propriedade pode ser simplesmente retirada do arquivo.

Uma pequena observação: se a propriedade estiver configurada para create-drop e ocorrer erro no servidor de aplicações, é preciso remover manualmente as tabelas do banco de dados.

Para demonstrar estas configurações, vou criar uma série de posts com a construção das camadas MVC que serão usadas em um projeto simples para uma livraria.

O primeiro passo é preparar uma classe abstrata que servirá de modelo para todas as entidades que forem criadas no projeto. O objetivo é que todas as entidades atendam os requisitos abaixo:

  1. um método chamado getId() que retorne o valor de sua chave primária;
  2. um atributo temporário chamado flagRemover, que sinalizará ao DAO que o objeto que chegou até ele deve ser removido do banco de dados;

A importância desta classe será demonstrada quando for implementado o CRUD do projeto. Vamos ao código:

package entidades;

import java.io.Serializable;
import javax.persistence.Transient;

public abstract class Entidade implements Serializable {

    @Transient
    public boolean flagRemover;

    public abstract Serializable getId();

    public Boolean getFlagRemover() {
        return flagRemover;
    }

    public void setFlagRemover(Boolean flagRemover) {
        this.flagRemover = flagRemover;
    }
}

Numa rápida análise, o pacote entidades conterá essa classe abstrata que tem  um atributo flagRemover, com seus métodos de acesso (get e set) e um método público abstrato que simula o método get de um atributo chamado id. Esse método possibilita generalizar a obtenção da chave primária de qualquer classe de entidade que herde essa classe, já que ele será implementado na subclasse, e poderá retornar justamente o atributo da chave primária da subclasse. Observamos também que o atributo flagRemover não será escrito no banco de dados, pois está anotado com @Transient. Ele será utilizado apenas para marcar uma entidade que deve ser removida, antes de enviá-la ao DAO.

É bastante clara a vantagem de usar uma classe abstrata em vez de uma interface, pois podemos deixar alguns métodos prontos já para a subclasse, o que não poderia ser feito com o uso de uma interface.

Um rápido exemplo:

package entidades;

import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public abstract class Pessoa extends Entidade implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer reg;
    @Column(length=50)
    private String nome;
    @Column(length=50)
    private String sobrenome;

    public Integer getReg() {
        return reg;
    }

    public void setReg(Integer reg) {
        this.reg = reg;
    }

    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;
    }

    @Override
    public Serializable getId() {
        return reg;
    }

}

A classe Pessoa (que também é uma classe abstrata!) herda a estrutura da classe Entidade (linha 11), ou seja, automaticamente possui um atributo flagRemover com get e set. Essa classe possui sua própria chave primária reg, anotada devidamente com @Id, e que não tem, inicialmente, uma ligação com o método getId.  No final do código, podemos ver a implementação (que é obrigatória) do método getId, que está retornando o atributo reg (chave primária da classe Pessoa). Portanto, outras classes poderão acessar o valor da chave primária da classe Pessoa, utilizando o método getId(), sem saber que o atributo original é chamado de reg, ou seja, deixando o atributo reg encapsulado.

No próximo post, a construção das classes DAO.

segunda-feira, 19 de abril de 2010

Criar um bean gerenciado que retorne uma lista com os dados

Nosso próximo passo é um Bean gerenciado que controle as requisições. É altamente recomendado que o projeto siga o padrão MVC - todas as requisições das páginas devem ser enviadas para este bean. Começamos com

Novo->Outro->JavaServer Faces->Bean gerenciado JSF

As configurações podem seguir o modelo a seguir, lembrando de colocar o arquivo no pacote controle, para manter o padrão:


As observações mais relevantes são a respeito do nome da classe e do nome que será usado nas páginas (ControladorBean e controlador, respectivamente). Essa diferenciação é apenas para facilitar a identificação.
Este Bean deve ter um método que retorne uma lista para montarmos o DataTable. Há várias maneiras de se fazer isto - vamos seguir este roteiro:

  1. instanciar a classe DAO;
  2. utilizar o método crud da classe DAO para recuperar os dados da tabela Person;
  3. criar uma instância de ListDataModel a partir dos dados recuperados.
O código final do Bean gerenciado ficará assim:
  
01 package controle; 02 03 import java.util.List; 04 import javax.faces.model.ListDataModel; 05 06 public class ControladorBean { 07 08 private ListDataModel lista; 09 private DAO dao; 10 11 public ControladorBean() { 12 dao = new DAO(); 13 } 14 15 public ListDataModel getLista() { 16 List relacao = dao.crud("from Person order by name"); 17 lista = new ListDataModel(relacao); 18 return lista; 19 } 20 21 }
O método getLista será referenciado na página onde será implementado o componente DataTable.

Voltar para DataTables básico