Nesta nova etapa nós vamos aproveitar o primeiro tutorial pra dar continuidade aos estudos do Futurepages2.
Repositório : http://repo.futurepages.org/svn/2/apps/alunoonline/tags/meu_primeiro_projeto_com_futurepages Usuário : user Senha : fpguser
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.
<?xml version="1.0" encoding="ISO-8859-1"?> <app-params-configuration> <param name="SCHEMA_GENERATION_TYPE" value="none"/> <param name="INSTALL_MODE" value="off"/> </app-params-configuration>
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.
<%@taglib uri="futurepagesApp" prefix="fpg"%> <div style="text-align:center"> <h1><fpg:out value="mensagemInicial"/></h1> <br/> <br/> <a href="javascript:void(0)" >Nova Turma</a> <br/> <br/> <a href="javascript:void(0)" >Listar Turmas</a> <br/> <br/> <a href="javascript:void(0)">Novo Aluno</a> <br/> <br/> <a href="javascript:void(0)">Listar Alunos</a> <br/> <br/> </div>
À 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.
* 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
* 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
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:
<app-params-configuration> <param name="SCHEMA_GENERATION_TYPE" value="export"/> <param name="INSTALL_MODE" value="off"/> </app-params-configuration>
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.
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<Turma> listaTurma; private Random rand = new Random(System.currentTimeMillis()); public AlunoExemplos() { } public AlunoExemplos(List<Turma> 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<Turma> listaTurma; new TurmaExemplos().execute(); listaTurma = Dao.list(Turma.class); new AlunoExemplos(listaTurma).execute(); } }
* Altere o value de INSTALL_MODE para on:
<?xml version="1.0" encoding="ISO-8859-1"?> <app-params-configuration> <param name="SCHEMA_GENERATION_TYPE" value="none"/> <param name="INSTALL_MODE" value="on"/> </app-params-configuration>
Execute a aplicação e depois retorne o value de INSTALL_MODE para off.
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<Turma> turmas = Dao.list(Turma.class, "", "nome asc"); output.setValue("turmas", turmas); } }
* Observe que TurmaActions é semelhante à classe AlunoActions mostrada no tutorial anterior.
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<Turma> 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<Aluno> alunos = Dao.list(Aluno.class, consulta, "nomeCompleto asc"); List<Turma> 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
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.
Em /WEB/modules/escola/, crie Turma.create.jsp, como segue:
<%@taglib uri="futurepagesApp" prefix="fpg"%> <div style="text-align:center" > <h1>Nova Turma</h1> <br /> <br /> <fpg:hasError> <div style="color: red; border: solid 1px red"> <fpg:error /> </div> </fpg:hasError> <br /> <form method="post" action="<fpg:modulePath module="escola" />/Turma.create.fpg" > <fpg:bean value="turma"> Nome: <input id="nome" name="nome" value="${turma.nome}" /> <br /> <br /> Codigo: <input id="codigo" name="codigo" value="${turma.codigo}" /> </fpg:bean> <br /> <br /> <input type="submit" value="Enviar"> </form> </div>
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:
Este endereço corresponde ao método (inner action) create() da classe TurmaAction.
Em /WEB/modules/escola/, crie Turma.explore.jsp, como segue:
<%@taglib uri="futurepagesApp" prefix="fpg"%> <div align="center"> <h2>Listagem de Turmas</h2> <fpg:hasSuccess> <fpg:success /> <br /> <br /> </fpg:hasSuccess> <a href="<fpg:modulePath module="escola" />/Turma.fpg?type=create">Nova Turma</a> <br /> <br /> <fpg:list value="turmas"> <fpg:isEmpty> Nenhuma turma cadastrada. </fpg:isEmpty> <fpg:isEmpty negate="true"> <table border="1"> <tr> <td><strong>ID</strong></td> <td><strong>CÓDIGO</strong></td> <td><strong>NOME</strong></td> </tr> <fpg:loop var="turma"> <tr> <td>${turma.id}</td> <td>${turma.codigo}</td> <td>${turma.nome}</td> </tr> </fpg:loop> </table> </fpg:isEmpty> </fpg:list> <br /> <br /> </div>
Em /WEB/modules/escola/, crie Aluno.create.jsp, como segue:
<%@taglib uri="futurepagesApp" prefix="fpg"%> <div style="text-align:center"> <h1>Novo Aluno</h1> <br/> <br/> <fpg:hasError> <div style="color: red; border:solid 1px red"> <fpg:error/> </div> </fpg:hasError> <br/> <form method="post" action="<fpg:modulePath module="escola" />/Aluno.create.fpg"> <fpg:bean value="aluno"> Nome: <input id="nomeCompleto" name="nomeCompleto" value="${aluno.nomeCompleto}" /> <br/><br/> Matrícula: <input id="matricula" name="matricula" value="${aluno.matricula}" /> </fpg:bean> <br /> <br /> <fpg:Select list="turmas" name="turma" showAttr="nome" /> <br /> <br /> <input type="submit" value="Enviar" /> </form> </div>
Em /WEB/modules/escola/, crie Aluno.explore.jsp, como segue:
<%@taglib uri="futurepagesApp" prefix="fpg" %> <div align="center"> <h2>Listagem de Alunos</h2> <fpg:hasSuccess> <fpg:success/> <br/> <br/> </fpg:hasSuccess> <a href="<fpg:modulePath module="escola" />/Aluno.fpg?type=create">Novo Aluno</a> <br/> <br/> <form name="selecionaPorTurma" method="post" action="<fpg:modulePath module="escola" />/Aluno.explore.fpg"> <fpg:Select list="turmas" name="turma" selected="${turma}" defaultText="- Todas as Turmas -" onchange="selecionaPorTurma.submit()" showAttr="nome" /> </form> <br/> <br/> <fpg:list value="alunos"> <fpg:isEmpty> Nenhum aluno cadastrado. </fpg:isEmpty> <fpg:isEmpty negate="true"> <table border="1"> <tr> <td><strong>ID</strong></td> <td><strong>NOME</strong></td> <td><strong>MATRÍCULA</strong></td> <td><strong>Turma</strong></td> </tr> <fpg:loop var="aluno"> <tr> <td>${aluno.id}</td> <td>${aluno.nomeCompleto}</td> <td>${aluno.matricula}</td> <td>${aluno.turma.nome}</td> </tr> </fpg:loop> </table> </fpg:isEmpty> </fpg:list> <br/> <br/> </div>
Vamos às novidades:
da action Aluno (classe AlunoAction);
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")); } }
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."); } } }
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.
Modifique init/Index.jsp:
<%@taglib uri="futurepagesApp" prefix="fpg"%> <div style="text-align:center"> <h1><fpg:out value="mensagemInicial"/></h1> <br/> <br/> <a href="<fpg:modulePath module="escola" />/Turma.fpg?type=create" >Nova Turma</a> <br/> <br/> <a href="<fpg:modulePath module="escola" />/Turma.fpg?type=explore" >Listar Turmas</a> <br/> <br/> <a href="<fpg:modulePath module="escola" />/Aluno.fpg?type=create">Novo Aluno</a> <br/> <br/> <a href="<fpg:modulePath module="escola" />/Aluno.fpg?type=explore">Listar Alunos</a> <br/> <br/> </div>
Execute a aplicação e veja-a funcionando como nas imagens abaixo:
OBS
Repositório : http://repo.futurepages.org/svn/2/apps/alunoonline/tags/meu_primeiro_projeto_com_futurepages_parte2 Usuário : user Senha : fpguser
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.