Tabela de conteúdos

Meu Primeiro Projeto Web com Futurepages2 - Parte 1

Neste Tutorial iremos criar um pequeno projeto Web com Futurepages2 para cadastro de Alunos. A seguir temos os requisitos do sistema:

Necessário

Passo 1 - Construindo a Primeira Tela

De posse de todos os arquivos descritos anteriormente e com o Tomcat devidamente instalado, siga os seguintes passos

Configure o espaçamento da IDE

Como possuímos padronização e liberdade como principais valores no futurepages, os projetos podem rodar em qualquer IDE que ofereça suporte a JEE (assim tendo liberdade de escolha). Este tutorial é desenvolvido baseado no NetBeans para que não percamos a padronização de nosso código e para que seja possível numa mesma equipe existir usuários de IDEs diferentes é necessário que padronizemos a configuração dos espaçamentos do código-fonte da IDE.

Se você é usuário do NetBeans, configure como ilustrado na imagem, caso contrário procure fazer o equivalente em sua IDE.

Vá em Ferramentas → Opções → Editor → Formatando

Crie um Novo Projeto Web

Altere as propriedades padrões do projeto

Configure sua aplicação para rodar sobre o futurepages2

Configure o arquivo em WEB-INF/web.xml para rodar o futurepages2 na inicialização como mostrado a seguir:

<?xml version="1.0" encoding="ISO-8859-1"?>
 
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
	<display-name>Aluno On Line</display-name>
 
        <!-- Tempo padrão da sessão http do usuário -->
	<session-config>
		<session-timeout>10</session-timeout>
	</session-config>
 
        <!-- Servlet Controlador - responsável pelas Actions -->
	<servlet>
		<servlet-name>Controller</servlet-name>
		<servlet-class>org.futurepages.core.control.Controller</servlet-class>
		<init-param>
			<param-name>applicationManager</param-name>
			<param-value>org.futurepages.core.ApplicationManager</param-value>
		</init-param>
	</servlet>
 
        <!-- Servlet responsável pelos Templates -->
        <servlet>
		<servlet-name>TemplateServlet</servlet-name>
		<servlet-class>org.futurepages.core.template.JspTemplateServlet</servlet-class>
		<init-param>
			<param-name>TemplateManager</param-name>
			<param-value>org.futurepages.core.template.TemplateManager</param-value>
		</init-param>
	</servlet>
 
        <!-- Inicializador da aplicação Futurepages -->
	<listener>
		<description>Application Listener</description>
		<listener-class>org.futurepages.core.ApplicationListener</listener-class>
	</listener>
 
        <!-- Gerenciador de eventos na criação e destruição de sessões http de usuário -->
	<listener>
		<listener-class>org.futurepages.core.session.SessionListener</listener-class>
	</listener>
 
        <!-- Mapeamentos de actions -->
	<servlet-mapping>
		<servlet-name>Controller</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
 
	<servlet-mapping>
		<servlet-name>Controller</servlet-name>
		<url-pattern>*.fpg</url-pattern>
	</servlet-mapping>
 
        <!-- Mapeamentos de templates -->
	<servlet-mapping>
		<servlet-name>TemplateServlet</servlet-name>
		<url-pattern>*.page</url-pattern>
	</servlet-mapping>
</web-app>


Note que neste arquivo estão sendo informados que…

Adicione os arquivos de Configurações

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.

<?xml version="1.0" encoding="ISO-8859-1"?>
 
 
<app-params-configuration>
 
   <!-- Em breve alguns parâmetros serão adicionados. -->
 
</app-params-configuration>


Configuração do Template

Crie em SRC conf/app-template.xml com o seguinte conteúdo:

<?xml version="1.0" encoding="ISO-8859-1"?>
 
 
<app-template-configuration>
    <page rule="^.*$" base="template/layout.jsp">
        <block id="cabecalho"   value="template/cabecalho.jsp"/>
        <block id="rodape"      value="template/rodape.jsp"/>
     </page>
</app-template-configuration>


O arquivo app-template.xml é responsável pela configuração de Template da aplicação - gerenciado pelo TemplateManager ;

Crie seus arquivos de template na pasta Web:

template/layout.jsp :

<%@ taglib uri="futurepagesApp" prefix="fpg"%>
<%@ page language="java" contentType="text/html; charset=iso-8859-1" pageEncoding="iso-8859-1"%>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
    <head>
        <title>Aluno Online QuickStart Application</title>
    </head>
 
    <body>
        <fpg:block id="cabecalho"/>
        <hr/>
	<fpg:block id="body"/>
        <hr/>
	<fpg:block id="rodape"/>
    </body>
</html>


template/cabecalho.jsp :

<%@ taglib uri="futurepagesApp" prefix="fpg"%>
 
<div style="text-align:center; font-size: 20px">
    <a href="<fpg:contextPath/>/">Aluno Online QuickStart Application</a>
</div>


template/rodape.jsp :

<div style="text-align:center; font-size: 10px">
    (c) 2008-2010 - Workset - Todos os Direitos Reservados
</div>


Neste momento você deve ter notado que a uri “futurepagesApp” não foi reconhecida pela IDE. Mais adiante será mostrado o que deve ser feito para que a taglib seja reconhecida.

Crie a Ação e a Tela Inicial da Aplicação

Alterações do SRC (JAVAs)
package init;
 
import org.futurepages.actions.FreeAction;
import org.futurepages.util.DateUtil;
 
/**
 * Ação Inicial da Aplicação
 */
public class Index extends FreeAction{
 
    @Override
    public String execute(){
        output.setValue("mensagemInicial","Seja bem-vindo. Data atual: "+DateUtil.viewToday("dd/MM/yyyy"));
        return SUCCESS;
    }
}


* Esta classe é uma FreeAction do Futurepages, pois não precisaremos de usuário logado para acessá-la.

Alterações da WEB (JSPs)
<%@taglib uri="futurepagesApp" prefix="fpg"%>
 
<div style="text-align:center">
 
    <h1><fpg:out value="mensagemInicial"/></h1>
    <br/>
    <br/>
    <a href="javascript:void(0)">Novo Aluno</a>
    <br/>
    <br/>
    <a href="javascript:void(0)">Listar Alunos</a>
    <br/>
    <br/>
 
</div>


Altere o arquivo /index.jsp para que ele redirecione para sua ação inicial:

<meta http-equiv="refresh" content="0;URL=Index.fpg"/>


Você acabou de criar a ação inicial padrão da aplicação Futurepages.

tela_inicial.jpg

Reconhecimento da taglib

taglib_origem.jpg

taglib_destno.jpg

Passo 2 - Criando o Modelo

Configure o acesso ao banco de dados

O seu arquivo context.xml gerado pelo NetBeans provavelmente deverá estar similar a este que se segue:

<?xml version="1.0" encoding="ISO-8859-1"?>
 
<Context antiJARLocking="true" path="/alunoonline"/>


Inclua a tag Resource mostrada a seguir dentro da tag Context. Seu arquivo deverá ficar como mostrado a seguir:

<?xml version="1.0" encoding="ISO-8859-1"?>
 
<Context antiJARLocking="true" path="/alunoonline">
 
    <Resource  
            name="jdbc/alunoOnLineDS"
            type="javax.sql.DataSource"
            driverClassName="com.mysql.jdbc.Driver"
            url="jdbc:mysql://localhost:3306/alunoonlinebd"
            username="root"
            password=""
            auth="Container"
            initialSize="4"
            maxActive="-1"
            validationQuery="Select 1"
            testOnBorrow="true"			   
	/>
 
</Context>


Entendendo os parâmetros do DataSource:

Parâmetros do Banco de Dados
name nome do DataSource
driverClassName Driver do Banco de Dados , MySQL neste exemplo
url url para conexão com o banco
username usuário de acesso ao banco de dados
password senha do usuário do banco.


Configure a camada de persistência (Hibernate)

O Futurepages utiliza o Hibernate Annotations como camada de persistência dos dados. ele que faz a ponte entre aplicação e banco de dados. Para utilizar-se deste recurso em nossa aplicação, deveremos configurar o acesso da aplicação ao banco de dados (DataSource) e especificar algumas outras propriedades do Hibernate. Essa configuração é feita através do arquivo hibernate.properties .

Crie em SRC o arquivo conf/hibernate.properties como mostrado a seguir:

 hibernate.dialect = org.hibernate.dialect.MySQLDialect
 hibernate.show_sql = false
 hibernate.format_sql = false
 hibernate.connection.datasource = java:/comp/env/jdbc/alunoOnLineDS


Observe:

 hibernate.dialect = org.hibernate.dialect.MySQLDialect
 hibernate.show_sql = false
 hibernate.format_sql = false
 hibernate.connection.driver_class=com.mysql.jdbc.Driver
 hibernate.connection.url=jdbc:mysql://localhost/alunoonlinebd
 hibernate.connection.username=root
 hibernate.connection.password=


A vantagem desta última configuração é a possibilidade de realizar testes no ambiente de desenvolvimento Java com maior facilidade. Você poderá executar classes com método main() e conseguirá acessar a base de dados, já que a configuração do banco não estará no Tomcat. Recomendamos, para o desenvolvimento, que utilize este último.

As desvantagens são o baixo desempenho para aplicações com muitos usuários (péssimo para ambiente em produção) e efeitos colaterais no controle do isolamento de transações (Mysql). Este último problema pode ser resolvido da seguinte maneira:

No Windows, no arquivo my.ini adicione ao seu final, uma nova linha com o seguinte comando, salve-o e reinicie o MySQL:

    transaction-isolation=READ-COMMITTED

No Linux, o arquivo é o my.cnf, localize-o na pasta correta de seu mysql. adicione o comando transaction-isolation=READ-COMMITTED no local indicado a seguir:


(...)

# The MySQL server
[mysqld]

default-storage-engine=InnoDB
transaction-isolation=READ-COMMITTED

user                = nobody
port                = 3306
socket                = /opt/lampp/var/mysql/mysql.sock


(...)

Crie os Beans

Beans são aquelas classes do modelo que refletirão nossas entidades do Banco de Dados. No nosso caso, temos somente uma entidade: Aluno. No código SRC , crie o pacote modules.escola.beans e dentro dele crie a classe Aluno.java que refletirá a nossa entidade Aluno.

O arquivo Aluno.java deverá ter o seguinte conteúdo:

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_aluno")
public class Aluno implements Serializable {
 
 
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;
 
 
	@Column(name = "matricula", length = 10, unique = true, nullable = false)
	private String matricula;
 
 
	private String nomeCompleto;
 
 
	public Aluno() {
	}
 
 
	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;
	}
}


Observações

Gere a estrutura (esquema) do Banco de Dados

Neste tópico verificaremos se os mapeamentos que fizemos em nossos beans sairam como esperado, iremos gerar as nossas tabelas no banco de dados já criado e configurado. Para isso, basta adicionarmos um parâmetro de configuração no nosso arquivo app-params.xml e executar a aplicação.

Deixe seu arquivo app-params.xml como se segue:

<app-params-configuration>
 
    <param name="SCHEMA_GENERATION_TYPE"    value="export"/>
 
</app-params-configuration>


Após modificar o arquivo, execute a aplicação. Você visualizará a sql de criação da tabela no log do Tomcat no momento da inicialização:

INFO: Running hbm2ddl schema export
drop table if exists escola_aluno
create table escola_aluno (id integer not null auto_increment,
                           matricula varchar(10) not null unique,
                           nomeCompleto varchar(255),
                           primary key (id))
15/04/2009 19:28:50 org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: exporting generated schema to database


Após executado, troque o valor export do parâmetro por none e deixe-o assim até que seja necessário criar um novo esquema para a base de dados.

Antes de passar para o próximo item, verifique no SGBD se o esquema foi criado como esperado. Você irá visualizar a tabela escola_aluno com os campos devidamente mapeados. Caso contrário, verifique a possibilidade de ter feito algo errado. A estrutura de sua tabela deverá estar como mostrado a seguir:

mysql_alunoonlinebd.jpg

Inserções Iniciais (Install)

O Futurepages oferece um recurso que possibilita a inserção de várias instâncias (linhas) no banco de dados no momento da inicialização da aplicação. Este recurso é o INSTALL MODE (Modo de Instalação) o qual funciona da seguinte maneira:

Parâmetro INSTALL_MODE em app-params.xml:
Ligue o "INSTALL MODE"

Altere o arquivo app-params.xml, deixando-o assim:

<?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>


Criando o Installer

Vamos criar alguns alunos de exemplo no nosso projeto, vamos criar nosso instalador e criar as instalações de alguns alunos.

Crie em modules.escola.install a classe AlunosInstaller com o seguinte código-fonte:

package modules.escola.install;
 
import org.futurepages.core.install.Installer;
import org.futurepages.core.persistence.Dao;
import modules.escola.beans.Aluno;
 
/**
 * Instala alunos para testes de exemplos
 *
 */
public class AlunosInstaller extends Installer{
 
    public void execute(){
        Dao.save(new Aluno("03N1047000", "Maria da Silva"));
        Dao.save(new Aluno("02N1047451", "João Fulano Cavalcante Soares"));
        Dao.save(new Aluno("99S5447050", "Antônio Feliciano Gomes"));
        Dao.save(new Aluno("99S5000001", "Sicrano da Silva e Silva"));
        Dao.save(new Aluno("99S8348349", "Maria Antonieta da Costa"));
        Dao.save(new Aluno("93E9394322", "José Pompeu Exemplus da Silva"));
    }
}


Observe:

    public Aluno(String matricula, String nomeCompleto) {
        this.matricula = matricula;
        this.nomeCompleto = nomeCompleto;
    }


Agora temos nosso Instalador devidamente criado e o INSTALL_MODE ligado. Vamos executar nossa aplicação.

No log de inicialização verificaremos a indicação de que o Instalador AlunosInstaller foi executado:

[:install:] BEGIN...
[:install:] module 'escola' installing...
[:install:]>>> installer AlunosInstaller running...
[:install:]>>> installer AlunosInstaller OK.
[:install:] module escola installed.
[:install:] END.


Verifique no banco se os dados estão lá como o esperado. Desligue o INSTALL MODE e continue o seu processo de desenvolvimento.

Passo 3 - Criando o Controle

Crie AlunoActions.java no pacote modules.escola.actions , esta classe refletirá a nossos casos de uso de criação, visualização, edição e deleção de aluno (CRUD). (Neste tutorial só faremos o caso de criação e listagem)

A classe deverá herdar org.futurepages.actions.CrudActions , uma das Actions do Futurepages, a qual possui automatizações para CRUDs.

Esta classe deve possuir um atributo private do tipo modules.escola.beans.Aluno

Lembre-se que todas as suas ações de casos de uso devem herdar uma das actions do futurepages.

Crie a innerAction create()

Crie o método (innerAction) contemplando a criação de um novo aluno, o padrão é create :

package modules.escola.actions;
 
import java.util.List;
import modules.escola.beans.Aluno;
import org.futurepages.actions.CrudActions;
import org.futurepages.core.persistence.Dao;
 
public class AlunoActions extends CrudActions {
 
    private Aluno aluno;
 
    public String create() {
        Dao.saveTransaction(aluno);
        return success("Aluno criado com sucesso");
    }
}


A innerAction create (nas actions, os métodos públicos são chamados de innerAction ) é o método que deverá ser chamado quando o usuário do sistema enviar uma requisição de “salvar novo aluno”. As propriedades do objeto aluno da classe deverão estar preenchidos com os dados do formulário antes do método ser executado. O método ao ser executado, irá inserir o novo aluno na base de dados e retornará uma mensagem de sucesso indicando que o aluno foi criado com sucesso.

Crie o método privado listObjects()

Trata-se do método que realiza a listagem padrão dos beans. Sobrescreva-o na sua action de CRUD. Pois ele deverá ser chamado automaticamente quando a tela de listagem padrão for requisitada. Nos próximos passos entenderemos como isso ocorre.

Adicione em AlunoActions o seguinte método:

    @Override
    protected void listObjects() {
        List<Aluno> alunos = Dao.list(Aluno.class,"","nomeCompleto asc");
        output.setValue("alunos", alunos);
    }


Este método carrega todos os alunos cadastrados na base de dados ordenados pelo nome completo e logo em seguida coloca esta lista no output da action nomeada com a chave “alunos”.

Passo 4 - Criando a Visão

Consideremos “visão” os arquivos JSPs (localizados na pasta WEB), os quais representam as telas do sistema:

Tela de Caso de Uso Arquivo em “WEB/modules/escola/”
Criação de Aluno (Novo Aluno) Aluno.create.jsp
Listagem de Alunos (Explorar com filtros) 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.

Atualize os links para as novas telas

Primeiramente iremos modificar a tela inicial da aplicação para contemplar os links corretos que irão redirecionar o usuário até as telas de cadastro de alunos (Aluno.create.jsp)

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


Veja que no arquivo:

Crie a tela de Novo Aluno

Crie /modules/escola/Aluno.create.jsp

<%@taglib uri="futurepagesApp" prefix="fpg"%>
 
<div style="text-align:center">
    <h1>Novo Aluno</h1>
    <br/>
    <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/>
        <input type="submit" value="Enviar" />
    </form>
</div>


Note que criamos a tela com o formulário de cadastro do novo aluno, no qual o usuário especificará nome e matrícula, enviando-os via POST para o seguinte endereço:

Nosso objetivo é que AlunoActions.create() seja executada a partir desta requisição, recebendo como entrada o atributo aluno existente na classe AlunoActions preenchido com os campos do formulário, para então persistí-lo na base de dados. Mais a seguir descobriremos como esta “mágica” é feita.

Crie a tela de Listagem de Alunos

Crie /modules/escola/Aluno.explore.jsp como se 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/>
	<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>
				</tr>
				<fpg:loop var="aluno">
					<tr>
						<td>${aluno.id}</td>
						<td>${aluno.nomeCompleto}</td>
						<td>${aluno.matricula}</td>
					</tr>
				</fpg:loop>
			</table>
		</fpg:isEmpty>
	</fpg:list>
	<br/>
	<br/>
</div>


Perceba que:

Passo 5 - Configurando o fluxo entre Controle e Visão

No passo anterior vimos que o usuário clica no link /modules/escola/Aluno.fpg?type=create para abrir o formulário de criação e o segundo envia o mesmo formulário para /modules/escola/Aluno.create.fpg . Algumas ressalvas sobre as requisições, antes de prosseguir:

Vejamos como AlunoActions foi apelidada de Aluno e como se dão os fluxos entre tela (jsp) e controle (java).

Crie o ModuleManager

Crie modules.escola.ModuleManager.java com o conteúdo a seguir:

package modules.escola;
 
import modules.escola.actions.AlunoActions;
import modules.escola.beans.Aluno;
import org.futurepages.core.control.AbstractModuleManager;
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))
 
            // se chamar Aluno.fpg?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"))
 
            //Aluno.fpg?type=explore ocorre o redirecionamento para a tela de listagem dos alunos cadastrados no sistema
            .on(EXPLORE, fwIn("Aluno.explore.page"))
               .on(SUCCESS, EXPLORE, fwIn("Aluno.explore.page")) 
         ;
 
    }
}


Entenda bem os elementos do ModuleManager

Note que dentro do método loadActions() você adiciona as actions , as quais somente serão reconhecidas pelo servlet controlador (*.fpg) se definidas em algum ModuleManager.

O método loadActions() de cada módulo é carregado no controlador no momento de inicialização da aplicação. Este método é composto por o que chamamos de ActionConfig s, estas podem ser métodos como action, filter, on , etc. Podem ser globais ou vinculadas à uma action:

As consequências podem ser do tipo: Forward (fwd) e Redirect (redir) :

Agora sua aplicação cria e lista alunos, execute-a e faça os testes.

Suas telas devem parecer com as duas telas que se seguem:



Passo 6 - Validando os Dados de Entrada

Foi especificado que este sistema NÃO permitirá:

Se tentarmos criar um aluno com matrícula já existente, ocorrerá uma exceção (ConstraintViolationException ), pois especificamos no esquema o campo matrícula teria o atributo unique=true na anotação @Column . O sistema de banco de dados não permitirá a inclusão, mas a mensagem não é amigável para o usuário.

Log do Servidor ao tentar-se criar um aluno com uma matrícula existente.

could not insert: [modules.escola.beans.Aluno]
org.hibernate.exception.ConstraintViolationException: could not insert: [modules.escola.beans.Aluno]

...

Caused by: java.sql.SQLException: Duplicate entry '' for key 2


Se tentarmos criar um aluno com o nome completo vazio, o aluno será criado com sucesso, ao contrário do que foi especificado.

Veremos neste passo como fazer para atender aos requisitos de validação de dados de entrada.

Crie o Validador

Validadores são classes que possuem métodos de validação para uma entidade. Se aluno é algo a ser validado, então criaremos um validador para Aluno (AlunoValidator) em modules.escola.validators .

Crie a classe modules.escola.validators.AlunoValidator :

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 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.");
			}
		}
 
	}
}


Caso não encontre a classe Validator do futurepages, é provável que você esteja utilizando uma versão desatualizada do futurepages. Baixe a versão mais nova para que então seja possível compilar sua classe. ( futurepages.jar )

Aplique o validador na action

Primeiro adicione o import no cabeçalho da sua classe

import modules.escola.validators.AlunoValidator;

Faça a seguinte chamada na innerAction create()

    public String create() {
        validate(AlunoValidator.class).create(aluno);  //validação de aluno
        Dao.saveTransaction(aluno);
        return success("Aluno criado com sucesso");
    }


Configure o fluxo do erro

Você irá adicionar a consequência do erro. Ou seja, dirá para onde o output da action deve ir assim que retornar algum erro. Para isso, iremos adicionar a seguinte linha ao ModuleManager como consequência da innerAction create() da action apelidada de “Aluno” .

.on(ERROR,   CREATE, fwIn("Aluno.create.page"))


A linha acima informa ao Manager o seguinte: Quando houver um erro durante a execução do método create() , todo o output da action irá para Aluno.create.page .

Seu ModuleManager ficará assim:

package modules.escola;
 
 
import modules.escola.actions.AlunoActions;
import modules.escola.beans.Aluno;
import org.futurepages.core.control.AbstractModuleManager;
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))
 
 
            // se chamar Aluno.fpg?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.fpg?type=explore ocorre o redirecionamento para a tela de listagem dos alunos cadastrados no sistema
            .on(EXPLORE, fwIn("Aluno.explore.page"))
               .on(SUCCESS, EXPLORE, fwIn("Aluno.explore.page")) 
         ;
 
    }
}


Contemple o retorno do erro na visão

A tag hasError verifica se a tela voltou do erro e error imprime a mensagem de erro.

<%@taglib uri="futurepagesApp" prefix="fpg"%>
 
<div style="text-align:center">
    <h1>Novo Aluno</h1>
    <br/>
    <br/>
    <fpg:hasError>
        <!-- imprime estre pedaço somente se houver erro na página -->
        <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/>
        <input type="submit" value="Enviar" />
    </form>
</div>


Pronto, a validação está concluída. Rode sua aplicação e provoque as telas de erro, passando como entrada dados inválidos.

Você deverá ver uma tela semelhante à que se segue:

Repositório : http://repo.futurepages.org/svn/2/apps/alunoonline/tags/meu_primeiro_projeto_com_futurepages
    Usuário : user
      Senha : fpguser