Skip to content

5. Formulários dinâmicos com restrições de integridade

Vamos agora desenvolver um novo aplicativo chamado strutspersonne2 utilizando

  • um formulário dinâmico, como no strutspersonne1
  • um arquivo de declaração de restrições de integridade a serem verificadas pelos campos desse formulário dinâmico

5.1. Declaração das restrições de integridade

A classe utilizada para armazenar os valores “nome” e “idade” da aplicação strutspersonne1 foi declarada da seguinte forma:

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

Tivemos que criar a classe PersonneDynaForm para dispor de um método de validação capaz de verificar se os valores “nome” e “idade” do formulário dinâmico eram válidos. As verificações a serem realizadas eram de dois tipos:

  • os dois campos não podiam estar vazios
  • o campo “idade” deveria verificar o máscara (expressão regular) \s*\d+\s*

Essas duas verificações fazem parte das verificações que o ambiente StrutsValidator pode realizar. Esse ambiente vem com o Struts e contém várias classes que podem ser encontradas em commons-validator.jar e jakarta-oro.jar. Se você seguiu o procedimento, explicado no início deste documento, para instalar as bibliotecas do Struts no Tomcat, essas bibliotecas já estão disponíveis no Tomcat. Certifique-se de que elas também estejam disponíveis no JBuilder. Isso também foi explicado no início deste documento.

A nova declaração do formulário no struts-config.xml passa a ser a seguinte:

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

Portanto, há muito pouca diferença. A classe associada ao formulário dinâmico agora é uma classe predefinida de StrutsValidator: org.apache.struts.validator.DynaValidatorForm. O desenvolvedor não precisa mais escrever nenhuma classe. Ele especifica as restrições de integridade que o formulário deve verificar em um arquivo separado, o XML. O controlador Struts deve conhecer o nome desse arquivo. Para isso, surge uma nova seção de configuração no arquivo 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>

A seção <plug-in> serve para carregar uma classe externa ao Struts. Seu principal atributo é classname, que indica o nome da classe a ser instanciada. O objeto instanciado pode precisar ser inicializado. Isso é feito por meio das tags set-property, que possuem dois atributos:

  • property: o nome da propriedade a ser inicializada
  • value: o valor da propriedade

Aqui, a classe DynaValidatorForm precisa conhecer duas informações:

  • o arquivo XML, que define as restrições de integridade padrão que a classe sabe verificar;
  • o arquivo XML, que define as restrições de integridade dos diversos formulários dinâmicos do aplicativo

Essas duas informações são fornecidas aqui pela propriedade pathnames. O valor dessa propriedade é uma lista de arquivos XML que o validador carregará:

  • validator-rules.xml é o arquivo que define as restrições de integridade padrão. Ele é fornecido com o Struts. Ele pode ser encontrado em <struts>\lib, acompanhado de seu arquivo de definição DTD:

Image

  • validation.xml define as restrições de integridade dos diversos formulários dinâmicos do aplicativo. Ele é criado pelo desenvolvedor. Seu nome pode ser escolhido livremente.

Esses dois arquivos podem ser colocados em qualquer lugar abaixo de WEB-INF. No nosso exemplo, eles serão colocados diretamente abaixo de WEB-INF:

Image

5.2. Definição das restrições de integridade dos formulários dinâmicos

O arquivo validation.xml conterá nossas restrições de integridade para os campos nome e idade do formulário frmPersonne, do tipo org.apache.struts.validator.DynaValidatorForm. Seu conteúdo é o seguinte:

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

As regras de escrita a serem respeitadas são as seguintes:

  • todas as regras estão contidas na tag <form-validation>
  • A tag <global> serve para definir informações de escopo global, c.a.d. Válidas para todos os formulários, caso haja mais de um. Aqui, colocamos constantes dentro de <global>. Uma constante é definida por seu nome (tag <constant-name>) e seu valor (tag <constant-value>). Definimos a constante “entierpositif” com o valor da expressão regular que um número inteiro positivo deve satisfazer: ^\s*\d+\s*$ (uma sequência de dígitos, eventualmente precedida e/ou seguida por espaços).
  • A tag <formset> define o conjunto de formulários para os quais há restrições de integridade a serem verificadas
  • a tag <form name="unFormulaire"> serve para definir as restrições de integridade de um formulário específico, aquele cujo nome é fornecido pelo atributo name. Esse nome deve existir na lista de formulários definidos em struts-config.xml. Aqui, o formulário frmPersonne utilizado está definido em struts-config.xml pela seguinte seção:
    <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>            
  • Uma tag <form> contém tantas tags <field> quantas forem as restrições de integridade a serem verificadas no formulário. Uma tag <field> possui os seguintes atributos:
    • property: nome do campo do formulário para o qual são definidas as restrições de integridade
    • depends: lista das restrições de integridade a serem verificadas.
      • As restrições possíveis são as seguintes: required (o campo não pode estar vazio), mask (o valor do campo deve corresponder a uma expressão regular definida pela variável mask), integer: o valor do campo deve ser um inteiro, byte (octet), long (inteiro longo), float (real simples), double (real duplo), short (inteiro curto), date (o valor do campo deve ser uma data válida), range (o valor do campo deve estar dentro de um intervalo determinado), email: (o valor do campo deve ser um endereço de e-mail válido), ...
      • as restrições de integridade são verificadas na ordem do atributo depends. Se uma restrição não for verificada, as seguintes não são testadas.
      • cada restrição está associada a uma mensagem de erro definida por uma chave. Aqui estão algumas delas no formato restrição (chave): required (errors.required), mask (errors.invalid), integer (errors.integer), byte (errors.byte), long (errors.long), ...
      • as mensagens de erro associadas às chaves anteriores estão definidas no arquivo validator-rules.xml:
   # Mensagens de erro do Struts Validator
   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.
  • Vemos acima que as mensagens estão em inglês. Além disso, elas estão em comentários no arquivo, onde é indicado que devem ser inseridas no arquivo de mensagens do aplicativo. Vale lembrar que este está definido em uma seção do arquivo struts-config.xml:
    <message-resources 
      parameter="ressources.personneressources"
    null="false"
  />    

O atributo **parameter** indica que as mensagens do aplicativo estão no arquivo

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

As mensagens de erro devem, portanto, ser colocadas nesse arquivo. Elas são adicionadas às que já existem:

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>

   # Mensagens de erro do Struts Validator
    # a chave é predefinida e não deve ser alterada
    # a mensagem de erro associada é livre
    # a mensagem pode ter até 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

Vamos examinar as restrições de integridade do arquivo validation.xml, uma a uma, para explicá-las:

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

Vale lembrar que essas restrições de integridade se aplicam aos campos “nome” e “idade” de um formulário dinâmico definido em 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>            

É importante que os nomes do formulário e de seus campos sejam idênticos nos dois arquivos. A restrição de integridade no campo “nom” (property="nom") determina que o campo não pode estar vazio (depends="required"). Caso contrário, será gerado um objeto ActionError com a chave errors.required. A mensagem associada a essa chave encontra-se no arquivo personne.ressources.properties:

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

Percebe-se que essa mensagem utiliza um parâmetro {0}. O valor desse parâmetro é definido pela tag <arg0> da restrição de integridade:

             <arg0 key="personne.nom"/>      

Mais uma vez, arg0 é designado por uma chave que também se encontra no arquivo de mensagens:

   personne.nom=nom

Se juntarmos tudo isso, a mensagem de erro gerada caso o campo “nom” não esteja preenchido é:

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

Vamos agora analisar a segunda restrição, a do 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>

Existem duas restrições para o campo “age”: “required” e “mask”. Podemos repetir a explicação anterior para a restrição “required”. Conclui-se que a mensagem de erro associada a essa restrição será:

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

A segunda restrição é mask. Isso significa que o conteúdo do campo deve corresponder a um padrão expresso por uma expressão regular. O valor desta última é definido em uma tag <var>, que define uma variável chamada mask (<var-name>) cujo valor é ${entierpositif} (<var-value>). entierpositif é uma constante definida na seção <global> do arquivo, cujo valor é a expressão regular ^\s*\d+\s*$. A restrição de integridade é, portanto, que a idade deve ser uma sequência de um ou mais dígitos, eventualmente precedida ou seguida por espaços. Se essa restrição não for verificada, será gerado um objeto ActionError com a chave errors.invalid. No arquivo de mensagens, essa chave está associada à seguinte mensagem:

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

A restrição deve definir um valor para o parâmetro {0}. Ela faz isso com a tag <arg0>:

             <arg0 key="personne.age"/>      

No arquivo de mensagens, a chave personne.age está associada à seguinte mensagem:

     personne.age=age

A mensagem de erro que será gerada caso a restrição mask não seja verificada é, portanto:

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

5.3. As classes do aplicativo

Em uma aplicação Struts, as classes a serem criadas são as dos formulários (ActionForm ou derivadas) e as das ações (Action ou derivadas). Na nova aplicação strutspersonne2, não há mais uma classe para o formulário. O conteúdo do formulário é definido em struts-config.xml e as restrições de integridade associadas em WEB-INF/validation.xml. Na aplicação strutspersonne1, a classe FormulaireAction de processamento do formulário era a seguinte:

package istia.st.struts.personne;

....

public class FormulaireAction
  extends Action {
  public ActionForward execute(ActionMapping mapping, ActionForm form,
                               HttpServletRequest request, HttpServletResponse response) throws IOException,
    ServletException {
     // temos um formulário válido; caso contrário, não teríamos chegado até aqui
    DynaActionForm formulaire=(DynaActionForm)form;
    request.setAttribute("nom",formulaire.get("nom"));
    request.setAttribute("age",formulaire.get("age"));
    return mapping.findForward("reponse");
  }//executar
}

A classe FormulaireAction esperava receber um formulário na forma de um objeto DynaActionForm (código em destaque). No entanto, no arquivo struts-config.xml, a classe do formulário está definida da seguinte forma:

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

O formulário será, portanto, colocado em um objeto do tipo DynaValidatorForm. Acontece que essa classe é derivada da classe DynaActionForm. O método execute da nossa classe FormulaireAction continua, portanto, válido. Ele não precisa ser reescrito.

5.4. Implantação e teste do aplicativo strutspersonne2

5.4.1. Criação do contexto

Chamamos essa nova aplicação de strutspersonne2. Criamos uma nova definição no arquivo <tomcat>\conf\serveur.xml do Tomcat 4.x:

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

Feito isso, é necessário reiniciar o Tomcat. É possível verificar a validade do contexto acessando o URL:

http://localhost:8080/strutspersonne2/

Image

5.4.2. As visualizações

Vamos copiar a pasta “vues” do aplicativo strutspersonne1 para a pasta do aplicativo strutspersonne2. Afinal, as visualizações não mudaram.

Image

5.4.3. A pasta WEB-INF

Copiaremos a pasta WEB-INF do aplicativo strutspersonne1 para a pasta do aplicativo strutspersonne2. Alguns arquivos foram alterados:

Image

O arquivo de configuração struts-config.xml passa a ter o seguinte conteúdo:

<?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 arquivo é idêntico ao da aplicação strutspersonne1, com exceção da definição dinâmica do formulário e da inserção do plugin de validação (partes emolduradas).

Adiciona-se ao arquivo WEB-INF o seguinte arquivo de validação 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>

Adicionamos ao WEB-INF os arquivos validator-rules.xml e validator-rules_1_1.dtd, que se encontram em <struts>\lib:

Image

Na pasta WEB-INF/classes, resta apenas uma única classe:

Image

Na pasta WEB-INF\classes\ressources, encontra-se o seguinte arquivo de mensagens 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>

   # Mensagens de erro do Struts Validator
    # a chave é predefinida e não deve ser alterada
    # a mensagem de erro associada é livre
    # a mensagem pode ter até 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. Testes

Estamos prontos para os testes. Abaixo, apresentamos algumas capturas de tela que o leitor é convidado a reproduzir.

Solicita-se o URLhttp://localhost:8080/strutspersonne2/formulaire.do:

Image

Utilize o botão [Envoyer] sem preencher os campos:

Image

Tentamos novamente, mas ocorre um erro no campo “idade”:

Image

Recebemos a seguinte resposta:

Image

Vamos tentar novamente, desta vez inserindo valores corretos:

Image

Obtém-se a seguinte resposta:

Image

5.6. Conclusão

Mostramos que o uso de formulários dinâmicos cujas restrições de integridade são “padrão” evita a criação de classes para representá-los. Se as restrições de integridade se desviarem do padrão, somos levados novamente a criar classes para verificar essas novas restrições.