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
CreateActions_it




JSPWiki v2.2.33

[RSS]


Hide Menu

ValidationAndList_it


Parte IV: Aggiungere la Validazione ed una Schermata Elenco - Aggiungere una logica di validazione al PersonForm in modo che firstName e lastName siano campi obbligatori ed aggiungere una schermata di elenco per visualizzare tutti i record di tipo person nel database.

Questo tutorial dipende da Parte III: Creare Action e JSP.

Informazioni su questo Tutorial

Questo tutorial ti mostrerà come aggiungere una logica di Validazione (sia lato client che server) all'oggetto PersonForm usando il Validator di Struts. Creeremo anche una schermata di elenco usando la Display Tag Library per visualizzare tutte le persone nel database.
Ti dirò come fare le cose nel Mondo Reale in un testo come questo.

Indice

  • [1] Aggiungi i tag Validator di XDoclet a Person.java
  • [2] Visualizza la JSP con la validazione aggiunta ed effettua un test
  • [3] Aggiungi i metodi testGetPeople ai Test di DAO e Manager
  • [4] Aggiungi i metodi getPeople a PersonDao e Manager
  • [5] Aggiungi il metodo testSearch al Test della Action
  • [6] Aggiungi il metodo search alla Action
  • [7] Crea personList.jsp ed il test Canoo
  • [8] Aggiungi un collegamento al menu

Aggiungi i tag Validator di XDoclet a Person.java [#1]

Per usare il Validator di Struts, normalmente devi scrivere un file validation.xml a mano. Se non stai usando AppFuse, devi anche configurare il Plugin Validator e le chiavi degli errori nel tuo ApplicationResources.properties. Per ulteriori informazioni sull'argomento, vedi il Tutorial Validation Made Easy (c'è anche un ricco insieme di tutorial sul solo Struts).

Grazie ad XDoclet, è molto più semplice - devi solo aggiungere un paio di tag @struts.validator alla classe Person. Apri (src/dao/**/model/Person.java) e modifica i metodi getFirstName() e getLastName() in modo da includere i tag @struts.validator type="required".


    /**
     * @struts.validator type="required"
     * @hibernate.property column="first_name" length="50"
     */
    public String getFirstName() {
        return this.firstName;
    }

    /**
     * @struts.validator type="required" 
     * @hibernate.property column="last_name" length="50"
     */
    public String getLastName() {
        return this.lastName;
    }

Puoi anche aggiungere un attributo msgkey a questo tag per fornire una tua chiave in alternativa a quella di default per il messaggio associato a questo errore.


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

La chiave di default per type="required" è già errors.required, pertanto io di solito la lascio al valore di default. Questa chiave viene specificata in web/WEB-INF/classes/ApplicationResources_*.properties. Come avrai notato, stiamo mettendo questi tag nei getter di questa classe per quanto la documentazione di XDoclet dica di metterli nei setter. Questo perché stiamo generando il nostro PersonForm.java - il file del modello (metadata/template/struts_form.xdt) si preoccupa di mettere questi tag sui setter nel file generato.

Ora se registri Person.java ed esegui ant clean webdoclet, verrà generato un file validation.xml in build/appfuse/WEB-INF/. Il suo contenuto dovrebbe includere una voce per "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>

La validazione lato-client è attivata per default in personForm.jsp. C'è un tag JSP <html:javascript> ed uno script in fondo alla pagina che lo attiva. Ciò che segue dovrebbe esser già presente (grazie ad AppGen) - ma potresti aver bisogno di rimuovere il commento se avevi commentato il blocco nel file nel tutorial precedente.

<html:javascript formName="personForm" cdata="false"
    dynamicJavascript="true" staticJavascript="false"/>
<script type="text/javascript" 
    src="<html:rewrite page="/scripts/validator.jsp"/>"></script>
NOTA: Se hai oggetti innestati con regole di validazione, verrano presi e messi nel validation.xml. Ciò avviene in quanto un tag @struts.validator viene aggiunto al setter dell'oggetto innestato quando viene generato il form (usando metadata/templates/struts_form.xdt). Se hai relazioni molti-a-molti bidirezionali fra oggetti, ciò potrebbe essere un problema. Ci sono due soluzioni per risolvere la questione. La prima è eliminare il tag @struts.validator tag da struts_form.xdt e posizionarlo a mano sul setter nel tuo POJO. La seconda viene descritta qui.

Visualizza la JSP con la validazione aggiunta ed effettua un test [#2]

Ora che hai configurato la Validazione per questo form, ogni volta che questo form viene usato in un action-mapping con validate="true", verranno applicate queste regole. Nell'ultimo tutorial, abbiamo aggiunto l'action-mapping "savePerson" per la PersonAction. I tag XDoclet per questo action-mapping erano:


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

Pertanto ora, se la tua web/pages/personForm.jsp ha un <html:form action="savePerson">, dovrebbe intervenire la validazione ogni volta che proviamo ad inviare questo form. Esegui ant db-load deploy, avvia Tomcat e vai a http://localhost:8080/appfuse/editPerson.html?id=1.

Se cancelli i valori nei campi firstName e lastName e fai clic sul pulsante registra, dovresti ottenere il seguente alert JavaScript.

validation-required.png

Per assicurarti che le cose funzionino davvero come previsto, puoi spegnere JavaScript e verificare se la validazione lato-server sta funzionando. Ciò è semplice in Firefox (il mio browser preferito), basta che vai in Strumenti → Preferenxe → Contenuto e deselezioni "Abilita JavaScript". Ora se cancelli i campi e invii il form, dovresti vedere il messaggio seguente:

validation-required-nojs.png

se non vedi questi errori di validazione, ci sono un paio di possibilità:

  • Il form registra cin un messaggio di successo, ma i campi firstName e lastName sono ora vuoti.
Questo perché l'<html:form> in web/pages/personForm.jsp ha action="editPerson" - controlla che abbia action="savePerson".
  • Fai clic su registra, ma compare una pagina vuota.
La pagina vuota indica che l'attributo "input" del tuo forward "savePerson" non è stato configurato correttamente. Controlla se si riferisca ad un action-forward locale o globale. In questo esempio, dovrebbe essre input="edit", che punta alla definizione del tile .personDetail. Dalla mia esperienza, il valore di input dovrebbe essere un forward, non un path ad una action.
Se vuoi la sola validazione lato server (niente JavaScript), puoi eliminare l'attributo onsubmit da <html:form> (in web/pages/personForm.jsp) come anche i tag JavaScript del Validator in fondo alla pagina.


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

Aggiungi i metodi testGetPeople ai Test di DAO e Manager [#3]

Per creare una schermata di Elenco (chiamata anche schermata master), dobbiamo creare dei metodi che restituiscano tutte le righe dall nostra tabella person. Iniziamo con l'aggiungere i test per questi metodi alle nostre classi PersonDaoTest e PersonManagerTest. Di solito io chiamo questi metodi getEntities (i.e. getUsers), ma potresti usare anche getAll o search - è solo questione di preferenze personali.

Apri test/dao/**/dao/PersonDaoTest.java ed agiungi un metodo testGetPeople:


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

Il motivo per cui sto passando un oggetto person al metodo getPeople è per permettere in futuro di filtrare il risultato (basandomi come criterio sui valori presenti in person). Aggiungere questo parametro alla firma del tuo metodo getPeople() è opzionale, ma il resto di questo tutorial assume tu lo abbia fatto.

Ora apri test/service/**/service/PersonManagerTest.java ed aggiungi un metodo testGetPeople:


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

        // set expected behavior on dao
        personDao.expects(once()).method("getPeople")
            .will(returnValue(results));

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

Affinché questi test compilino, devi aggiungere il metodo getPeople() alle interfacce PersonDao e PersonManager, nonché alle relative implementazioni.

Aggiungi i metodi getPeople a PersonDao e Manager [#4]

Apri src/dao/**/dao/PersonDao.java ed aggiungi la firma del metodo getPeople():


    public List getPeople(Person person);

Ora aggiungi la medesima firma di metodo a src/service/**/service/PersonManager.java. Registra tutti i tuoi file e correggi gli import nei tuoi test. Come passo successivo devi implementare il metodo getPeople() nelle tue classi di implementazione. Apri src/dao/**/dao/hibernate/PersonDaoHibernate.java ed aggiungi il metodo seguente:


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

Noterai qui che che nulla è stato fatto con il parametro person. Per il momento è solo un segnaposto - nel futuro potresti voler filtrare in base alle sue proprità usando il Linguaggio di Query di Hibernate (HQL) o le Query per Criteri.

Un esempio che usa le Query per Criteri:


    // filter on properties set in the person object
    HibernateCallback callback = new HibernateCallback() {
        public Object doInHibernate(Session sessionthrows HibernateException {
            Example ex = Example.create(person).ignoreCase().ignoreZeroes()
                                .enableLike(MatchMode.ANYWHERE);
            return session.createCriteria(Person.class).add(ex).list();
        }
    };
    return (ListgetHibernateTemplate().execute(callback);

Ora implementa il metodo getPeople() in src/service/**/impl/PersonManagerImpl.java:


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

Dopo aver registrato tutte le tue modifiche, dovresti essere in grado di eseguire entrambi i test eseguendo i seguenti comandi:

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

Se funziona tutto - ottimo lavoro! Ore devi aggiungere questa funzionalità di recupera tutto allo strato web.

Aggiungi il metodo testSearch al Test della Action [#5]

Apri test/web/**/action/PersonActionTest.java ed aggiungi il metodo seguente:


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

        verifyForward("list");

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

Questa classe non compilerà finché non aggiungi la variabile PERSON_LIST al file src/dao/**/Constants.java.

Di solito io copio una variabile analoga già esistente in questo file - i.e. USER_LIST.


    /**
     * The request scope attribute that holds the person list
     */
    public static final String PERSON_LIST = "personList";

Ora registra tutte le tue modifiche. Non puoi ancora eseguire ant test-web -Dtestcase=PersonAction in quanto PersonAction.search() non esiste (per il momento).

Aggiungi il metodo search alla Action [#6]

Apri src/web/**/action/PersonAction.java ed aggiungi il seguente tag XDoclet in cima - per impostare il forward alla nostra schermata di elenco.


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

Ora aggiungi il metodo search all'interno dell classe PersonAction.

Ho utilizzato UserAction.search() come modello per questo metodo.


    public ActionForward search(ActionMapping mapping, ActionForm form,
                                HttpServletRequest request,
                                HttpServletResponse response)
            throws Exception {
        if (log.isDebugEnabled()) {
            log.debug("Entering 'search' method");
        }

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

        // return a forward to the person list definition
        return mapping.findForward("list");
    }

Esegui ant test-web -Dtestcase=PersonAction.

Bene! BUILD SUCCESSFUL
Total time: 1 minute 26 seconds

Crea personList.jsp ed il test Canoo [#7]

Apri il file personList.jsp in web/pages. Molto probabilmente vorrai modificare il codice in modo da visualizzare la forma plurale degli elementi che stai elencando. Il nome generato in questo esempio è "persons" e probabilmente sarebbe meglio fosse people. Alla riga 31 o vicino ad essa, dovresti avere la seguente:
<display:setProperty name="paging.banner.items_name" value="persons"/>

Modificala in:

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

Infine, aggiungi le chiavi per titolo ed intestazione (personList.title e personList.heading) a web/WEB-INF/classes/ApplicationResources.properties. Apri questo file ed aggiungi quanto segue:

# -- person list page --
personList.title=Person List
personList.heading=All People

Come promemoria, il personList.title è ciò che finisce nella barra del titolo del tuo browser (il tah <title>) e personList.heading verrà messo in un tag <h1> prima di qualsiasi contenuto della pagina.

A questo punto, dovresti essere in grado di eseguire ant clean deploy, avvia Tomcat e vedi la pagina nel tuo browser su http://localhost:8080/appfuse/editPerson.html?method=Search.

Ora che abbiamo un Schermata Elenco, modifichiamo le pagine che sono visualizzate all'aggiunta di una nuova Person e alla sua eliminazione. In src/web/**/action/PersonAction.java, modifica il mapping.findForward("mainMenu") nei metodi save, delete e cancel in modo che diventi:


    return mapping.findForward("viewPeople");

Devi anche modificare verifyForward("mainMenu") in verifyForward("viewPeople") nel metodo testRemove di test/web/**/action/PersonActionTest.java. Per ultimo, i test Canoo "AddPerson" e "DeletePerson" devono essere aggiornati. Apri test/web/web-tests.xml e modifica la seguente riga nel target "AddPerson":

<verifytitle description="Main Menu appears if save successful" 
    text=".*${mainMenu.title}.*" regex="true"/>

in:

<verifytitle description="Person List appears if save successful" 
    text=".*${personList.title}.*" regex="true"/>

Poi nel target "DeletePerson", modifca la seguente riga:

<verifytitle description="display Main Menu" 
    text=".*$(mainMenu.title}.*" regex="true"/>

in:

<verifytitle description="display Person List" text=".*${personList.title}.*" regex="true"/>

Infine, dichiara il forward viewPeople in metadata/web/global-forwards.xml dopo viewUsers come qui sotto:

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

Il nome "viewPeople" viene usato al posto di "list" in modo che venga eseguito il metodo search, invece di effettuare un semplice forward alla personForm.jsp (cui punta il forward "list").

Per verificare che la visualizzazione di questa pagina funzioni, crea un nuovo test JSP in test/web/web-tests.xml:


    <!-- Verify the people list screen displays without errors -->
    <target name="SearchPeople" 
        description="Tests search for and displaying all people">
        <webtest name="searchPeople">
            &config;
            <steps>
                &login;

                <invoke description="click View People link" url="/editPerson.html?method=Search"/>
                <verifytitle description="we should see the personList title" 
                    text=".*${personList.title}.*" regex="true"/>
            </steps>
        </webtest>
    </target>

Vorrai anche aggiungere il target "SearchPeople" al target "PersonTests" in modo che venga eseguito insieme agli altri test relativi a person.


    <!-- runs person-related tests -->
    <target name="PersonTests" 
        depends="SearchPeople,EditPerson,SavePerson,AddPerson,DeletePerson"
        description="Call and executes all person test cases (targets)">
        <echo>Successfully ran all Person JSP tests!</echo>
    </target>

Ora puoi eseguire ant test-canoo -Dtestcase=SearchPeople (o ant test-jsp se Tomcat non è in esecuzione) e sperabilmente otterrai come risultato un "BUILD SUCCESSFUL". Se è così - ottimo lavoro!

Aggiungi un collegamento al menu [#8]

L'ultimo passo è rendere visibili all'utente le funzioni di elenco, aggiunta, modifica ed eliminazione. Il modo più semplice è aggiungere un nuovo collegamento all'elenco di collegamenti in web/pages/mainMenu.jsp:

NOTA: Gli altri collegamenti in mainMenu.jsp non usano in modo che questa JSP possa essere condivisa fra le varie implementazioni di framework web usate in AppFuse (i.e. Spring MVC e WebWork).


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

Dove menu.viewPeople è una voce nel file web/WEB-INF/classes/ApplicationResources.properties.

menu.viewPeople=View People

Un'alternativa (più probabile) è che tu voglia aggiungere questa voce al menu. Per far questo, aggiungi quanto segue a web/WEB-INF/menu-config.xml:


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

Controlla che l'XML su indicato si trovi all'interno del tag <Menus>, ma non dentro un altro tag <Menu>. Poi aggiungi questo nuovo menu a to web/common/menu.jsp - che ora dovrebbe presentarsi in questo modo:


<%@ 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>

Ora se esegui ant clean deploy, avvi Tomcat e vai a http://localhost:8080/appfuse/mainMenu.html, dovresti vedere qualcosa di simile alla schermata qui sotto.

new-menu-item.png

Nota che c'è un nuovo collegamento sul lato sinistro (da mainMenu.jsp) e sulla destra nel nostro menu (da menu.jsp).

È tutto!

Hai completato il ciclo di sviluppo completo di un insieme di pagine master-detail con AppFuse e Struts - Congratulazioni! Ora il vero test è se sei in grado di eseguire tutti i test nella tua applicazione senza errori. Per verificare, ferma tomcat ed esegui ant clean test-all. Questo target esegure tutti gli unit test nel tuo progetto. Come promemoria, dovrebbe essere semplice impostare e fare un test di AppFuse da zero usando ant setup-db setup-tomcat test-all. Inoltre, se stai cercando degli esempi più corposi - prova a vedere Struts Resume.

Buona Giornata!

BUILD SUCCESSFUL
Total time: 2 minutes 31 seconds

Attachments:


Go to top   Edit this page   More info...   Attach file...
This page last changed on 27-Feb-2007 05:08:26 MST by MarcelloTeodori.