Raible's Wiki

Raible Designs
Wiki Home
News
Recent Changes

AppFuse

Homepage
  - Korean
  - Chinese
  - Italian
  - Japanese

QuickStart Guide
  - Chinese
  - French
  - German
  - Italian
  - Korean
  - Portuguese
  - Spanish
  - Japanese

User Guide
  - Korean
  - Chinese

Tutorials
  - Chinese
  - German
  - Italian
  - Korean
  - Portuguese
  - Spanish

FAQ
  - Korean

Latest Downloads

Other Applications

Struts Resume
Security Example
Struts Menu

Set your name in
UserPreferences

Edit this page


Referenced by
Articles
Articles_pt
CreateActions_pt




JSPWiki v2.2.33

[RSS]


Hide Menu

ValidationAndList_pt


Parte IV: Adicionando Validação e Tela de Listagem - Adicionando a lógica de validação para o PersonForm para que o firstName e o lastName sejam campos obrigatórios e adicionar uma tela de listagem para mostrar todas as tuplas de pessoas da base de dados.

Este tutorial depende da Parte III: Criando Actions e JSPs.

Sobre este tutorial

Este tutorial nos mostrará como adicionar lógica de validação (tanto cliente quanto servidor) para o objeto PersonForm utilizando Struts Validator. Também criaremos uma tela de listagem utilizando a Display Tag Library para mostrar todas as pessoas da base de dados.
Vou dizer a vocês como faço as coisas no Mundo Real em textos como este.

Tabela de Conteúdo

  • [1] Adicionar as tags de validação XDoclet para o Person.java
  • [2] Veja o JSP com a validação com a validação adicionada e teste
  • [3] Adicione métodos testGetPeople nos testes DAO e Manager
  • [4] Adicione métodos getPeople para PersonDao e PersonManager
  • [5] Adicione o método testSearch ao teste da Action
  • [6] Adicione o método search à Action
  • [7] Crie personList.jsp e seu teste Canoo
  • [8] Adicione o link ao menu

Adicionar as tags de validação XDoclet para o Person.java [#1]

Para utilizar o Struts Validator, normalmente teríamos que escrever um arquivo validation.xml na mão. Se não utilizarmos AppFuse, teremos que configurar o Validator Plugin e as chaves de erro em nosso ApplicationResources.properties (ApplicationResources_pt.properties). Para maiores informações, veja o Tutorial Validations Made Easy (há também um rico conjunto de tutoriais para Struts).

Graças ao XDoclet, isto é muito mais fácil - só precisamos adicionar algumas tags @struts.validator à classe Person. Devemos abrir esta classe (src/dao/**/model/Person.java) e modificar os comentários dos métodos getFirstName() e getLastName(), adicionando as tags @struts.validator type="required".


    /**
     * Método de acesso ao atributo firstName
     * @struts.validator type="required"
     * @hibernate.property column="first_name" length="50"
     */
    public String getFirstName() {
        return this.firstName;
    }

    /**
     * Método de acesso ao atributo lastName
     * @struts.validator type="required" 
     * @hibernate.property column="last_name" length="50"
     */
    public String getLastName() {
        return this.lastName;
    }

Podemos também adicionar um atributo msgkey a esta tag para sobreescrever a chave padrão de mensagem para este erro.


@struts.validator type="required" msgkey="errors.required"

A chave padrão para type="required" já é errors.required, então eu comumente deixo como o padrão. Esta chave é definida em web/WEB-INF/classes/ApplicationResources_*.properties. Perceberemos que incluimos estas tags nos métodos de acesso (getters) da classe, mesmo quando a documentação XDoclet diz que devemos colocar as tags nos métodos de modificação (setters). Isto é porque geraremos nossa classe PersonForm.java - o arquivo de template (metadata/template/struts_form.xdt) se encarrega de incluir estas tags nos métodos de modificação (setters) do arquivo gerado.

Agora se salvarmos Person.java e rodarmos ant clean webdoclet, um arquivo validation.xml será gerado em build/appfuse/WEB-INF/. Seu conteúdo deve conter uma entrada para "personForm".


      <form name="personForm">
              <field property="firstName"
                     depends="required">

                  <arg0 key="personForm.firstName"/>
              </field>
              <field property="lastName"
                     depends="required">

                  <arg0 key="personForm.lastName"/>
              </field>
      </form>

A validação do lado cliente é habilitada por padrão no personForm.jsp. Existe uma tag JSP e um script na parte inferior da página que habilita isso. O seguinte código já deve existir (graças ao AppGen) - mas pode ser necessário retirar os comentários se estes foram feitos no último tutorial.

<html:javascript formName="personForm" cdata="false"
    dynamicJavascript="true" staticJavascript="false"/>
<script type="text/javascript" 
    src="<html:rewrite page="/scripts/validator.jsp"/>"></script>
NOTA: Se possuírmos objetos aninhados com regras de validação, estas regras serão pegas e colocadas no arquivo validation.xml. Isto porque uma tag @struts.validator é adicionada ao método de modificação (setter) do objeto aninhado quando o formulário é gerado (utilizando metadata/templates/struts_form.xdt). Se temos um relacionamento bidirecional muitos para muitos entre objetos, este relacionamento pode nos causar transtornos. Existem duas soluções para consertar isto. A primeira é removermos a tag @struts.validator do template struts_form.xdt e adicionar manualmente no método de modificação (setter) do nosso POJO. A segunda solução é descrita aqui.

Veja o JSP com a validação com a validação adicionada e teste [#2]

Agora que possuímos a validação configurada para este formulário, estas regras serão aplicadas toda vez que este formulário for utilizado em um action-mapping com validate="true". No tutorial anterior, adicionamos o action-mapping "savePerson" para a classe PersonAction. As tags XDoclet para este action-mapping eram:


 * @struts.action name="personForm" path="/savePerson" scope="request"
 *  validate="true" parameter="method" input="edit"

Então agora, contanto que nosso web/pages/personForm.jsp possua um <html:form action="savePerson">, a validação deve ser realizada quando tentarmos salvar este formulário. Rodaremos ant db-load deploy, inicie o Tomcat (ou ant db-load deploy start.tomcat para simplificar) e vá para http://localhost:8080/appfuse/editPerson.html?id=1.

Se apagarmos os valores nos campos firstName e lastName, e clicarmos o botão Salvar, devemos receber o seguinte alerta Javascript:

validation-required.png

Para nos certificarmos que tudo está realmente executando como esperamos, podemos desligar Javascript para provar que a validação do lado do servidor está funcionando. Isto é relativamente simples no Mozilla Firebird (meu browser favorito), apenas vá em Ferramentas(Tools) → Opções (Options) → Facilidades (Web Features) and uncheck "Permitir Javascript" ("Enable JavaScript"). Agora se limparmos os campos e salvarmos formulário, devemos ver o seguinte:

validation-required-nojs.png

Se não forem mostrados os erros de validação, podem haver algumas possibilidades:

  • O formulário salva com a mensagem de sucesso, mas os campos firstName e lastName estão em branco.
Isto é porque o <html:form> na página web/pages/personForm.jsp possui action="editPerson" - certifique-se que ele contenha action="savePerson".
  • Clicamos em "Salvar", mas uma página em branco apareceu.
A página em branco indica que o atributo de "entrada" de nosso envio "savePerson" está configurada erroneamente. Devemos nos certificar que ele esteja relacionado com um action-forward local ou global. Neste exemplo, ele deve ser input="edit", que aponta para a definição de .personDetail. Por experiência própria, um valor de entrada deve ser um envio, não um caminho para uma action.
Se desejarmos apenas validação do lado servidor (sem Javascript), podemos remover o atributo onsubmit do <html:form> (em web/pages/personForm.jsp) assim como as tags de validação Javascript no final da página.


<html:javascript formName="personForm" cdata="false"
      dynamicJavascript="true" staticJavascript="false"/>
<script type="text/javascript" 
      src="<html:rewrite page="/scripts/validator.jsp"/>"></script>

Adicione métodos testGetPeople nos testes DAO e Manager [#3]

Para criarmos uma tela de listagem (também chamada uma tela mestre), devemos criar métodos que retornarão todas as tuplas de nossa tabela person. Vamos começar adicionando os métodos de teste às nossas classes PersonDaoTest e PersonManagerTest. Geralmente nomeio este método getEntidades (i.e. getUsers), mas podemos também utilizar getAll ou search - isto é realmente uma questão de preferência pessoal.

Abra o arquivo test/dao/**/dao/PersonDaoTest.java e adicione o método testGetPeople:


    public void testGetPeople() {
        person = new Person();
        List results = dao.getPeople(person);
        assertTrue(results.size() 0);
    }

A razão pela qual passamos um objeto person ao método getPeople é para permitir filtragem (baseado nos atributos do person) no futuro. Adicionando este parâmetro na assinatura de nosso método getPeople() é opcional, mas o resto do tutorial assume que fizemos isto.

Agora abra o arquivo test/service/**/service/PersonManagerTest.java e adicione um método testGetPeople:


    public void testGetPeople() throws Exception {
        List results = new ArrayList();
        person = new Person();
        results.add(person);

        // seta o comportamento esperado do DAO
        personDao.expects(once()).method("getPeople")
            .will(returnValue(results));

        List people = personManager.getPeople(null);
        assertTrue(people.size() == 1);
        personDao.verify();
    }

Para estes testes compilarem, devemos adicionar o método getPeople() às interfaces PersonDao e PersonManager, assim como a suas implementações.

Adicione métodos getPeople para PersonDao e PersonManager [#4]

Abra o arquivo src/dao/**/dao/PersonDao.java e adicione a assinatura do método getPeople():


    public List getPeople(Person person);

Agora devemos adicionar a mesma assinatura de método ao arquivo src/service/**/service/PersonManager.java. Devemos salvar todos os arquivos e ajustar os imports em nossos testes. Após isso, devemos implementar o método getPeople() em nossas classes de implementação. Abra o arquivo src/dao/**/dao/hibernate/PersonDaoHibernate.java e adicione o seguinte método:


    public List getPeople(Person person) {
        return getHibernateTemplate().find("from Person");
    }

Devemos notar que nada está sendo feito com o parâmetro person. Este parâmetro não está sendo utilizado ainda como filtro - no futuro talvez necessitemos executar este filtro utilizando Hibernate's Query Language - HQL ou utilizando Criteria Queries.

Um exemplo utilizando Criteria Query:


    // filtra as propriedades no objeto person
    HibernateCallback callback = new HibernateCallback() {
        public Object doInHibernate(Session sessionthrows HibernateException {
            Example ex = Example.create(person).ignoreCase().enableLike(MatchMode.ANYWHERE);
            return session.createCriteria(Person.class).add(ex).list();
        }
    };
    return (ListgetHibernateTemplate().execute(callback);

Agora devemos implementar o método getPeople() no arquivo src/service/**/impl/PersonManagerImpl.java:


    public List getPeople(Person person) {
        return dao.getPeople(person);
    }

Após salvarmos todas as modificações, poderemos rodar ambos os testes executando os seguintes comandos:

  • ant test-dao -Dtestcase=PersonDao
  • ant test-service -Dtestcase=PersonManager

Se tudo funcionar - Bom Trabalho! Devemos agora adicionar a funcionalidade de recuperar todos à camada web.

Adicione o método testSearch ao teste da Action [#5]

Devemos abrir o arquivo test/web/**/action/PersonActionTest.java e adicionar o seguinte método:


    public void testSearch() {
        setRequestPathInfo("/editPerson");
        addRequestParameter("method""Search");
        actionPerform();

        verifyForward("list");

        assertNotNull(getRequest().getAttribute(Constants.PERSON_LIST));
        verifyNoActionErrors();
    }

Esta classe não compilará até que adicionemos a variável PERSON_LIST ao arquivo src/dao/**/Constants.java.

Geralmente eu copio uma variável similar que já existe no arquivo - i.e. USER_LIST.


    /**
     * O atributo de escopo de requisição que contém a lista de pessoas
     */
    public static final String PERSON_LIST = "personList";

Agora devemos salvar todas as nossas modificações. Não seremos capazes de rodar ant test-web -Dtestcase=PersonAction ainda porque o método PersonAction.search() não existe (ainda).

Adicione o método search à Action [#6]

Abra o arquivo src/web/**/action/PersonAction.java e adicione a seguinte tag XDoclet na parte superior - para mapearmos um envio à nossa tela de listagem.


 * @struts.action-forward name="list" path="/WEB-INF/pages/personList.jsp"

Agora devemos adicionar o método de pesquisa ao corpo da classePersonAction.

Utilizei UserAction.search() como um template para este método.


    public ActionForward search(ActionMapping mapping, ActionForm form,
                                HttpServletRequest request,
                                HttpServletResponse response)
            throws Exception {
        if (log.isDebugEnabled()) {
            log.debug("Entrando no método 'search'");
        }

        PersonManager mgr = (PersonManagergetBean("personManager");
        List people = mgr.getPeople(null);
        request.setAttribute(Constants.PERSON_LIST, people);

        // retorna um envio à definição da lista de pessoas
        return mapping.findForward("list");
    }

Rode ant test-web -Dtestcase=PersonAction.

Nice! BUILD SUCCESSFUL
Total time: 1 minute 26 seconds

Crie personList.jsp e seu teste Canoo [#7]

Devemos abrir o arquivo personList.jsp em web/pages. Na parte superior do arquivo existe uma tag <bean:struts> que expõe o envio à tela de edição como uma variável de escopo de página. Esta variável já deve estar com o valor de "editPerson".


<%-- Para ligar com a tela de edição --%>
<bean:struts id="editURL" forward="editPerson"/>

Adicione o seguinte conteúdo ao arquivo metadata/web/global-forwards.xml, contendo envios globais tanto para a tela de edição quanto para a tela de listagem. Desta forma, eles serão incluídos em nosso arquivo struts-config.xml.


        <forward name="editPerson" path="/editPerson.html"/>
        <forward name="viewPeople" path="/editPerson.html?method=Search"/>

Outra coisa que provavelmente devemos mudar é o plural dos itens que estamos listando. O nome gerado no exemplo é "persons" e provavelmente deve ser pessoas (ou people, se estiver utilizando i18n). Perto ou na linha 31, devemos ter a seguinte linha:

<display:setProperty name="paging.banner.items_name" value="persons"/>

Devemos mudar para:

<display:setProperty name="paging.banner.items_name" value="pessoas"/>

Finalmente, devemos adicionar as chaves de título e de cabeçalho (personList.title e personList.heading) ao arquivo web/WEB-INF/classes/ApplicationResources.properties (no nosso caso, web/WEB-INF/classes/ApplicationResources_pt.properties). Devemos abrir este arquivo e adicionar o seguinte:

# -- página da lista de pessoas --
personList.title=Lista de Pessoas
personList.heading=Todas as Pessoas

Como um lembrete, o personList.title é o que está na barra de título do navegador (a tag <title>) e personList.heading será colocado em uma tag <h1> antes de qualquer conteúdo da página.

Neste ponto, já seremos capazes de rodar ant clean deploy, iniciar o Tomcat e ver a página no navegador em http://localhost:8080/appfuse/editPerson.html?method=Search.

Agora que temos uma tela de listagem, vamos mudar as páginas que são mostradas após adicionar e remover uma nova pessoa. Em src/web/**/action/PersonAction.java, devemos mudar o mapping.findForward("mainMenu") nos métodos save, delete e cancel para:


    return mapping.findForward("viewPeople");

Devemos também modificar verifyForward("mainMenu") para verifyForward("viewPeople") no método testRemove do arquivo test/web/**/action/PersonActionTest.java. Por último, os testes Canoo "AddPerson" e "DeletePerson" devem ser atualizados. Devemos abrir o arquivo test/web/web-tests.xml e modificar a seguinte linha do alvo (target) "AddPerson":

<verifytitle description="O Menu Principal aparece se o save ocorreu com sucesso" 
    text=".*${mainMenu.title}.*" regex="true"/>

para:

<verifytitle description="A lista de pessoas aparece se salvou com sucesso" 
    text=".*${personList.title}.*" regex="true"/>

E no alvo (target) "DeletePerson", devemos mudar as seguintes linhas:

<verifytitle description="mostra o Menu Principal" 
    text=".*$(mainMenu.title}.*" regex="true"/>

para:

<verifytitle description="mostra a Lista de Pessoas" text=".*${personList.title}.*" regex="true"/>

Utilizamos "viewPeople" ao invés de "list" para que o método de pesquisa seja executado, ao invés de simplesmente enviar para a página personForm.jsp (que o envio "list" aponta).

Para testar esta página, devemos criar um novo teste JSP no arquivo test/web/web-tests.xml:


    <!-- Verifica se a tela de listagem de pessoas aparece sem erros -->
    <target name="SearchPeople" 
        description="Testa a procura e mostra todas as pessoas">
        <webtest name="searchPeople">
            &config;
            <steps>
                &login;

                <invoke description="clicando no link Mostrar Pessoas" url="/editPerson.html?method=Search"/>
                <verifytitle description="devemos ver o título da lista de pessoas" 
                    text=".*${personList.title}.*" regex="true"/>
            </steps>
        </webtest>
    </target>

Devemos também adicionar o alvo (target) "SearchPeople" ao alvo "PersonTests" para que ele seja executado juntamente com os outros testes relacionados à pessoa.


    <!-- roda os testes relacionados à pessoa -->
    <target name="PersonTests" 
        depends="SearchPeople,EditPerson,SavePerson,AddPerson,DeletePerson"
        description="Chama e executa todos os casos de teste (targets) relacionados à pessoa">
        <echo>Rodou todos os testes JSP de Pessoa com sucesso!</echo>
    </target>

Agora podemos rodar ant test-canoo -Dtestcase=SearchPeople (ou ant test-jsp se o Tomcat não está rodando) e se tudo der certo isto resultará em um "BUILD SUCCESSFUL". Se este foi o resultado - bom trabalho!!

Adicione o link ao menu [#8]

O último passo é fazer as funções de listagem, adição, edição e remoção visíveis ao usuário. O meio mais simples é adicionar um novo link para a lista de links no arquivo web/pages/mainMenu.jsp: NOTA: Os outros links em mainMenu.jsp não utilizam então o JSP pode ser compartilhado entre os vários frameworks web existentes no appfuse (i.e. como o Spring MVC e o WebWork).


    <li>
        <html:link forward="viewPeople">
            <fmt:message key="menu.viewPeople"/>
        </html:link>
    </li>

Onde menu.viewPeople é uma entrada em web/WEB-INF/classes/ApplicationResources.properties (no nosso caso, web/WEB-INF/classes/ApplicationResources_pt.properties).

menu.viewPeople=Mostrar Pessoas

A outra (mais eficiente) alternativa é que adicionemos isto ao menu. Para fazê-lo, devemos adicionar o seguinte conteúdo ao arquivo web/WEB-INF/menu-config.xml:


<Menu name="PeopleMenu" title="menu.viewPeople" forward="viewPeople"/>

Devemos nos certificar que o XML acima esteja dentro da tag <Menus>, mas não dentro de outra tag <Menu>. Então devemos adicionar este novo menu à página web/common/menu.jsp - a qual deve agora estar da seguinte forma:


<%@ include file="/common/taglibs.jsp"%>

<div id="menu">
<menu:useMenuDisplayer name="ListMenu" permissions="rolesAdapter">
    <menu:displayMenu name="AdminMenu"/>
    <menu:displayMenu name="UserMenu"/>
    <menu:displayMenu name="PeopleMenu"/>
    <menu:displayMenu name="FileUpload"/>
    <menu:displayMenu name="FlushCache"/>
    <menu:displayMenu name="Clickstream"/>
</menu:useMenuDisplayer>
</div>

Agora se rodarmos ant clean deploy , iniciarmos o Tomcat e acessarmos http://localhost:8080/appfuse/mainMenu.html, veremos algo como a tela abaixo.

new-menu-item.png

Devemos notar que existe um novo link do lado esquerdo (do mainMenu.jsp) e do lado direito no nosso menu (from menu.jsp).

É isso!

Você completou o ciclo de vida completo de desenvolvimento de um conjunto de páginas master-detail com o AppFuse e Struts - Parabéns! Agora o teste real é se você puder rodar todos os testes em sua aplicação sem falhas. Para testar, pare o Tomcat e rode ant clean test-all. Isto rodará todos os testes unitários de seu projeto. Como um lembrete, é fácil de instalar e testar o Appfuse do zero utilizando ant setup-db setup-tomcat test-all. Ainda assim, se você estiver procurando exemplos mais robustos, veja o Struts Resume.

Tena um Bom Dia!

BUILD SUCCESSFUL
Total time: 2 minutes 31 seconds

Attachments:


Go to top   Edit this page   More info...   Attach file...
This page last changed on 06-Nov-2006 13:53:00 MST by RafaelNami.