Skip to content

5. Formularios dinámicos con restricciones de integridad

Ahora vamos a desarrollar una nueva aplicación llamada strutspersonne2 que utiliza

  • un formulario dinámico como en strutspersonne1
  • un archivo de declaración de restricciones de integridad que deben verificar los campos de este formulario dinámico

5.1. Declaración de restricciones de integridad

La clase utilizada para almacenar los valores «nombre» y «edad» de la aplicación strutspersonne1 se declaraba de la siguiente manera:

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

Tuvimos que crear la clase PersonneDynaForm para disponer de un método validate capaz de verificar que los valores «nombre» y «edad» del formulario dinámico fueran válidos. Las verificaciones a realizar eran de dos tipos:

  • los dos campos debían estar rellenos
  • el campo «edad» debía verificar la máscara (expresión regular) \s*\d+\s*

Estas dos comprobaciones forman parte de las que puede realizar el entorno StrutsValidator. Este entorno viene con Struts e incluye una serie de clases que se encuentran en commons-validator.jar y jakarta-oro.jar. Si ha seguido el procedimiento, explicado al principio del documento, para instalar las bibliotecas de Struts en Tomcat, estas bibliotecas ya están disponibles en Tomcat. Asegúrese de que también lo estén en JBuilder. Esto también se ha explicado al principio del documento.

La nueva declaración del formulario en struts-config.xml queda así:

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

Por lo tanto, hay muy poca diferencia. La clase asociada al formulario dinámico es ahora una clase predefinida de StrutsValidator: org.apache.struts.validator.DynaValidatorForm. El desarrollador ya no tiene que escribir ninguna clase. Especifica las restricciones de integridad que debe verificar el formulario en un archivo XML independiente. El controlador Struts debe conocer el nombre de este archivo. Para ello, aparece una nueva sección de configuración en el archivo struts-config.xml:

    <plug-in className="org.apache.struts.validator.ValidatorPlugIn">
        <set-property 
        property="pathnames" 
      value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"
    />
    </plug-in>

La sección <plug-in> sirve para cargar una clase externa a Struts. Su atributo principal es classname, que indica el nombre de la clase que se va a instanciar. Es posible que el objeto instanciado necesite inicializarse. Esto se hace mediante las etiquetas set-property, que tienen dos atributos:

  • property: el nombre de la propiedad que se va a inicializar
  • value: el valor de la propiedad

En este caso, la clase DynaValidatorForm necesita conocer dos datos:

  • el archivo XML, que define las restricciones de integridad estándar que la clase sabe verificar.
  • el archivo XML que define las restricciones de integridad de los diferentes formularios dinámicos de la aplicación

Esta información la proporciona aquí la propiedad pathnames. El valor de esta propiedad es una lista de archivos XML que el validador cargará:

  • validator-rules.xml es el archivo que define las restricciones de integridad estándar. Se incluye con Struts. Se encuentra en <struts>\lib junto con su archivo de definición DTD:

Image

  • validation.xml define las restricciones de integridad de los distintos formularios dinámicos de la aplicación. Lo crea el desarrollador. Su nombre es libre.

Estos dos archivos pueden colocarse en cualquier lugar bajo WEB-INF. En nuestro ejemplo, se colocarán directamente bajo WEB-INF:

Image

5.2. Escritura de las restricciones de integridad de los formularios dinámicos

El archivo validation.xml contendrá nuestras restricciones de integridad para los campos nombre y edad del formulario frmPersonne de tipo org.apache.struts.validator.DynaValidatorForm. Su contenido es el siguiente:

<form-validation>
    <global>
      <constant>
        <constant-name>entierpositif</constant-name>
        <constant-value>^\s*\d+\s*$</constant-value>
    </constant>
  </global>      
    <formset>
        <form name="frmPersonne">
          <field property="nom" depends="required">
             <arg0 key="personne.nom"/>      
          </field>
          <field property="age" depends="required,mask">            
             <arg0 key="personne.age"/>      
              <var>
                  <var-name>mask</var-name>
                  <var-value>${entierpositif}</var-value>
              </var>
          </field>
    </form>
    </formset>
</form-validation>    

Las reglas de escritura que deben respetarse son las siguientes:

  • todas las reglas se encuentran dentro de una etiqueta <form-validation>
  • la etiqueta <global> sirve para definir información de alcance global, c.a.d. Válida para todos los formularios si hay varios. Aquí hemos puesto constantes en <global>. Una constante se define por su nombre (etiqueta <constant-name>) y su valor (etiqueta <constant-value>). Definimos la constante «entierpositif» con el valor de la expresión regular que debe cumplir un número entero positivo: ^\s*\d+\s*$ (una secuencia de dígitos precedida y/o seguida de espacios).
  • La etiqueta <formset> define el conjunto de formularios para los que hay restricciones de integridad que verificar
  • La etiqueta <form name="unFormulaire"> sirve para definir las restricciones de integridad de un formulario concreto, aquel cuyo nombre viene dado por el atributo name. Este nombre debe existir en la lista de formularios definidos en struts-config.xml. En este caso, el formulario frmPersonne utilizado se define en struts-config.xml mediante la siguiente sección:
    <form-beans>
        <form-bean name="frmPersonne" type="org.apache.struts.validator.DynaValidatorForm">
            <form-property name="nom" type="java.lang.String" initial=""/>
            <form-property name="age" type="java.lang.String" initial=""/>
        </form-bean>            
  • Una etiqueta <form> contiene tantas etiquetas <field> como restricciones de integridad que se deben verificar en el formulario. Una etiqueta <field> tiene los siguientes atributos:
    • property: nombre del campo del formulario para el que se definen las restricciones de integridad
    • depends: lista de restricciones de integridad que se deben verificar.
      • Las restricciones posibles son las siguientes: required (el campo no debe estar vacío), mask (el valor del campo debe corresponder a una expresión regular definida por la variable mask), integer: el valor del campo debe ser un entero, byte (byte), long (entero long), float (real simple), double (real doble), short (entero corto), date (el valor del campo debe ser una fecha válida), range (el valor del campo debe estar dentro de un intervalo determinado), email: (el valor del campo debe ser una dirección de correo electrónico válida), ...
      • Las restricciones de integridad se comprueban en el orden del atributo depends. Si no se cumple una restricción, no se comprueban las siguientes.
      • Cada restricción está vinculada a un mensaje de error definido por una clave. A continuación se muestran algunas de ellas en el formato restricción (clave): required (errors.required), mask (errors.invalid), integer (errors.integer), byte (errors.byte), long (errors.long), ...
      • los mensajes de error asociados a las claves anteriores se definen en el archivo validator-rules.xml:
   # Struts Validator Error Messages
   errors.required={0} is required.
   errors.minlength={0} can not be less than {1} characters.
   errors.maxlength={0} can not be greater than {1} characters.
   errors.invalid={0} is invalid.

   errors.byte={0} must be a byte.
   errors.short={0} must be a short.
   errors.integer={0} must be an integer.
   errors.long={0} must be a long.
   errors.float={0} must be a float.
   errors.double={0} must be a double.

   errors.date={0} is not a date.
   errors.range={0} is not in the range {1} through {2}.
   errors.creditcard={0} is an invalid credit card number.
   errors.email={0} is an invalid e-mail address.
  • Como vemos arriba, los mensajes están en inglés. Además, aparecen como comentarios en el archivo, donde se indica que deben colocarse en el archivo de mensajes de la aplicación. Recordemos que este se define en una sección del archivo struts-config.xml:
    <message-resources 
      parameter="ressources.personneressources"
    null="false"
  />    

El atributo «parameter» indica que los mensajes de la aplicación se encuentran en el archivo

WEB-INF/classes/ressources/personneressources.properties.

Por lo tanto, los mensajes de error deben colocarse en este archivo. Se añaden a los que ya existen:

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 est incorrect</li>
errors.header=<ul>
errors.footer=</ul>

   # Mensajes de error de Struts Validator
    # la clave está predefinida y no debe modificarse
    # el mensaje de error asociado es libre
    # el mensaje puede tener hasta 4 parámetros {0} a {3}

   errors.required=<li>Le champ [{0}] doit être renseigné.</li>
   errors.minlength=<li>Le champ [{0}] foit avoir au moins {1} caractère.</li>
   errors.maxlength=<li>Le champ [{0}] ne peut avoir plus de {1} caractères.</li>
   errors.invalid=<li>Le champ [{0}] est incorrect.</li>

   errors.byte=<li>{0} doit être un octet.</li>
   errors.short=<li>{0} doit être un entier court.</li>
   errors.integer=<li>{0} doit être un entier.</li>
   errors.long=<li>{0} doit être un entier long.</li>
   errors.float=<li>{0} doit être un réel simple.</li>
   errors.double=<li>{0} doit être un réel double.</li>

   errors.date=<li>{0} n'est pas une date valide.</li>
   errors.range=<li>{0} doit être dans l'intervalle {1} à {2}.</li>
   errors.creditcard=<li>{0} n'est pas un numéro de carte valide.</li>
   errors.email=<li>{0} n'est pas une adresse électronique valide.</li>

   personne.nom=nom
     personne.age=age

Analicemos una por una las restricciones de integridad del archivo validation.xml para explicarlas:

    <formset>
        <form name="frmPersonne">
          <field property="nom" depends="required">
             <arg0 key="personne.nom"/>      
          </field>
...
    </form>
    </formset>

Recordemos que estas restricciones de integridad se aplican a los campos «nombre» y «edad» de un formulario dinámico definido en struts-config.xml:

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

Es importante que los nombres del formulario y de sus campos sean idénticos en ambos archivos. La restricción de integridad del campo «nombre» (property="nombre") indica que el campo no debe estar vacío (depends="required"). Si no es así, se generará un objeto ActionError con la clave errors.required. El mensaje asociado a esta clave se encuentra en el archivo personne.ressources.properties:

   errors.required=<li>Le champ [{0}] doit être renseigné.</li>

Se observa que este mensaje utiliza un parámetro {0}. El valor de este se establece mediante la etiqueta <arg0> de la restricción de integridad:

             <arg0 key="personne.nom"/>      

Una vez más, arg0 se designa mediante una clave que también se encuentra en el archivo de mensajes:

   personne.nom=nom

Si unimos todo esto, el mensaje de error generado si el campo «nombre» no está rellenado es:

<li>Le champ [nom] doit être renseigné.</li>

Analicemos ahora la segunda restricción, la del campo «age»:

    <global>
      <constant>
        <constant-name>entierpositif</constant-name>
        <constant-value>^\s*\d+\s*$</constant-value>
    </constant>
  </global>      
    <formset>
        <form name="frmPersonne">
...
          <field property="age" depends="required,mask">            
             <arg0 key="personne.age"/>      
              <var>
                  <var-name>mask</var-name>
                  <var-value>${entierpositif}</var-value>
              </var>
          </field>
    </form>
    </formset>

Hay dos restricciones para el campo «age»: «required» y «mask». Podemos repetir la explicación anterior para la restricción «required». El resultado es que el mensaje de error asociado a esta restricción será:

<li>Le champ [age] doit être renseigné.</li>

La segunda restricción es mask. Esto significa que el contenido del campo debe corresponder a un patrón expresado mediante una expresión regular. El valor de esta última se define en una etiqueta <var> que define una variable con el nombre mask (<var-name>) cuyo valor es ${entierpositif} (<var-value>).entierpositif es una constante definida en la sección <global> del archivo con el valor de la expresión regular ^\s*\d+\s*$. Por lo tanto, la restricción de integridad es que la edad debe ser una secuencia de uno o varios dígitos, eventualmente precedida o seguida de espacios. Si no se cumple esta restricción, se generará un objeto ActionError con la clave errors.invalid. En el archivo de mensajes, esta clave se asocia al siguiente mensaje:

   errors.invalid=<li>Le champ [{0}] est incorrect.</li>

La restricción debe definir un valor para el parámetro {0}. Lo hace con la etiqueta <arg0>:

             <arg0 key="personne.age"/>      

En el archivo de mensajes, la clave personne.age está asociada al siguiente mensaje:

     personne.age=age

El mensaje de error que se generará si no se cumple la restricción mask es, por lo tanto:

<li>Le champ [age] est incorrect.</li>

5.3. Las clases de la aplicación

En una aplicación Struts, las clases que hay que escribir son las de los formularios (ActionForm o derivada) y las de las acciones (Action o derivada). En la nueva aplicación strutspersonne2 ya no hay ninguna clase para el formulario. El contenido del formulario se define en struts-config.xml y las restricciones de integridad asociadas en WEB-INF/validation.xml. En la aplicación strutspersonne1, la clase FormulaireAction de procesamiento del formulario era la siguiente:

package istia.st.struts.personne;

....

public class FormulaireAction
  extends Action {
  public ActionForward execute(ActionMapping mapping, ActionForm form,
                               HttpServletRequest request, HttpServletResponse response) throws IOException,
    ServletException {
     // tenemos un formulario válido; de lo contrario, no habríamos llegado hasta aquí
    DynaActionForm formulaire=(DynaActionForm)form;
    request.setAttribute("nom",formulaire.get("nom"));
    request.setAttribute("age",formulaire.get("age"));
    return mapping.findForward("reponse");
  }//execute
}

La clase FormulaireAction esperaba recibir un formulario en forma de objeto DynaActionForm (código entre corchetes). Sin embargo, en el archivo struts-config.xml, la clase del formulario se define de la siguiente manera:

        <form-bean name="frmPersonne" type="org.apache.struts.validator.DynaValidatorForm">
...
        </form-bean>            

Por lo tanto, el formulario se colocará en un objeto de tipo DynaValidatorForm. Resulta que esta clase deriva de la clase DynaActionForm. El método execute de nuestra clase FormulaireAction sigue siendo válido. No es necesario reescribirlo.

5.4. Implementación y prueba de la aplicación strutspersonne2

5.4.1. Creación del contexto

Hemos llamado a esta nueva aplicación strutspersonne2. Creamos una nueva definición en el archivo <tomcat>\conf\serveur.xml de Tomcat 4.x:

                <Context path="/strutspersonne2" docBase="e:/data/serge/web/struts/personne2" />

Una vez hecho esto, hay que reiniciar Tomcat. Se puede comprobar la validez del contexto solicitando el URL:

http://localhost:8080/strutspersonne2/

Image

5.4.2. Las vistas

Copiaremos la carpeta «vues» de la aplicación strutspersonne1 a la carpeta de la aplicación strutspersonne2. De hecho, las vistas no han cambiado.

Image

5.4.3. La carpeta WEB-INF

Copiaremos la carpeta WEB-INF de la aplicación strutspersonne1 a la carpeta de la aplicación strutspersonne2. Algunos archivos cambian:

Image

El archivo de configuración struts-config.xml queda así:

<?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="org.apache.struts.validator.DynaValidatorForm">
            <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"
            validate="true"
            input="/erreurs.do"
            scope="session"
          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"
    null="false"
  />    

    <plug-in className="org.apache.struts.validator.ValidatorPlugIn">
        <set-property 
        property="pathnames" 
      value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"
    />
    </plug-in>

</struts-config>

Este archivo es idéntico al de la aplicación strutspersonne1, salvo por la definición dinámica del formulario y la inserción del plugin de validación (partes enmarcadas).

Se añade en WEB-INF el siguiente archivo de validación validation.xml:

<form-validation>
    <global>
      <constant>
        <constant-name>entierpositif</constant-name>
        <constant-value>^\s*\d+\s*$</constant-value>
    </constant>
  </global>      
    <formset>
        <form name="frmPersonne">
          <field property="nom" depends="required">
             <arg0 key="personne.nom"/>      
          </field>
          <field property="age" depends="required,mask">            
             <arg0 key="personne.age"/>      
              <var>
                  <var-name>mask</var-name>
                  <var-value>${entierpositif}</var-value>
              </var>
          </field>
    </form>
    </formset>
</form-validation>

Se añaden a WEB-INF los archivos validator-rules.xml y validator-rules_1_1.dtd, que se encuentran en <struts>\lib:

Image

En la carpeta WEB-INF/classes, solo queda una clase:

Image

En la carpeta WEB-INF\classes\ressources, se encuentra el siguiente archivo de mensajes personneressources.properties:

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 est incorrect</li>
errors.header=<ul>
errors.footer=</ul>

   # Mensajes de error de Struts Validator
    # la clave está predefinida y no debe modificarse
    # el mensaje de error asociado es libre
    # el mensaje puede tener hasta 4 parámetros {0} a {3}

   errors.required=<li>Le champ [{0}] doit être renseigné.</li>
   errors.minlength=<li>Le champ [{0}] foit avoir au moins {1} caractère.</li>
   errors.maxlength=<li>Le champ [{0}] ne peut avoir plus de {1} caractères.</li>
   errors.invalid=<li>Le champ [{0}] est incorrect.</li>

   errors.byte=<li>{0} doit être un octet.</li>
   errors.short=<li>{0} doit être un entier court.</li>
   errors.integer=<li>{0} doit être un entier.</li>
   errors.long=<li>{0} doit être un entier long.</li>
   errors.float=<li>{0} doit être un réel simple.</li>
   errors.double=<li>{0} doit être un réel double.</li>

   errors.date=<li>{0} n'est pas une date valide.</li>
   errors.range=<li>{0} doit être dans l'intervalle {1} à {2}.</li>
   errors.creditcard=<li>{0} n'est pas un numéro de carte valide.</li>
   errors.email=<li>{0} n'est pas une adresse électronique valide.</li>

   personne.nom=nom
  personne.age=age

Image

5.5. Pruebas

Estamos listos para las pruebas. A continuación se incluyen algunas capturas de pantalla que el lector puede reproducir.

Se solicita el URL http://localhost:8080/strutspersonne2/formulaire.do :

Image

Se utiliza el botón [Envoyer] sin rellenar los campos:

Image

Volvemos a intentarlo con un error en el campo «edad»:

Image

Se obtiene la siguiente respuesta:

Image

Volvemos a intentarlo, esta vez introduciendo los valores correctos:

Image

Se obtiene la siguiente respuesta:

Image

5.6. Conclusión

Hemos demostrado que el uso de formularios dinámicos en los que las restricciones de integridad son «estándar» evita la creación de clases para representarlos. Si las restricciones de integridad se salen de lo estándar, nos vemos obligados de nuevo a crear clases para verificar estas nuevas restricciones.