====== Meu Primeiro Projeto WEB com Futurepages2 - Parte 2 ====== Nesta nova etapa nós vamos aproveitar o primeiro tutorial pra dar continuidade aos estudos do **Futurepages2**. * Será abordado: * Adicionar o cadastro de Turma. Deste modo, para que cada aluno fazer uma referência a uma turma; * Modificação das telas anteriores do projeto para acrescentar o cadastro e listagem das turmas. Também a exibição e cadastro de alunos serão alterados para ficarem de acordo com a nova proposta. * A aplicação contemplará as seguintes **críticas**: * **Turma** possuirá os campos //nome// e //código//; * O sistema não permitirá inserir uma turma com código já existente; * O sistema não permitirá inserir uma turma tanto com código ou nome não especificados; * **Aluno** possuirá os campos nome //completo//, //matricula// e //turma//; * O sistema não permitirá inserir um aluno com matrícula já existente; * O sistema não permitirá inserir um aluno tanto com turma, matrículas e/ou nomes não especificados; * Quanto ao **template**: * **Cabeçalho** e **rodapé** constantes em todas as telas. ===== Necessário ===== * Ter praticado a primeira parte deste tutorial, presente neste link: [[quickstart:projeto_futurepages_do_zero]] * O código fonte pode ser baixado diretamente dos repositórios do SVN aqui: 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"%>



Nova Turma

Listar Turmas

Novo Aluno

Listar Alunos

//À 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"%>

Listagem de Turmas



/Turma.fpg?type=create">Nova Turma

Nenhuma turma cadastrada.
ID CÓDIGO NOME
${turma.id} ${turma.codigo} ${turma.nome}


* Quando é acessado **Turma.fpg?type=explore**, o método (inner action) **listObjects** da action **TurmaAction**, será acessado. * A tag **** verifica se a lista é vazia. == Criando a Tela de Novo Aluno == Em **/WEB/modules/escola/**, crie **Aluno.create.jsp**, como segue: <%@taglib uri="futurepagesApp" prefix="fpg"%>

Novo Aluno




/Aluno.create.fpg"> Nome:

Matrícula:




* O detalhe aqui é para a tag ****, que contém uma listagem de turmas onde será selecionada uma turma para efetuar o cadastro do aluno. * **list** é o atributo que define a chave da lista do tipo (**List**) que foi passada no **output**. * **showAttr** define qual o atributo de cada elemento da lista será mostrado no **select**. * **name** define um nome para o select. == Criando a Tela de Listagem de Alunos == Em **/WEB/modules/escola/**, crie **Aluno.explore.jsp**, como segue: <%@taglib uri="futurepagesApp" prefix="fpg" %>

Listagem de Alunos



/Aluno.fpg?type=create">Novo Aluno

/Aluno.explore.fpg">

Nenhum aluno cadastrado.
ID NOME MATRÍCULA Turma
${aluno.id} ${aluno.nomeCompleto} ${aluno.matricula} ${aluno.turma.nome}


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 ****; * Cada elemento do select contém uma turma; * Quando uma turma é selecionada, é enviado o id da turma para a inner action **explore** (método **explore()**) da action Aluno (classe **AlunoAction**); ===== Passo 5 - Alterando o ModuleManager ===== Altere o **ModuleManager.java** em **modules.escola**, e deixe-o como segue: 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"%>



/Turma.fpg?type=create" >Nova Turma

/Turma.fpg?type=explore" >Listar Turmas

/Aluno.fpg?type=create">Novo Aluno

/Aluno.fpg?type=explore">Listar Alunos

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.