Skip to content

4. Utilisation de formulaires dynamiques

4.1. Déclaration du formulaire dynamique

Nous avons vu que Struts utilisait des objets ActionForm pour stocker les valeurs des formulaires HTML traitées par les différentes servlets de l'application. Pour chaque formulaire de notre application, il nous faut construire une classe dérivée de ActionForm. Ceci peut devenir vite assez lourd puisque pour chaque champ xx, il nout écrire deux méthodes setXx et getXx. Struts nous offre la possibilité d'utiliser des formulaires

  • dont la structure est déclarée dans le fichier struts-config.xml dans la section <form-beans>
  • qui sont créés dynamiquement par l'environnement Struts selon la structure déclarée

Ainsi la classe utilisée pour stocker les valeurs nom et age de l'application strutspersonne pourrait être définie comme suit :

    <form-beans>
        <form-bean name="frmPersonne" type="org.apache.struts.actions.DynaActionForm">
            <form-property name="nom" type="java.lang.String" initial=""/>
            <form-property name="age" type="java.lang.String" initial=""/>
        </form-bean>            
    </form-beans>

Pour chaque champ du formulaire on définit une balise <form-property> avec deux attributs :

  • name : le nom du champ
  • type : son type java

Parce que les valeurs d'un formulaire envoyées par un client web sont des chaînes de caractères, les types les plus usités sont java.lang.String pour les champs à valeur unique et java.lang.String[] pour les champs à valeurs multiples (boîtes à cocher portant le même nom, listes à sélection multiple, ...). La classe DynactionForm comme la classe ActionForm a une méthode validate qui ne fait rien. Pour lui faire vérifier la validité des paramètres du formulaire, il faut la dériver et écrire soi-même la méthode validate. La déclaration du formulaire sera donc la suivante :

    <form-beans>
        <form-bean name="frmPersonne" type="istia.st.struts.personne.PersonneDynaForm">
            <form-property name="nom" type="java.lang.String" initial=""/>
            <form-property name="age" type="java.lang.String" initial=""/>
        </form-bean>            
    </form-beans>

La classe istia.st.struts.personne.PersonneDynaForm devra être écrite par nos soins.

4.2. Écriture de la classe DynaActionForm associée au formulaire dynamique

Ci-dessus, nous avons associé la classe istia.st.struts.personne.PersonneDynaForm au formulaire (nom,age). Nous écrivons maintenant cette classe :

package istia.st.struts.personne;

import javax.servlet.http.*;
import org.apache.struts.action.*;

public class PersonneDynaForm extends DynaActionForm {
  // validation
  public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
    // gestion des erreurs
    ActionErrors erreurs = new ActionErrors();
    // le nom doit être non vide
    String nom = (String)this.get("nom");
    if (nom == null || nom.trim().equals("")) {
      erreurs.add("nomvide", new ActionError("personne.formulaire.nom.vide"));
    }
    // l'âge doit être non vide
    String age = (String)this.get("age");
    if (age == null || age.trim().equals("")) {
      erreurs.add("agevide", new ActionError("personne.formulaire.age.vide"));
    }
    else {
      // l'âge doit être un entier positif
      if (!age.matches("^\\s*\\d+\\s*$")) {
        erreurs.add("ageincorrect", new ActionError("personne.formulaire.age.incorrect", age));
        // on rend la liste des erreurs
      }
    } //if
    // on rend la liste d'erreurs
    return erreurs;
  }
}//classe

Les points à noter sont les suivants :

  • la classe dérive de DynaActionForm
  • la méthode validate de la classe DynaActionForm a été réécrite. Lorsqu'elle est exécutée par le contrôleur Struts, l'objet PersonneDynaForm a été construit. Il contient un dictionnaire ayant pour clés les champs du formulaire nom et age et pour valeurs les valeurs de ces champs. Pour avoir accès à un champ au sein des méthodes de DynaActionForm on utilise la méthode Object get(String nomDuChamp). Si on veut fixer une valeur à un champ, on pourra utiliser la méthode void set(String nomDuChamp, Object valeur). On se reportera à la définition de la classe DynaActionForm pour une définition complète.
  • une fois récupérées les valeurs des champs nom et age du formulaire, la méthode validate ne diffère pas de celle qui avait été écrite lorsque le formulaire était associé à un objet ActionForm.

4.3. La nouvelle classe FormulaireAction

Le fichier de configuration définit l'action /main suivante :

...
    <form-beans>
        <form-bean name="frmPersonne" type="istia.st.struts.personne.PersonneDynaForm">
            <form-property name="nom" type="java.lang.String" initial=""/>
            <form-property name="age" type="java.lang.String" initial=""/>
        </form-bean>            
    </form-beans>
....
      <action
          path="/main"
          name="frmPersonne"
            scope="session"
            validate="true"
            input="/erreurs.do"
          type="istia.st.struts.personne.FormulaireAction"
      >
            <forward name="reponse" path="/reponse.do"/>
        </action>

Cette définition est la même que dans l'application strutspersonne. L'action /main est réalisée par un objet de type FormulaireAction. Cet objet reçevait les valeurs du formulaire frmPersonne dans un objet de type FormulaireBean. Maintenant il les reçoit dans un objet de type PersonneDynaForm. Il faut donc réécrire la classe :

package istia.st.struts.personne;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import javax.servlet.ServletException;
import istia.st.struts.personne.PersonneDynaForm;

public class FormulaireAction extends Action {

  public ActionForward execute(ActionMapping mapping, ActionForm form,
           HttpServletRequest request, HttpServletResponse response) throws IOException,ServletException {

    // on a un formulaire valide, sinon on ne serait pas arrivé là
    PersonneDynaForm formulaire=(PersonneDynaForm)form;
    request.setAttribute("nom",formulaire.get("nom"));
    request.setAttribute("age",formulaire.get("age"));
    return mapping.findForward("reponse");
  }//execute
}

Les points à noter sont les suivants :

  • nous devons importer la classe PersonneDynaForm qui contient les données du formulaire pour avoir accès à sa définition
  • la méthode execute récupère la valeur des paramètres du formulaire avec la méthode [DynaActionForm].get.

Vis à vis de la classe FormulaireAction de l'application strutspersonne, seule la façon d'accéder aux valeurs du formulaire a changé.

4.4. Déploiement et test de l'application strutspersonne1

4.4.1. Création du contexte

Nous avons appelé strutspersonne1 cette nouvelle application. Nous créons une nouvelle définition dans le fichier <tomcat>\conf\serveur.xml de Tomcat 4.x :

    <Context path="/strutspersonne1" docBase="e:/data/serge/web/struts/personne1" />

Ceci fait, il faut relancer Tomcat. On peut vérifier la validité du contexte en demandant l'URL :

http://localhost:8080/strutspersonne1/

Image

4.4.2. Les vues

On copiera le dossier vues de l'application strutspersonne dans le dossier de l'application strutspersonne1. En effet, les vues n'ont pas changé.

Image

4.4.3. Compilation des classes

Nous avons deux classes à créer : PersonneDynaForm et FormulaireAction, la dernière utilisant la première. On pourra les créer et les compiler à l'aide d'un projet Jbuilder :

Image

4.4.4. Le dossier WEB-INF

On copiera le dossier WEB-INF de l'application strutspersonne dans le dossier de l'application strutspersonne1. Quelques fichiers changent :

Image

Le fichier de configuration struts-config.xml devient le suivant :

<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE struts-config PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
          "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">

<struts-config>
    <form-beans>
        <form-bean name="frmPersonne" type="istia.st.struts.personne.PersonneDynaForm">
            <form-property name="nom" type="java.lang.String" initial=""/>
            <form-property name="age" type="java.lang.String" initial=""/>
        </form-bean>            
    </form-beans>

    <action-mappings>
      <action
          path="/main"
          name="frmPersonne"
            scope="session"
            validate="true"
            input="/erreurs.do"
          type="istia.st.struts.personne.FormulaireAction"
      >
            <forward name="reponse" path="/reponse.do"/>
        </action>
      <action
          path="/erreurs"
          parameter="/vues/erreurs.personne.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />
      <action
          path="/reponse"
          parameter="/vues/reponse.personne.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />
      <action
          path="/formulaire"
          parameter="/vues/formulaire.personne.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />
    </action-mappings>

    <message-resources parameter="ressources.personneressources"/>    
</struts-config>

Ce fichier est identique à celui de l'application strutspersonne à l'exception de la définition dynamique du formulaire (partie encadrée).

Dans le dossier WEB-INF/classes, on mettra les classes compilées par Jbuilder :

Image

Dans le dossier WEB-INF\classes\ressources, on place le fichier des messages. Il n'a pas changé.

personne.formulaire.nom.vide=<li>Vous devez indiquer un nom</li>
personne.formulaire.age.vide=<li>Vous devez indiquer un age</li>
personne.formulaire.age.incorrect=<li>L'âge [{0}] est incorrect</li>
errors.header=<ul>
errors.footer=</ul>

Image

4.5. Tests

Nous sommes prêts pour les tests. On trouvera ci-dessous quelques copies d'écran que le lecteur est invité à reproduire.

On demande l'URL http://localhost:8080/strutspersonne1/formulaire.do :

Image

On utilise le bouton [Envoyer] sans remplir les champs :

Image

On recommence avec une erreur sur le champ age :

Image

On obtient la réponse suivante :

Image

On recommence en mettant cette fois-ci des valeurs correctes :

Image

On obtient la réponse suivante :

Image

4.6. Conclusion

L'utilisation de formulaire dynamiques facilite l'écriture des classes de type ActionForm chargées de stocker les valeurs des formulaires. On peut aller un peu plus loin dans la simplification de la gestion des formulaires. Dans l'application strutspersonne1, nous avons créé une classe PersonneDynaForm pour vérifier la validité des valeurs (nom,age) du formulaire. Dans la pratique, certaines vérifications reviennent fréquemment : champ non vide, champ vérifiant une certaine expression régulière, champ entier, champ date, ... Ce type de vérification standard peut alors être demandé dans le fichier de configuration struts-config.html. Si toutes les vérifications à faire sont "standard", alors il n'y a plus de classe à écrire pour le formulaire. C'est ce que nous voyons maintenant.