Repositório : http://repo.futurepages.org/svn/2/apps/alunoonline/tags/meu_primeiro_projeto_com_futurepages
Usuário : user
Senha : fpguser
* Se você tiver dúvidas de como fazer um projeto usando os repositórios do SVN, pode usar esse tutorial como ajuda: [[quickstart:criando_projeto_a_partir_do_svn]]
===== Passo 1 - Modificando a Primeira Tela =====
== Parâmetros da Aplicação ==
Crie em SRC o arquivo **conf/app-params.xml** com o seguinte conteúdo. A aplicação possui parâmetros padrões, neste arquivo indicaremos algum parâmetro de configuração. Mais a frente veremos alguns destes parâmetros.
//Mais adiante iremos alterar os valores de **SCHEMA_GENERATION_TYPE** para **export** e **INSTALL_MODE** para **on**, pois vamos criar as tabelas no banco (esta ação destruirá a tabela criada no tutorial anterior; e lembre-se que usaremos o banco chamado **alunoonlinebd**) e instalar os exemplos.//
== init/Index.jsp ==
* Crie dentro da pasta **WEB**, uma pasta init e crie um arquivo chamado Index.jsp (note que este arquivo é **semelhante** ao tutorial anterior).
* Ele deverá ter o seguinte conteúdo:
<%@taglib uri="futurepagesApp" prefix="fpg"%>
//À medida que as funcionalidades da aplicação forem tornando-se disponíveis, iremos alterar os valores **javascript:void(0)**, em **href** de cada link, para os valores apropriados.//
O arquivo /index.jsp deve permanecer igual ao do tutorial anterior. Para mais informações, consulte-o.
**OBS**: Não esqueça de copiar o arquivo **taglib.tld** da pasta ///build/web/WEB-INF// para a pasta ///web/WEB-INF//.
===== Passo 2 - Acrescentando o Bean Turma ao Modelo =====
== Crie os Beans ==
* Vamos agora criar o bean Turma, que ficará dentro do pacote **modules.escola.bean**.
O arquivo **Turma.java** ficara assim:
package modules.escola.beans;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="escola_turma")
public class Turma implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(length = 10, unique = true, nullable = false)
private String codigo;
@Column(nullable = false)
private String nome;
public Turma() {
}
public Turma(String codigo, String nome) {
setCodigo(codigo);
setNome(nome);
}
public void setCodigo(String codigo) {
this.codigo = codigo;
}
public void setId(int id) {
this.id = id;
}
public void setNome(String nome) {
this.nome = nome;
}
public String getCodigo() {
return codigo;
}
public int getId() {
return id;
}
public String getNome() {
return nome;
}
}
**Observações** \\
* **@Entity**, diz que essa será uma classe mapeada como entidade numa base de dados.\\
* Usamos **@Table(name="escola_turma")** para definir o nome da tabela como sendo //escola_turma//.\\
* **@Id**, para identificar o atributo **id** como um identificador da classe/tabela.\\
* **@GeneratedValue(strategy=GenerationType.IDENTITY)**, determina que o campo associado ao atributo será auto_increment.\\
* **@Column(length=10, unique=true, nullable=false)**, diz que o atributo será associado à coluna “matricula”, será um índice UNIQUE, NOT NULLe será VARCHAR(10) pois o atributo é do tipo String e length=10.
* Agora vamos criar o bean Aluno, que ficará no mesmo pacote de Turma.
O arquivo **Aluno.java** ficará assim:
package modules.escola.beans;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name = "escola_aluno")
public class Aluno implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(length = 10, unique = true, nullable = false)
private String matricula;
@Column(nullable = false)
private String nomeCompleto;
@ManyToOne
private Turma turma;
public Aluno() {
}
public Aluno(String matricula, String nomeCompleto) {
this.matricula = matricula;
this.nomeCompleto = nomeCompleto;
}
public Aluno(String matricula, String nomeCompleto, Turma turma) {
this.matricula = matricula;
this.nomeCompleto = nomeCompleto;
this.turma = turma;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getMatricula() {
return matricula;
}
public void setMatricula(String matricula) {
this.matricula = matricula;
}
public String getNomeCompleto() {
return nomeCompleto;
}
public void setNomeCompleto(String nomeCompleto) {
this.nomeCompleto = nomeCompleto;
}
public Turma getTurma() {
return turma;
}
public void setTurma(Turma turma) {
this.turma = turma;
}
}
**Observação**
* A classe **Aluno** possui uma referência para a classe **Turma**.
* O atributo //turma// é anotado com **@ManyToOne**, que diz que há uma relação **muitos para um**.
== Gere a estrutura (esquema) do Banco de Dados ==
Aqui iremos gerar as tabelas no banco de acordo com o mapeamento que fizemos nos nossos beans. Para isso, abra o arquivo **app-params.xml** e altere o //value// de **SCHEMA_GENERATION_TYPE** para **export**.
O arquivo deve ficar assim:
Salve o arquivo e execute a aplicação.
**OBS**: Não esqueça de retornar o //value// de **SCHEMA_GENERATION_TYPE** para **none** após a execução.
== Inserções Iniciais (Install) ==
Vamos instalar algumas instâncias no banco de dados. Para isso vamos criar as classes de instalação.
Crie o pacote **module.install.res**.
* Crie **TurmaExemplos.java** dentro de **module.install.res**, como é mostrado logo abaixo:
package modules.escola.install.res;
import modules.escola.beans.Turma;
import org.futurepages.core.persistence.Dao;
/*
* Instala turmas para testes de exemplos
*/
public class TurmaExemplos {
public void execute() {
Dao.save(new Turma("T01", "Cálculo I"));
Dao.save(new Turma("T02", "Introdução à computação"));
Dao.save(new Turma("T03", "Lógica"));
Dao.save(new Turma("T04", "Estatística"));
Dao.save(new Turma("T05", "Programação I"));
Dao.save(new Turma("T06", "Programação II"));
Dao.save(new Turma("T07", "Cálculo II"));
Dao.save(new Turma("T08", "Estrutura de dados"));
Dao.save(new Turma("T09", "Arquitetura de computadores"));
Dao.save(new Turma("T10", "Redes de computadores I"));
Dao.save(new Turma("T011", "Sistemas Operacionais I"));
Dao.save(new Turma("T012", "Redes de computadores II"));
Dao.save(new Turma("T013", "Sistemas Operacionais II"));
}
}
* Crie também, **AlunoExemplos.java** dentro de **module.install.res**:
package modules.escola.install.res;
import java.util.List;
import modules.escola.beans.Turma;
import java.util.Random;
import modules.escola.beans.Aluno;
import org.futurepages.core.persistence.Dao;
/*
* Instala alunos para testes de exemplos
*/
public class AlunoExemplos {
private List listaTurma;
private Random rand = new Random(System.currentTimeMillis());
public AlunoExemplos() {
}
public AlunoExemplos(List listaTurma) {
this.listaTurma = listaTurma;
}
private int modulo(int n) {
return ((n < 0) ? (-n) : n);
}
/*
* Retorna uma refência, de forma dinâmica, a uma turma
* dentro da lista de turmas recuperadas do banco.
*/
private Turma obtemTurmaRandomica() {
return listaTurma.get(modulo(rand.nextInt()) % listaTurma.size());
}
/*
* Instala os alunos e os cadastra em turmas
* de forma randomicas.
*/
public void execute() {
Dao.save(new Aluno("03N1047000", "Maria da Silva", obtemTurmaRandomica()));
Dao.save(new Aluno("02N1047451", "João Fulano Cavalcante Soares", obtemTurmaRandomica()));
Dao.save(new Aluno("99S5447050", "Antônio Feliciano Gomes", obtemTurmaRandomica()));
Dao.save(new Aluno("99S5000001", "Sicrano da Silva e Silva", obtemTurmaRandomica()));
Dao.save(new Aluno("99S8348349", "Maria Antonieta da Costa", obtemTurmaRandomica()));
Dao.save(new Aluno("93E9394322", "José Pompeu Exemplus da Silva", obtemTurmaRandomica()));
}
}
* Neste ponto, vá até o arquivo **AlunosInstaller.java**, criado na Parte 1 deste Projeto, e comente o conteúdo do método execute, já que os alunos criados por esta classe não possuem o atributo turma. Você também pode simplesmente excluir este arquivo.
* Por fim, crie o arquivo **EscolaInstaller.java** em **module.install**.
package modules.escola.install;
import java.util.List;
import modules.escola.beans.Turma;
import modules.escola.install.res.AlunoExemplos;
import modules.escola.install.res.TurmaExemplos;
import org.futurepages.core.install.Installer;
import org.futurepages.core.persistence.Dao;
/*
* Instala as turmas e depois os alunos.
*/
public class EscolaInstaller extends Installer{
@Override
public void execute() throws Exception {
List listaTurma;
new TurmaExemplos().execute();
listaTurma = Dao.list(Turma.class);
new AlunoExemplos(listaTurma).execute();
}
}
* Altere o //value// de **INSTALL_MODE** para **on**:
Execute a aplicação e depois retorne o //value// de **INSTALL_MODE** para **off**.
===== Passo 3 - Alterando o Controle =====
== TurmaAction ==
Dentro do pacote **modules.escola.actions**, criaremos a classe **TurmaActions** que herdará do pacote **org.futurepages.actions.CrudActions**.
O arquivo TurmaActions.java fica assim:
package modules.escola.actions;
import java.util.List;
import modules.escola.beans.Turma;
import modules.escola.validators.TurmaValidator;
import org.futurepages.actions.CrudActions;
import org.futurepages.core.persistence.Dao;
public class TurmaActions extends CrudActions {
private Turma turma;
@Override
protected void listDependencies() {
if (hasError()) {
output.setValue("turma", turma);
}
}
public String create() {
validate(TurmaValidator.class).create(turma);
Dao.saveTransaction(turma);
return success("Turma criada com sucesso.");
}
@Override
protected void listObjects() {
List turmas = Dao.list(Turma.class, "", "nome asc");
output.setValue("turmas", turmas);
}
}
* Observe que **TurmaActions** é semelhante à classe **AlunoActions** mostrada no tutorial anterior.
== AlunoActions ==
No mesmo pacote onde foi colocada a classe **TurmaActions**, será colocada **AlunoActions**:
package modules.escola.actions;
import java.util.List;
import modules.escola.beans.Aluno;
import modules.escola.beans.Turma;
import modules.escola.validators.AlunoValidator;
import org.futurepages.actions.CrudActions;
import org.futurepages.core.persistence.Dao;
import org.futurepages.util.Is;
public class AlunoActions extends CrudActions {
private Aluno aluno;
/*
* Em output.setValue(...), nesta inner action, é passado
* a lista de turmas ao componente select.
* Desta lista, uma turma será escolhida para cadastrar
* um novo aluno.
*/
@Override
protected void listDependencies() {
if(hasError()) {
output.setValue("aluno", aluno);
}
// Recupera as turmas e adiciona-as à tela de criação
// para que possa ser selecionada no cadastro de aluno.
List turmas = Dao.list(Turma.class, "", "codigo asc");
output.setValue("turmas", turmas);
}
/*
* Em create, além de recuperar o aluno, recupera o id
* da turma que o aluno faz referência (input.getValue(...)).
* Em seguida é recuperado do banco a turma que possui tal id
* (turma = Dao.get(...)) e esta turma é atribuída ao aluno.
*
* OBS: O uso de PIFilter possibilitou a não utilização das três
* linhas comentadas logo abaixo. Não há necessidade do programador
* injetar uma turma em aluno. Ao usar o PIFilter isso passa
* a ser automatizado.
*/
public String create() {
// String sTurma = (String) input.getValue("turma");
// Turma turma = Dao.get(Turma.class, Integer.parseInt(sTurma));
// aluno.setTurma(turma);
validate(AlunoValidator.class).create(aluno);
Dao.saveTransaction(aluno);
return success("Aluno criado com sucesso");
}
/*
* listObjects() é chamado quando TYPE é igual a
* EXPLORE.
* Chama filtra(...) com parâmetro inteiro igual à
* zero, pois não necessita filtrar nenhum aluno por
* turma.
*/
@Override
protected void listObjects() {
filtra(0);
}
/*
* Inner action chamada quando é solicitado a filtragem
* de alunos por turma. Recebe como parâmtro o id da turma
* pelo qual se deseja filtrar os alunos, e faz uma chamada
* a filtra(...) com tal id (turma).
*/
public String explore(int turma) {
filtra(turma);
return SUCCESS;
}
/*
* Filtra os alunos de acontor com a turma (id da turma).
*/
private void filtra(Integer turma) {
String consulta;
// Verifica se turma possui um valor dafault (não filtrar).
if (!Is.selected(turma)) {
consulta = "";
}
// Criando a String para refinar a busca no banco.
else {
consulta = "turma.id = " + turma;
}
// Buscas no banco de alunos e turmas
List alunos = Dao.list(Aluno.class, consulta, "nomeCompleto asc");
List turmas = Dao.list(Turma.class, "", "codigo asc");
output.setValue("alunos", alunos);
output.setValue("turmas", turmas);
// Faz com que select, na tela de visão, mostre
// por padrão o valor contido em turma.
output.setValue("turma", turma);
}
}
**Observações**
* **listDependencies**, //joga// no output a lista de turmas cadastradas. Para que quando for criado um aluno, posse ser escolhido uma turma para ser cadastrada.
* **create**, obtem o //id// da turma atribuída ao aluno, recupera do banco tal turma e passar esta referência ao aluno. Em seguida, o aluno é //avaliado// (validate) e salvo no no banco.
* **listObjects** é chamado quando TYPE é igual a EXPLORE. Chama filtra(...) com parâmetro inteiro igual à zero, pois não necessita filtrar nenhum aluno por turma.
* **explore** é chamado quando é solicitado a filtragem de alunos por turma. Recebe como parâmtro o **id** da turma pelo qual se deseja filtrar os alunos, e faz uma chamada a **filtra** com tal **id** (turmaId).
* **filtra**, filtra os alunos de acordo com a turma (id da turma).
===== Passo 4 - Criando a Visão =====
O projeto agora passa a ter as seguintes telas:
^Tela de Caso de Uso ^Arquivo em "WEB/modules/escola/" |
|Criação de Turma (Nova Turma) |**Turma.create.jsp** |
|Listagem de Turma (Listar Turmas) |**Turma.explore.jsp** |
|Edição de Turma |**Turma.update.jsp** %%*%% |
|Exclusão de Turma |**Turma.delete.jsp** %%*%% |
|Criação de Aluno (Novo Aluno) |**Aluno.create.jsp** |
|Listagem de Aluno (Listar Aluno, com filtro) |**Aluno.explore.jsp** |
|Edição de Aluno |**Aluno.update.jsp** %%*%% |
|Exclusão de Aluno |**Aluno.delete.jsp** %%*%% |
//%%*%% não será apresentado neste tutorial, fica como atividade extra.//
== Criando a Tela de Nova Turma ==
Em **/WEB/modules/escola/**, crie **Turma.create.jsp**, como segue:
<%@taglib uri="futurepagesApp" prefix="fpg"%>
Nova Turma
/Turma.create.fpg" >
Nome:
Codigo:
Da mesma forma como criar um novo Aluno, a tela de criação de uma nova turma possui um formulário de cadastro de turma no qual o usuário especificará o nome e o código da turma enviado-os via POST para o endereço:
* http://nomeDoHost/modules/escola/Turma.create.fpg
Este endereço corresponde ao método (inner action) **create()** da classe **TurmaAction**.
== Criando a tela de listagem de Turmas ==
Em **/WEB/modules/escola/**, crie **Turma.explore.jsp**, como segue:
<%@taglib uri="futurepagesApp" prefix="fpg"%>
* Quando é acessado **Turma.fpg?type=explore**, o método (inner action) **listObjects** da action **TurmaAction**, será acessado.
* A tag **
<%@taglib uri="futurepagesApp" prefix="fpg"%>
Novo Aluno
/Aluno.create.fpg">
Nome:
Matrícula:
* O detalhe aqui é para a tag **
<%@taglib uri="futurepagesApp" prefix="fpg" %>
Vamos às novidades:
* É usando um **form**, pois iremos mandar informação para a aplicação através da tela de listagem:
* O formulário contém uma tag **
package modules.escola;
import modules.escola.actions.AlunoActions;
import modules.escola.actions.TurmaActions;
import modules.escola.beans.Aluno;
import modules.escola.beans.Turma;
import org.futurepages.core.control.AbstractModuleManager;
import org.futurepages.filters.PIFilter;
import org.futurepages.filters.VOFilter;
public class ModuleManager extends AbstractModuleManager {
@Override
public void loadActions() {
//Configuração da Action com o apelido "Aluno"
action("Aluno", AlunoActions.class)
// VOFilter: pega os valores dos campos do formulário da visão e
// casa-os com os atributos da classe Aluno.class, instancia um
// objeto deste tipo e insere os valores dos campos do formulário
// nas respectivas propriedades, o objeto preenchido é atribuido
// ao campo da action com o nome "aluno".
.filter(new VOFilter("aluno", Aluno.class))
// PIFIlter: recupera do banco uma "turma" de acordo com o id
// adquirido no formulário e insere-o em um objeto "aluno".
// Retirando assim, esta tarefa do programador.
.filter(new PIFilter("aluno", "turma", Turma.class))
// se chamar Aluno?type=create, o método execute será chamado, e
// a consequência do método deverá mandar o resultado do output
// (fwIn) para a tela de criação do aluno dentro do módulo
// (com o template montado)
.on(CREATE, fwIn("Aluno.create.page"))
// se ocorrer sucesso na criação do aluno vai para a tela de
// listagem dos alunos cadastrados
.on(SUCCESS, CREATE, fwIn("Aluno.fpg?type=explore"))
// se ocorrer error na criacao do aluno volta para a tela de
// criação do aluno
.on(ERROR, CREATE, fwIn("Aluno.create.page"))
// Aluno?type=explore ocorre o redirecionamento para a tela
// de listagem dos alunos cadastrados no sistema
.on(EXPLORE, fwIn("Aluno.explore.page"))
// Aluno.explore.fpg retorna SUCCESS e redireciona para a
// tela de listagem de alunos cadastrados, filtrados por
// turma.
.on(SUCCESS, EXPLORE, fwIn("Aluno.explore.page"));
// Configuração da Action "Turma"
// TurmaActions recebe um apelido "Turma"
action("Turma", TurmaActions.class)
//VOFilter: pega os valores dos campos do formulário da visão e
// casa-os com os atributos da classe Turma.class, instancia um
// objeto deste tipo e insere os valores dos campos do formulário
// nas respectivas propriedades, o objeto preenchido é atribuido
// ao campo da action com o nome "turma".
.filter(new VOFilter("turma", Turma.class))
// se chamar Turma?type=create, o método execute será chamado, e
// a consequência do método deverá mandar o resultado do output
// (fwIn) para a tela de criação do aluno dentro do módulo
// (com o template montado)
.on(CREATE, fwIn("Turma.create.page"))
// se ocorrer sucesso na criação de turma vai para a tela de
// listagem das turmas cadastrados
.on(SUCCESS, CREATE, fwIn("Turma.fpg?type=explore"))
// se ocorrer error na criacao da turma volta para a tela de
// criação de turma
.on(ERROR, CREATE, fwIn("Turma.create.page"))
// Turma?type=explore ocorre o redirecionamento para a tela
// de listagem das turmas cadastrados no sistema
.on(EXPLORE, fwIn("Turma.explore.page"));
}
}
* Note que adicionada a consequência **//.on(SUCCESS, EXPLORE, fwIn("Aluno.explore.page"))//** na action Aluno.
* Note também, que foi adicionado uma action "Turma" ao ModuleManager con suas respectivas consequênias.
* Uma novidade aqui é o uso do **PIFilter**. Este filtro permite que seja injetado automaticamente em um aluno uma turma recuperada do banco a partir de informações vindas de algum formulário. Neste caso, durante o cadastro de um aluno, a turma será escolhida pelo id, este id será buscado no banco e a respectiva turma será injetada no aluno.
===== Passo 6 - Criando o Validator =====
== TurmaValidator.java ==
Crie em **modules.validators** a classe TurmaValidator.java:
package modules.escola.validators;
import modules.escola.beans.Turma;
import org.futurepages.core.persistence.Dao;
import org.futurepages.core.validation.Validator;
import org.futurepages.util.Is;
public class TurmaValidator extends Validator {
public void create(Turma turma) {
// validando o nome da turma
if (Is.empty(turma.getNome())) {
error("Preencha o campo: nome da turma.");
}
// validação do código está vazio
if (Is.empty(turma.getCodigo())) {
error("Preencha o campo: código da turma.");
}
// verifica se o código da turma já está cadastrado.
else if (Dao.uniqueResult(Turma.class, "codigo='" + turma.getCodigo() + "'") != null) {
error("Já existe uma turma com esse código.");
}
}
}
== AlunoValidator.java ==
Crie em **modules.validators** a classe AlunosValidator.java:
package modules.escola.validators;
import modules.escola.beans.Aluno;
import org.futurepages.core.persistence.Dao;
import org.futurepages.core.validation.Validator;
import org.futurepages.util.Is;
public class AlunoValidator extends Validator {
public void create(Aluno aluno) {
// Validação da turma
if (Is.empty(aluno.getTurma())) {
error("Selecione uma turma.");
}
// Validação do nome
if (Is.empty(aluno.getNomeCompleto())) {
error("Preencha o nome do aluno.");
}
// Validação da matrícula
if (Is.empty(aluno.getMatricula())) { //verifica se matrícula vazia
error("Especifique a matrícula do aluno.");
} else {
// Caso matrícula não seja vazia, verifica se a matrícula já existe
if (Dao.uniqueResult(Aluno.class, "matricula='" + aluno.getMatricula() + "'") != null) {
error("Já existe um aluno com esta matrícula.");
}
}
}
}
Veja que a única direfênça para a versão anterior dessa classe foi ter acrescentado o teste para a turma em qual o aluno se cadastra.
===== Passo 7 - Atualize os links para as novas páginas =====
Modifique init/Index.jsp:
<%@taglib uri="futurepagesApp" prefix="fpg"%>
Execute a aplicação e veja-a funcionando como nas imagens abaixo:
{{ :quickstart:tela_inicial-tutorial-parte2.png |}}
{{ :quickstart:nova_turma-tutorial-parte2.png |}}
{{ :quickstart:listar_turmas-tutorial-parte2.png |}}
{{ :quickstart:novo_aluno-tutorial-parte2.png |}}
{{ :quickstart:listar_alunos-tutorial-parte2.png |}}
{{ :quickstart:listar_alunos_com_filtro-tutorial-parte2.png |}}
**OBS**
* O projeto usado neste tutorial pode ser baixado nos nossos repositórios:
Repositório : http://repo.futurepages.org/svn/2/apps/alunoonline/tags/meu_primeiro_projeto_com_futurepages_parte2
Usuário : user
Senha : fpguser
* Uma extensão do projeto que inclui **editar** e **excluir** um aluno também pode ser baixado aqui:
Repositório : http://repo.futurepages.org/svn/2/apps/alunoonline/tags/meu_primeiro_projeto_com_futurepages_parte2_extensao
Usuário : user
Senha : fpguser
Ficará como tarefa adicional para o estudante, a implementação de edição e exclusão de turmas.
Bons estudos.