Skip to content

6. Formulários HTML

Até agora, utilizamos um único formulário com apenas dois campos de entrada. Propomos aqui criar e processar um formulário utilizando os componentes gráficos comuns (botões de opção, caixas de seleção, campos de entrada, caixas de combinação, listas).

6.1. As visualizações do aplicativo

A aplicação terá apenas duas visualizações. A primeira apresenta um formulário em branco:

QZXW2HTMLP000547ZQX 1 - formulaire

Image

Essa primeira visualização, chamada formulaire.jsp, nos permitirá implementar diferentes tags da biblioteca struts-html. O usuário preenche o formulário:

Image

O botão [Envoyer] permite obter uma confirmação dos valores inseridos. Essa será a segunda visualização:

Image

Essa segunda visualização nos permitirá utilizar outras duas bibliotecas de tags: struts-bean e struts-logic. O link [Retour au formulaire] nos permite acessar o formulário exatamente como foi preenchido. Assim, voltamos à primeira visualização.

6.2. A arquitetura da aplicação

  • O formulário (vista 1) será representado por um objeto Struts dinâmico chamado dynaFormulaire, de tipo derivado de DynaActionForm. Ele será exibido pela vista formulaire.jsp.
  • A ação Struts InitFormulaireAction terá como objetivo obter os dados necessários para a exibição do formulário
  • o formulário preenchido será processado por uma ação ForwardAction, que se limitará a redirecionar a solicitação para a segunda visualização confirmation.jsp. Esta se encarregará de exibir os valores do formulário.

6.3. A configuração do aplicativo

6.3.1. O arquivo server.xml

O contexto da aplicação será denominado /formulário2. Portanto, adicionaremos a seguinte linha no arquivo server.xml do Tomcat:

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

Feito isso, reiniciamos o Tomcat, se necessário, para que ele reconheça o novo contexto. Podemos verificar se ele está válido acessando o URL http://localhost:8080/formulaire2:

Image

6.3.2. O arquivo web.xml

O arquivo de configuração web.xml do aplicativo será o seguinte:

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

<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
    <servlet>
      <servlet-name>action</servlet-name>
    <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
    <init-param>
        <param-name>config</param-name>
      <param-value>/WEB-INF/struts-config.xml</param-value>
    </init-param>
  </servlet>

  <servlet-mapping>
      <servlet-name>action</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>

  <taglib>
      <taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
    <taglib-location>/WEB-INF/struts-html.tld</taglib-location>
  </taglib>
  <taglib>
      <taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
    <taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
  </taglib>
  <taglib>
      <taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
    <taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
  </taglib>

</web-app>

Em relação aos arquivos de configuração web.xml já mencionados, estamos fazendo algumas alterações:

  • introduzimos duas novas bibliotecas de tags: struts-bean e struts-logic. Elas serão utilizadas na visualização confirmation.jsp. Já a visualização formulaire.jsp utilizará a biblioteca struts-html.

6.3.3. O arquivo struts-config.xml

O arquivo struts-config.xml 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="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
            <form-property name="opt" type="java.lang.String" initial="non"/>
            <form-property name="chk1" type="java.lang.String"/>
            <form-property name="chk2" type="java.lang.String"/>
            <form-property name="chk3" type="java.lang.String"/>            
            <form-property name="champSaisie" type="java.lang.String" initial=""/>
            <form-property name="mdp" type="java.lang.String" initial=""/>        
            <form-property name="boiteSaisie" type="java.lang.String" initial=""/>        
            <form-property name="combo" type="java.lang.String"/>
            <form-property name="listeSimple" type="java.lang.String"/>
            <form-property name="listeMultiple" type="java.lang.String[]"/>                
            <form-property name="secret" type="java.lang.String" initial="xxx"/>
            <form-property name="valeursCombo" type="java.lang.String[]" />
            <form-property name="valeursListeSimple" type="java.lang.String[]" />
            <form-property name="valeursListeMultiple" type="java.lang.String[]"/>                  
        </form-bean>            
    </form-beans>

    <action-mappings>
      <action
          path="/confirmation"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          parameter="/vues/confirmation.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />

      <action
          path="/init"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          type="istia.st.struts.formulaire.InitFormulaireAction"
      >
            <forward name="afficherFormulaire" path="/vues/formulaire.jsp"/>
        </action>

      <action
          path="/affiche"
          parameter="/vues/formulaire.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />

    </action-mappings>

        <message-resources 
      parameter="ApplicationResources"
        null="false"/>    

</struts-config>

Nele, encontramos as três seções principais:

  • a declaração dos formulários na seção <form-beans>
  • a declaração das ações na seção <action-mappings>
  • a declaração do arquivo de recursos na seção <message-ressources>

6.3.4. Os objetos (beans) de formulário do aplicativo

Os objetos utilizados para representar os formulários HTML da aplicação são objetos do tipo ActionForm ou derivados (DynaActionForm, DynaValidatorForm, ...). Eles são chamados de beans porque sua construção segue as regras dos JavaBeans. Há apenas um bean de formulário em nosso aplicativo, chamado dynaFormulaire e de tipo derivado de DynaActionForm. Ele será utilizado nas seguintes situações:

  • conter os dados necessários para a exibição da vista nº 1
  • recuperar os valores do formulário da visualização nº 1 quando o usuário o enviar (submit)
  • conter os dados necessários para a exibição da visualização nº 2

A estrutura do bean dynaFormulaire está intimamente ligada ao formulário da visualização nº 1. Vamos analisá-lo:

N.º
Tipo HTML
Função
1
<input name="opt" type="radio" value="sim">
<input name="opt" type="radio" value="não">
grupo de botões de opção interligados (mesmo nome)
2
<input name="chk1" type="radio" value="on">
<input name="chk2" type="radio" value="on">
<input name="chk3" type="radio" value="on">
grupos de caixas de seleção
independentes (com nomes diferentes)
3
<input type="text" name="champSaisie" >
um campo de entrada
4
<input type="password" name="mdp" >
um campo de senha
5
<textarea name="boiteSaisie">...</textarea>
um campo de entrada com várias linhas
6
<select name="combo" size="1">..</select>
um menu suspenso
7
<select name="listeSimple" size="3">..</select>
uma lista de seleção única
8
<select name="listeMultiple" size="3" multiple>..</select>
uma lista de seleção múltipla
9
<input type="button" value="Apagar"
onclick='effacerListe("listeSimple")'>
botão que permite desmarcar
os itens selecionados em listeSimple (7)
10
<input type="button" value="Apagar"
onclick='effacerListe("listeMultiple")'>
botão que permite desmarcar
os elementos selecionados em listeMultiple (8)
11
<input type="submit" value="Enviar">
botão de envio do formulário
12
<input type="hidden" name="secret" value="...">
um campo oculto

Vamos distinguir vários casos:

  1. o objeto dynaFormulaire é usado para conter os valores do formulário HTML acima, que será enviado pelo botão [Envoyer]. Portanto, ele deve ter os mesmos campos que o formulário HTML. O tipo do campo é definido pela seguinte regra:
  • se o campo HTML fornecer apenas um valor, então o campo de dynaFormulaire será do tipo java.lang.String
  • se o campo HTML fornecer vários valores, então o campo dynaFormulaire será do tipo java.lang.String[]

No formulário HTML acima, apenas o campo listeMultiple pode estar associado a vários valores (aqueles selecionados pelo usuário). Portanto, uma primeira definição do objeto dynaFormulaire seria a seguinte:

        <form-bean name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
            <form-property name="opt" type="java.lang.String" initial="non"/>
            <form-property name="chk1" type="java.lang.String"/>
            <form-property name="chk2" type="java.lang.String"/>
            <form-property name="chk3" type="java.lang.String"/>            
            <form-property name="champSaisie" type="java.lang.String" initial=""/>
            <form-property name="mdp" type="java.lang.String" initial=""/>        
            <form-property name="boiteSaisie" type="java.lang.String" initial=""/>        
            <form-property name="combo" type="java.lang.String"/>
            <form-property name="listeSimple" type="java.lang.String"/>
            <form-property name="listeMultiple" type="java.lang.String[]"/>                
            <form-property name="secret" type="java.lang.String" initial="xxx"/>
        </form-bean>            

Como será feito o preenchimento do dynaFormulaire com os valores do formulário HTML enviados pelo cliente web?

opt
O campo “opt” receberá o valor “sim” se o campo HTML <input type="radio" name="opt" value="sim"> tiver sido marcado, e o valor “não” se for o campo <input type="radio" name="opt" value="não"> que tiver sido marcado.
chk1
o campo chk1 receberá o valor “on” se o campo HTML <input name="chk1" type="radio" value="1"> tiver sido marcado; caso contrário, não receberá nenhum valor. Nesse último caso, o campo chk1 manterá seu valor anterior.
chk2
idem
chk3
idem
champSaisie
o campo champSaisie receberá o texto inserido pelo usuário no campo HTML <input type="text" name="champSaisie">. Esse texto pode, eventualmente, ser uma string vazia.
mdp
O campo mdp receberá o texto inserido pelo usuário no campo HTML <input type="password" name="mdp">. Esse texto pode, eventualmente, ser uma string vazia.
boiteSaisie
O campo boiteSaisie receberá o texto inserido pelo usuário no campo HTML <textarea name="boiteSaisie">...</textarea>. Esse texto forma uma única sequência de caracteres, composta pelas linhas digitadas pelo usuário, separadas entre si pela sequência de caracteres "\r\n". O texto obtido pode, eventualmente, ser uma sequência vazia.
combo
o campo de lista suspensa receberá a opção selecionada pelo usuário no campo HTML <select name="combo" size="1">..</select>. A opção selecionada é aquela que aparece na lista suspensa. Se a opção HTML selecionada for do tipo <option value="XX">YY</option>, o campo de lista suspensa receberá o valor “XX”. Se a opção HTML selecionada for do tipo <option>YY</option>, o campo de lista suspensa receberá o valor “YY”.
listeSimple
o campo listeSimple receberá a opção selecionada pelo usuário no campo HTML <select name="listeSimple" size="..">..</select> caso haja alguma. Caso não haja nenhuma, o campo listeSimple não receberá nenhum valor e manterá seu valor anterior. O valor efetivamente atribuído ao campo listeSimple segue as regras indicadas para o menu suspenso.
listeMultiple
o campo listeMultiple, do tipo String[], receberá as opções selecionadas pelo usuário no campo HTML <select name="listeMultiple" size=".." multiple>..</select> caso haja alguma. Caso não haja nenhuma, a matriz listeMultiple não receberá nenhum valor e seu conteúdo permanecerá inalterado. Os valores efetivamente atribuídos à matriz listeMultiple seguem as regras indicadas para o menu suspenso.
secret
o campo “secret” receberá o valor XX do campo HTML <input type="hidden" name="secret" value="XX">. Esse texto pode, eventualmente, ser a string vazia.
  1. O objeto dynaFormulaire é utilizado para fornecer o conteúdo inicial da visualização nº 1. Os valores dos campos anteriores serão utilizados para os seguintes fins:
opt
deve ter o valor “sim” ou “não” para que o navegador saiba qual botão de opção marcar
chk1
se chk1 tiver o valor “on”, a caixa de seleção será marcada; caso contrário, não será
chk2
idem
chk3
idem
champSaisie
o valor do campo será exibido na área de entrada champSaisie
mdp
o valor do campo será exibido no campo de entrada de senha
boiteSaisie
o valor do campo será exibido no campo de entrada boiteSaisie
combo
o valor deste campo indica qual elemento da lista suspensa deve ser selecionado ao exibir o formulário
listeSimple
idem
listeMultiple
os valores da tabela listeMultiple indicam quais elementos da lista múltipla devem ser selecionados ao exibir o formulário
secret
o valor do campo será atribuído ao atributo “value” do campo secreto HTML.

A visualização nº 1 precisa de outras informações:

  • a lista de valores a serem exibidos na lista suspensa
  • a lista de valores a serem exibidos na lista listeSimple
  • a lista de valores a serem exibidos na lista listeMultiple

Existem várias maneiras de fornecer essas informações à visualização. Tabelas incluídas na consulta passada à visualização, por exemplo, serviriam para isso. Aqui, colocamos essas tabelas no bean dynaFormulaire:

        <form-bean name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
...
            <form-property name="valeursCombo" type="java.lang.String[]" />
            <form-property name="valeursListeSimple" type="java.lang.String[]" />
            <form-property name="valeursListeMultiple" type="java.lang.String[]"/>                  
        </form-bean>            

O formulário dynaFormulaire será inicializado pela ação /init, que chamará um objeto derivado de Action chamado InitFormulaireAction. É esse objeto que se encarregará de criar as três tabelas necessárias para a exibição das três listas e de colocá-las no bean dynaFormulaire. O arquivo de configuração atribui a esse bean um escopo igual ao da sessão. Isso faz com que o controlador Struts coloque esse bean na sessão. Assim, não precisaremos regenerá-lo entre dois ciclos de solicitação-resposta. Portanto, a ação /init será chamada apenas uma vez.

  1. O objeto dynaFormulaire também é usado para fornecer o conteúdo da visualização nº 2. Esta se limita a exibir os valores.

6.3.5. As ações da aplicação

As ações são executadas por objetos do tipo Action ou derivados. A configuração das ações é feita dentro das tags <action-mappings>:

    <action-mappings>
      <action
          path="/confirmation"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          parameter="/vues/confirmation.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />

      <action
          path="/init"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          type="istia.st.struts.formulaire.InitFormulaireAction"
      >
            <forward name="afficherFormulaire" path="/vues/formulaire.jsp"/>
        </action>

      <action
          path="/affiche"
          parameter="/vues/formulaire.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />

    </action-mappings>

Vale ressaltar que nem sempre há um formulário associado a uma ação. Esse é o caso, acima, da ação /affiche. Antes de detalhar cada ação, vamos relembrar como funciona o par ação-formulário associado dentro de uma tag <action>:

  • uma ação começa com uma solicitação de um cliente web e termina com o envio de uma página de resposta. Esse é o ciclo de solicitação-resposta do cliente-servidor web. A solicitação é recebida pelo controlador Struts do tipo ActionServlet ou derivado. É também esse controlador que envia a resposta.
  • O bean do formulário do tipo ActionForm ou derivado é criado, caso ainda não exista. O controlador verifica se consegue encontrar um objeto com o nome name no escopo indicado por scope. Se sim, ele o utiliza. Se não, ele o cria e o coloca no escopo indicado por scope, associado ao atributo indicado por name.

No exemplo da ação /init, por exemplo, o controlador executará um request.getSession().getAttribute("dynaFormulaire") para verificar se dynaFormulaire já foi criado ou não. Se não for o caso, ele o criará e o colocará na sessão por meio de uma instrução do tipo request.getSession().setAttribute("dynaFormulaire", new DynaFormulaire(...)).

  • O controlador também buscará um objeto Action do tipo indicado pelo atributo type. Se não o encontrar, ele o criará; caso contrário, ele o utilizará.
  • O método reset do bean de formulário será chamado. Este, exceto na sua criação inicial, é reciclado. Ele contém, portanto, dados que talvez seja necessário “limpar”. É no método reset do bean ActionForm ou derivado que isso será feito.
  • Se a ação for o destino de um formulário enviado via POST, os valores do formulário contidos na solicitação do cliente são copiados para os campos com o mesmo nome no bean do formulário. Observe que o método reset foi chamado antes dessa cópia.
  • Se a configuração especificar o atributo `validate="true"`, o método `validate` do bean do formulário será chamado. Esse método deve, então, verificar os dados do bean. Essa verificação geralmente ocorre apenas quando o formulário acaba de receber novos dados por meio de um formulário enviado via POST e se deseja verificar a validade desses dados. Esse método retorna ao controlador uma eventual lista de erros em um objeto ActionErrors.
  • Se o objeto ActionErrors não estiver vazio, o controlador exibe a visualização especificada pelo atributo input da ação.
  • Se a validação dos dados não for solicitada ou se tiver sido bem-sucedida, o controlador executa o método `execute` do objeto do tipo `Action` ou derivado associado à ação em andamento. É nesse método que a solicitação do cliente web é processada. O método `execute` retorna um objeto ActionForward indexado por chaves do tipo cadeia de caracteres. Essas chaves são as declaradas pelas tags `forward` da ação configurada. Em nosso exemplo, a ação `/init` possui uma única tag `forward`. Ela associa a chave “afficherFormulaire” à visualização formulaire.jsp.
  • O controlador exibe a visualização à qual a chave recebida está associada. Essa visualização pode, na verdade, ser uma ação; nesse caso, o processo anterior é repetido.

A ação /init

        <action
          path="/init"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          type="istia.st.struts.formulaire.InitFormulaireAction"
      >
            <forward name="afficherFormulaire" path="/vues/formulaire.jsp"/>
        </action>
  • A ação /init ocorre normalmente uma vez durante o primeiro ciclo de solicitação-resposta, quando o usuário solicita o URLhttp://localhost:8080/formulaire2/init.do
  • o objeto dynaFormulaire é criado ou reciclado. Ele é recuperado (reciclagem) ou inserido (criação) na sessão, conforme determinado pelo atributo scope.
  • Seu método reset é chamado. O que ele deve fazer? Normalmente, os campos do objeto ActionForm são repostos com os valores padrão. Porém, neste caso, não faremos isso, pois o objeto dynaFormulaire é inserido na sessão (scope="session"). Os campos de dynaFormulaire devem, portanto, manter seus valores. Quais são esses valores na criação inicial do objeto dynaFormulaire? Há dois casos:
  • o campo possui um valor inicial indicado no arquivo de configuração:
            <form-property name="opt" type="java.lang.String" initial="non"/>

Nesse caso, o controlador Struts criará esse campo com esse valor inicial.

  • o campo não possui valor inicial definido na configuração: aplicam-se as regras de inicialização do Java. Em geral, os campos numéricos terão o valor zero, as cadeias de caracteres terão como valor a cadeia vazia e os demais objetos terão o valor null.

Vejamos a configuração inicial de dynaFormulaire:

        <form-bean name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
            <form-property name="opt" type="java.lang.String" initial="non"/>
            <form-property name="chk1" type="java.lang.String"/>
            <form-property name="chk2" type="java.lang.String"/>
            <form-property name="chk3" type="java.lang.String"/>            
            <form-property name="champSaisie" type="java.lang.String" initial=""/>
            <form-property name="mdp" type="java.lang.String" initial=""/>        
            <form-property name="boiteSaisie" type="java.lang.String" initial=""/>        
            <form-property name="combo" type="java.lang.String"/>
            <form-property name="listeSimple" type="java.lang.String"/>
            <form-property name="listeMultiple" type="java.lang.String[]"/>                
            <form-property name="secret" type="java.lang.String" initial="xxx"/>
            <form-property name="valeursCombo" type="java.lang.String[]" />
            <form-property name="valeursListeSimple" type="java.lang.String[]" />
            <form-property name="valeursListeMultiple" type="java.lang.String[]"/>             
        </form-bean>            

Os valores iniciais dos campos de dynaFormulaire após sua criação serão os seguintes:

Campo
Valor inicial
opt
"não"
chk1, chk2, chk3
cadeia vazia
champSaisie
cadeia vazia
mdp
cadeia vazia
boiteSaisie
cadeia vazia
combo
cadeia vazia
listeSimple
cadeia vazia
listeMultiple
matriz de cadeias vazias
secret
"xxx"
valeursCombo, listeSimple, listeMultiple
matriz de strings vazias
  • seria possível imaginar que o método reset de dynaFormulaire atribua valores às três tabelas que devem alimentar as três listas da visualização formulaire.jsp. Isso seria possível aqui, pois os dados desses três tabuletos são gerados de forma arbitrária. No entanto, o caso mais comum é que esses dados provenham do modelo da aplicação, o M de MVC. Aqui, adotaremos uma posição intermediária, para não complicar o exemplo, fazendo com que esses valores sejam gerados pela ação InitFormulaireAction, ou seja, pelo C de MVC.
  • Não há obrigação de escrever um método reset em dynaFormulaire, já que a classe ActionForm, da qual ela deriva, possui um método desse tipo que não faz nada (sem inicializações).
  • Assim que o método reset de dynaFormulaire for chamado, o controlador verifica o atributo validate da ação. Aqui, ele tem o valor “false”. O método validate de dynaFormulaire não será chamado.
  • O objeto InitFormulaireAction é criado ou reciclado, caso já existisse, e seu método `execute` é executado. É esse método que atribuirá valores arbitrários às três matrizes de dynaFormulaire: valeursCombo, valeursListeSimple e valeursListeMultiple. O método retorna um ActionForward com a chave “afficherFormulaire”.
  • O controlador exibe a visualização /vues/formulaire.jsp, que foi associada à chave “afficherFormulaire” por meio de um tag forward da ação /init.

A ação /confirmation

      <action
          path="/confirmation"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          parameter="/vues/confirmation.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />
  • A ação /confirmation ocorre quando o usuário clica no botão [Envoyer] da visualização nº 1. O navegador então “envia” ao controlador Struts o formulário preenchido pelo usuário.
  • O objeto dynaFormulaire é obtido na sessão
  • e seu método reset é chamado. Após ser chamado, o controlador Struts copiará os valores dos campos do formulário enviado pelo cliente para os campos com os mesmos nomes em dynaFormulaire. Vamos revisar a lista de campos deste último e ver como ocorre essa cópia:
Campo
Código associado do HTML
Valor do campo
após a cópia dos valores do formulário
opt
<input type="radio" name="opt" value="sim">Sim
<input type="radio" name="opt" value="não" checked="checked">Não
- “sim” ou “não”, dependendo do botão de opção marcado
chk1
<input type="checkbox" name="chk1" value="on">
- “on” se a caixa de seleção chk1 tiver sido marcada
- mantém seu valor anterior se a caixa de seleção chk1 não tiver sido marcada
chk2
<input type="checkbox" name="chk2" value="on">
- “on” se a caixa de seleção chk2 tiver sido marcada
- mantém seu valor anterior se a caixa de seleção chk2 não tiver sido marcada
chk3
<input type="checkbox" name="chk2" value="on">
- “on” se a caixa de seleção chk3 tiver sido marcada
- mantém o valor anterior se a caixa de seleção chk3 não tiver sido marcada
champSaisie
<input type="text" name="champSaisie" value="">
- valor digitado pelo usuário em champSaisie
mdp
<input type="password" name="mdp" value="">
- valor digitado pelo usuário em mdp
boiteSaisie
<textarea name="boiteSaisie"></textarea>
- valor digitado pelo usuário em boiteSaisie
combo
<select name="combo">...</select>
- valor selecionado pelo usuário em combo
listeSimple
<select name="listeSimple" size="3">...</select>
- valor selecionado pelo usuário em listeSimple
listeMultiple
<select name="listeMultiple" multiple="multiple" size="5">
- matriz de strings contendo os valores selecionados pelo usuário em listeMultiple
secret
<input type="hidden" name="secret" value="xxx">
- “xxx”.

Temos uma dificuldade com os campos que nem sempre recebem um valor na solicitação enviada pelo navegador. É o caso das caixas de seleção chk1 a chk3 e das duas listas listeSimple e listeMultiple. Nesse caso, esses campos mantêm seus valores anteriores, aqueles obtidos durante o ciclo de solicitação-resposta anterior.

Vamos analisar a caixa de seleção chk1, por exemplo, e supor que, no ciclo anterior de solicitação-resposta, o usuário tenha marcado essa caixa. O navegador, então, enviou na cadeia de parâmetros de sua solicitação a informação chk1="on". O desenvolvedor, portanto, atribuiu o valor “on” ao campo chk1 de dynaFormulaire. Suponhamos agora que, no ciclo atual, o usuário não marque a caixa de seleção chk1. Nesse caso, na cadeia de parâmetros da nova solicitação, o navegador não envia algo como chk1="off", mas sim nada. Consequentemente, o campo chk1 de dynaFormulaire manterá seu valor “on” e, portanto, terá um valor que não reflete o do formulário validado pelo usuário. Utilizaremos o método reset de dynaFormulaire para resolver esse problema. Nesse método, definiremos os três campos chk1, chk2 e chk3 como “off”. No nosso exemplo do chk1, se o usuário:

  • marcar a caixa de seleção chk1. Nesse caso, o navegador enviará a informação chk1="on" e o campo chk1 de dynaFormulaire passará para “on”
  • não marcar a caixa de seleção chk1. Nesse caso, o navegador não enviará nenhum valor para o campo chk1, que manterá seu valor anterior “off”. Nos dois casos, o valor registrado no campo chk1 de dynaFormulaire está correto.

O problema é semelhante para as duas listas listeSimple e listeMultiple. Se nenhuma opção tiver sido selecionada nessas listas, elas não estarão presentes nos parâmetros da consulta e, portanto, manterão seus valores anteriores. No método reset de dynaFormulaire, reinicializaremos listeSimple com uma string vazia e listeMultiple com uma matriz de strings de comprimento 0.

  • Assim que o método reset de dynaFormulaire for chamado, o controlador recopia nos campos de dynaFormulaire as informações que lhe foram enviadas na solicitação do cliente
  • Um objeto ForwardAction é criado ou reutilizado, e seu método `execute` é chamado. ForwardAction é uma classe predefinida que retorna um objeto ActionForward apontando para a visualização definida pelo atributo “parameter” da ação, neste caso /vues/confirmation.jsp.
  • O controlador envia essa visualização. O ciclo está concluído.

A ação /exibe

      <action
          path="/affiche"
          parameter="/vues/formulaire.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />
  • A ação /affiche é acionada ao clicar no link [Retour vers le formulaire] da visualização nº 2.
  • Aqui não há nenhum formulário associado à ação. Portanto, passa-se imediatamente para a execução do método `execute` de um objeto `ForwardAction`, que retornará um objeto `ActionForward` apontando para a visualização `/vues/formulaire.jsp`.

6.3.6. O arquivo de mensagens do aplicativo

A terceira seção do arquivo struts-config.xml é a do arquivo de mensagens:

        <message-resources 
          parameter="ApplicationResources"
            null="false"
      />    

O arquivo ApplicationResources.properties está localizado em WEB-INF/classes. Ele estará vazio. Mesmo vazio, ele deve, no entanto, ser declarado no arquivo de configuração; caso contrário, a biblioteca de tags struts-bean, que veremos um pouco mais adiante, gera um erro. Essa biblioteca é utilizada pela visualização confirmation.jsp.

6.4. O código das visualizações

6.4.1. A visualização formulaire.jsp

Vale lembrar que essa vista é exibida em dois casos:

  • ao chamar a ação /init durante o primeiro ciclo de solicitação-resposta
  • ao chamar a ação /affiche nos ciclos seguintes

O código da visualização formulaire.jsp é o seguinte:

<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>

<html>
  <head>
      <title>formulaire</title>
  </head>  
  <body background='<html:rewrite page="/images/standard.jpg"/>'>
      <h3>Formulaire Struts</h3>
    <hr>
    <html:form action="/confirmation" name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
      <table border="0">
        <tr>
          <td>bouton radio</td>
          <td>
                        <html:radio name="dynaFormulaire" property="opt" value="oui">Oui</html:radio>
                        <html:radio name="dynaFormulaire" property="opt" value="non">Non</html:radio>                                            
          </td>
        </tr>
        <tr>
          <td>Cases à cocher</td>
          <td>
                        <html:checkbox name="dynaFormulaire" property="chk1">1</html:checkbox>
                        <html:checkbox name="dynaFormulaire" property="chk2">2</html:checkbox>
                        <html:checkbox name="dynaFormulaire" property="chk3">3</html:checkbox>                                                
          </td>
        </tr>
        <tr>
          <td>Champ de saisie</td>
          <td>
                        <html:text name="dynaFormulaire" property="champSaisie" />
          </td>
        </tr>
        <tr>
          <td>Mot de passe</td>
          <td>
              <html:password name="dynaFormulaire" property="mdp" />
          </td>
        </tr>
        <tr>
          <td>Boîte de saisie multilignes</td>
          <td>
              <html:textarea name="dynaFormulaire" property="boiteSaisie" />
          </td>
        </tr>
        <tr>
          <td>Combo</td>
          <td>
              <html:select name="dynaFormulaire" property="combo">
                            <html:options name="dynaFormulaire" property="valeursCombo"/>
                        </html:select>
          </td>
        </tr>
        <tr>
          <td>
                        <table>
                            <tr>
                                <td>Liste à sélection unique</td>
                            </tr>
                            <tr>
                                <td>
                                    <input type="button" value="Effacer" onclick="this.form.listeSimple.selectedIndex=-1"/>
                                </td>
                            </tr>
                        </table>
          <td>
              <html:select name="dynaFormulaire" property="listeSimple" size="3">
                            <html:options name="dynaFormulaire" property="valeursListeSimple"/>                        
                        </html:select>
          </td>
        </tr>
        <tr>
                    <td>
                        <table>
                            <tr>
                                <td>Liste à sélection multiple</td>
                            </tr>
                            <tr>
                                <td>
                                    <input type="button" value="Effacer" onclick="this.form.listeMultiple.selectedIndex=-1"/>                                
                                </td>
                            </tr>
                        </table>
                    </td>
          <td>
              <html:select name="dynaFormulaire" property="listeMultiple" size="5" multiple="true">
                            <html:options name="dynaFormulaire" property="valeursListeMultiple"/>                        
                        </html:select>
          </td>
        </tr>
      </table>
      <html:hidden name="dynaFormulaire" property="secret"/>
            <br>
            <hr>
            <html:submit>Envoyer</html:submit> 
    </html:form>
  </body>
</html>

Esta página JSP utiliza tags provenientes da biblioteca struts-html. Vale lembrar que, para utilizar uma biblioteca de tags, é necessário:

  • declará-la no arquivo web.xml do aplicativo com uma tag <tag-lib>
  <taglib>
      <taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
    <taglib-location>/WEB-INF/struts-html.tld</taglib-location>
  </taglib>
  • coloque o código dessa biblioteca em algum lugar na estrutura de diretórios do aplicativo, neste caso WEB-INF/struts-html.tld
  • Declare o uso desta biblioteca no início das páginas JSP que a utilizam:
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>

A visualização formulaire.jsp utiliza tags que explicaremos a seguir:

balise
<body background="<html:rewrite page="/images/standard.jpg"/>">
traduction HTML
<body background="/formulaire2/images/standard.jpg">
explication
A tag html:rewrite permite ignorar o nome do aplicativo em URL. Ela possui um atributo:
page
URL – a ser reescrito
Assim, conforme mostrado acima, se decidirmos chamar o aplicativo de formulário3, o código do atributo background não precisa ser reescrito. A tag html:rewrite gerará o novo código HTML
background="/formulaire3/images/standard.jpg"
balise
<html:form action="/confirmation" name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
traduction HTML
<form name="dynaFormulaire" method="post" action="/formulaire2/confirmation.do">
explication
A tag html:form permite gerar a tag HTML form. Ela possui vários atributos:
action
ação Struts para a qual o formulário deve ser enviado — deve corresponder a uma das ações definidas em struts-config.xml
name
opcional — nome do bean ActionForm ou derivado no qual os valores do formulário enviado deverão ser inseridos ou lidos. Na ausência desse atributo, é utilizado o formulário associado à ação definida pelo atributo action. Essa informação se encontra no arquivo de configuração (atributo name da ação).
type
opcional — classe Java a ser instanciada para o formulário. Na ausência desse atributo, é utilizada a classe associada à ação definida pelo atributo action. Essa informação se encontra no arquivo de configuração (atributo type da ação).
Vemos que, por padrão, o código HTML gerado utiliza o método POST. Nesse mesmo código HTML, o URL da ação foi reescrito para receber como prefixo o nome do aplicativo e como sufixo .do.
balise
<html:radio name="dynaFormulaire" property="opt" value="sim">Sim</html:radio>
traduction HTML
<input type="radio" name="opt" value="oui">
explication
A tag html:radio serve para gerar a tag HTML <input type="radio" ...>. Ela admite diversos atributos:
name
opcional — nome do bean ActionForm ou derivado no qual o valor do campo deverá ser inserido ou lido. Na ausência desse atributo, é utilizado o formulário associado à tag <html:form>.
property
nome do campo do bean de formulário associado ao botão de opção, para leitura e gravação.
value
opcional — valor a ser atribuído ao campo HTML
O texto entre as tags de início e fim é o texto que será exibido ao lado do botão de opção.
balise
<html:checkbox name="dynaFormulaire" property="chk1">1</html:checkbox>
traduction HTML
<input type="checkbox" name="chk1" value="on">
explication
A tag html:checkbox serve para gerar a tag HTML <input type="checkbox" ...>. Ela admite diversos atributos:
name
opcional — nome do bean ActionForm ou derivado no qual o valor do campo deverá ser inserido ou lido. Na ausência desse atributo, é utilizado o formulário associado à tag <html:form>.
property
nome do campo do bean de formulário associado à caixa de seleção, com acesso de leitura e gravação.
value
opcional — valor a ser atribuído ao campo HTML
O texto entre as tags de início e fim é o texto que será exibido ao lado da caixa de seleção.
balise
<html:text name="dynaFormulaire" property="champSaisie" />
traduction HTML
<input type="text" name="champSaisie" value="">
explication
A tag html:text serve para gerar a tag HTML <input type="text" ...>. Ela admite diversos atributos:
name
opcional — nome do bean ActionForm ou derivado no qual o valor do campo deverá ser inserido ou lido. Na ausência desse atributo, é utilizado o formulário associado à tag <html:form>.
property
nome do campo do bean de formulário associado ao campo de entrada para leitura e gravação.
value
opcional - valor a ser inserido no campo HTML
balise
<html:password name="dynaFormulaire" property="mdp" />
traduction HTML
<input type="password" name="mdp" value="">
explication
A tag html:password serve para gerar a tag HTML <input type="password" ...>. Ela admite diversos atributos:
balise
<html:textarea name="dynaFormulaire" property="boiteSaisie" />
traduction HTML
<textarea name="boiteSaisie"></textarea>
explication
A tag html:textarea serve para gerar a tag HTML <textarea>...</textarea>. Ela admite diversos atributos:
name
opcional — nome do bean ActionForm ou derivado no qual o valor do campo deverá ser inserido ou lido. Na ausência desse atributo, é utilizado o formulário associado à tag <html:form>.
property
nome do campo do bean de formulário associado ao campo de senha, com permissão de leitura e gravação.
value
opcional — valor a ser atribuído ao campo HTML
balise
<html:select name="dynaFormulaire" property="combo">....</html:select>
traduction HTML
<select name="combo">...</select>
explication
A tag html:select serve para gerar a tag HTML <select>...</select>. Ela admite diversos atributos:
name
opcional — nome do bean ActionForm ou derivado no qual o valor do campo deverá ser inserido ou lido. Na ausência desse atributo, é utilizado o formulário associado à tag <html:form>.
property
nome do campo do bean de formulário associado ao campo de entrada para leitura e gravação.
value
opcional — valor a ser atribuído ao campo HTML. A opção da lista suspensa com esse valor será selecionada.
balise
<html:select name="dynaFormulaire" property="combo">
<html:options name="dynaFormulaire" property="valeursCombo"/>
</html:select>
traduction HTML
<option value="combo1">combo1</option>
<option value="combo2">combo2</option>

explication
A tag HTML:options serve para gerar as tags HTML <option>...</option> dentro de uma tag HTML <select>. Existem várias maneiras de especificar como encontrar os valores de preenchimento do select. Aqui, utilizamos os atributos name e property:
name
opcional — nome do bean ActionForm ou derivado no qual o valor do campo deverá ser inserido ou lido. Na ausência desse atributo, é utilizado o formulário associado à tag <html:form>.
property
nome do campo do bean de formulário que contém os valores da lista suspensa. Deve ser uma matriz de cadeias de caracteres.

As outras duas listas são geradas de forma análoga à anterior:

          <html:select name="dynaFormulaire" property="listeSimple" size="3">
            <html:options name="dynaFormulaire" property="valeursListeSimple"/>            
        </html:select>

Acima, especifica-se um atributo size diferente de 1 para obter uma lista em vez de um menu suspenso.

<html:select name="dynaFormulaire" property="listeMultiple" size="5" multiple="true">
        <html:options name="dynaFormulaire" property="valeursListeMultiple"/>                
    </html:select>

Acima, especifica-se o atributo multiple="true" para obter uma lista com seleção múltipla.

balise
<html:hidden name="dynaFormulaire" property="secret"/>
traduction HTML
<input type="hidden" name="secret" value="xxx">
explication
A tag html:hidden serve para gerar a tag HTML <input type="hidden" ...>.
name
opcional - nome do bean ActionForm ou derivado no qual o valor do campo deverá ser inserido ou lido. Na ausência desse atributo, é utilizado o formulário associado à tag <html:form>.
property
nome do campo do bean de formulário associado ao campo oculto. O valor “xxx” atribuído ao campo secreto HTML provém da definição do formulário no arquivo de configuração. Nele, foi definido um valor inicial “xxx” para o campo secreto.

Para compreender bem a relação entre a visualização formulaire.jsp e o bean dynaFormulaire que a representa na memória, é preciso lembrar que o bean dynaFormulaire é utilizado tanto para leitura quanto para gravação:

A solicitação ocorre quando o usuário clica no botão [Envoyer] do formulário. O navegador então “envia” o formulário HTML para a ação /confirmation. Já explicamos o que acontece nesse momento e, em particular, que os campos de dynaFormulaire receberão os valores dos campos com o mesmo nome do formulário HTML.

O que acontece quando o controlador solicita a exibição da vista formulaire.jsp em resposta a uma solicitação? Vamos reexaminar as tags uma a uma:

balise
<body background="<html:rewrite page="/images/standard.jpg"/>">
fonction
gera o código HTML
<body background="/formulaire2/images/standard.jpg">
balise
<html:form action="/confirmation" name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
...
</html:form>
fonction
gera o código HTML
<form name="dynaFormulaire" method="post" action="/formulaire2/confirmation.do">
balise
<html:radio name="dynaFormulaire" property="opt" value="sim">Sim</html:radio>
<html:radio name="dynaFormulaire" property="opt" value="não">Não</html:radio>
fonction
Se o campo opt de dynaFormulaire for “sim”, gere o código HTML
<input type="radio" name="opt" value="oui" checked="checked">Oui
<input type="radio" name="opt" value="non">Non
balise
<html:checkbox name="dynaFormulaire" property="chk1">1</html:checkbox>
<html:checkbox name="dynaFormulaire" property="chk2">2</html:checkbox>
<html:checkbox name="dynaFormulaire" property="chk3">3</html:checkbox>
fonction
Se os campos chk1 e chk3 de dynaFormulaire estiverem em “on” e o campo chk2 estiver em “off”, gere o código HTML
<input type="checkbox" name="chk1" value="on" checked="checked">1
<input type="checkbox" name="chk2" value="on">2
<input type="checkbox" name="chk3" value="on" checked="checked">3                                                
balise
<html:text name="dynaFormulaire" property="champSaisie" />
fonction
se o campo champSaisie tiver o valor “este é um teste”, gera o código HTML
<input type="text" name="champSaisie" value="ceci est un essai">
balise
<html:password name="dynaFormulaire" property="mdp" />
fonction
se o campo mdp for “azerty”, gera o código HTML
<input type="password" name="mdp" value="azerty">
balise
<html:password name="dynaFormulaire" property="mdp" />
fonction
se o campo mdp for “azerty”, gera o código HTML
<input type="password" name="mdp" value="azerty">
balise
<html:password name="dynaFormulaire" property="mdp" />
fonction
se o campo mdp for “azerty”, gera o código HTML
<input type="password" name="mdp" value="azerty">
balise
<html:select name="dynaFormulaire" property="combo">
<html:options name="dynaFormulaire" property="valeursCombo"/>
</html:select>
fonction
se o campo do menu suspenso tiver o valor “combo2”, gera o código HTML
<select name="combo">
    <option value="combo0">combo0</option>
    <option value="combo1">combo1</option>
    <option value="combo2" selected="selected">combo2</option>
    <option value="combo3">combo3</option>
    <option value="combo4">combo4</option>
</select>
balise
<html:select name="dynaFormulaire" property="listeSimple" size="3">
<html:options name="dynaFormulaire" property="valeursListeSimple"/>
</html:select>
fonction
se o campo listeSimple tiver o valor “simple1”, gera o código HTML
<select name="listeSimple" size="3">
    <option value="simple0">simple0</option>
    <option value="simple1" selected="selected">simple1</option>
    <option value="simple2">simple2</option>
...
</select>
balise
<html:select name="dynaFormulaire" property="listeMultiple" size="5" multiple="true">
<html:options name="dynaFormulaire" property="valeursListeMultiple"/>
</html:select>
fonction
se o campo listeMultiple for a matriz {"multiple0","multiple2"}, gera o código HTML
<select name="listeMultiple" multiple="multiple" size="5">
    <option value="multiple0" selected="selected">multiple0</option>
    <option value="multiple1">multiple1</option>
    <option value="multiple2" selected="selected">multiple2</option>
    <option value="multiple3">multiple3</option>
...
</select>
balise
<html:hidden name="dynaFormulaire" property="secret"/>
fonction
se o campo secreto tiver o valor “xxx”, gera o código HTML
<input type="hidden" name="secret" value="xxx">
balise
<html:submit>Enviar</html:submit>
fonction
gera o código HTML
<input type="submit" value="Envoyer">

A última coisa a ser explicada é o código JavaScript incluído na página JSP e vinculado aos dois botões [Effacer], que desmarcam os itens selecionados nas listas listeSimple e listeMultiple:

<input type="button" value="Effacer" onclick="this.form.listeSimple.selectedIndex=-1"/>                                
<input type="button" value="Effacer" onclick="this.form.listeMultiple.selectedIndex=-1"/>

A tag

<html:form action="/confirmation" name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">

gera o seguinte código HTML:

<form name="dynaFormulaire" method="post" action="/formulaire2/confirmation.do">

Para entender o código JavaScript associado aos botões [Effacer], vale lembrar como os diferentes elementos de um documento da web são designados em um código JavaScript que utiliza esse documento:

Dado
Significado
document
designa o documento da web na íntegra
document.forms
refere-se ao conjunto de formulários definidos no documento
document.forms[i]
refere-se ao formulário nº i do documento
document.forms["nomFormulaire"]
refere-se ao formulário <form> cujo atributo name é igual a "nomFormulaire"
document.nomFormulaire
refere-se ao formulário <form> cujo atributo name é igual a "nomFormulaire"
document.[formulaire].elements
refere-se à coleção dos elementos que compõem o formulário designado pela expressão [formulaire]. Essa coleção inclui todas as tags <input>, <textarea> e <select> do formulário designado.
document.[formulaire].elements[i]
designa o elemento nº i de [formulaire]
document.[formulaire].elements["nomComposant"]
refere-se ao elemento de [formulaire] cujo atributo name é igual a nomComposant
document.[formulaire]. nomComposant
refere-se ao elemento de [formulaire] cujo atributo name é igual a nomComposant
document.[formulaire].[composant].value
designa o valor do componente [composant] do formulário [formulaire] quando o código HTML deste pode ter um atributo value (<input>, <textarea>)
document.[formulaire].[select].selectedIndex
indica o índice da opção selecionada em uma lista. É utilizada tanto na leitura quanto na gravação. Definir essa propriedade como -1 desmarca todos os elementos da lista.
document.[formulaire].[select].options
indica a matriz de opções associadas a uma tag <select>
document.[formulaire].[select].options[i]
indica a opção nº i da tag <select> especificada
document.[formulaire].[select].options[i].selected
valor booleano que indica se a opção nº i da tag [select] indicada está selecionada (true) ou não. Pode ser usado para leitura e gravação

Vamos revisar o código JavaScript dos dois botões:

<input type="button" value="Effacer" onclick="this.form.listeSimple.selectedIndex=-1"/>                                
<input type="button" value="Effacer" onclick="this.form.listeMultiple.selectedIndex=-1"/>

Ao clicar no botão, o código associado ao atributo “onclick” é executado. Aqui, trata-se de um código embutido. Na maioria das vezes, escreve-se onclick="função(...)", onde função é uma função definida dentro de uma tag <script language="javascript">...</script>. O que o código acima faz? Vamos comentar o código do primeiro botão:

this
designa o documento da web no qual o botão está localizado
this.form
refere-se ao formulário no qual o botão está localizado
this.form.listeSimple
refere-se ao componente listeSimple do formulário
this.form.listeSimple.selectedIndex
indica o índice da opção selecionada em listeSimple. Definir essa propriedade como -1 desmarca todas as opções.

6.4.2. A visualização confirmation.jsp

Vale lembrar que essa visualização é exibida após a ação/confirmação c.a.d, depois que o formulário contido na visualização formulaire.jsp for enviado pelo cliente web. Seu único objetivo é exibir os valores inseridos pelo usuário. Seu código é o seguinte:

<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

<html>
    <head>
      <title>Confirmation</title>
  </head>
  <body background="<html:rewrite page="/images/standard.jpg"/>">
      <h3>Confirmation des valeurs saisies</h3>
    <hr/>
    <table border="1">
        <tr>
        <td>Bouton radio</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="opt"/></td>
      </tr>
        <tr>
        <td>Case à cocher chk1</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="chk1"/></td>
      </tr>
        <tr>
        <td>Case à cocher chk2</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="chk2"/></td>
      </tr>
        <tr>
        <td>Case à cocher chk3</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="chk3"/></td>
      </tr>

        <tr>
        <td>Champ de saisie</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="champSaisie"/></td>
      </tr>
        <tr>
        <td>Mot de passe</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="mdp"/></td>
      </tr>

        <tr>
        <td>Boîte de saisie</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="boiteSaisie"/></td>
      </tr>

        <tr>
        <td>combo</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="combo"/></td>
      </tr>
        <tr>
        <td>liste simple</td>
        <td><bean:write name="dynaFormulaire" scope="session" property="listeSimple"/></td>
      </tr>
            <logic:iterate id="choix" indexId="index" name="dynaFormulaire" property="listeMultiple">
          <tr>
          <td>liste multiple[<bean:write name="index"/>]</td>
          <td><bean:write name="choix"/></td>
        </tr>
            </logic:iterate>
    </table>
        <br>
    <html:link page="/affiche.do">
            Retour au formulaire
        </html:link>    
  </body>
</html>

Apresentamos aqui duas novas bibliotecas de tags: struts-bean e struts-logic. A biblioteca struts-bean permite acessar objetos contidos na solicitação, na sessão ou no contexto da aplicação. A biblioteca struts-logic permite introduzir lógica de execução por meio de tags. Essas duas bibliotecas não são, de forma alguma, indispensáveis. Como vimos, uma página JSP pode:

  • recuperar objetos da solicitação (request.getAttribute(...)), da sessão (session.getAttribute(...)) ou do contexto da aplicação
  • incluir partes dinâmicas no código HTML por meio de variáveis <%= variável %>
  • conter código Java <% código Java %>

A inclusão de código Java nas páginas JSP incomoda todos aqueles que desejam uma separação estrita entre a lógica da aplicação (código Java) e a apresentação (uso de tags). Por isso, foram criadas bibliotecas de tags especialmente para eles.

Vamos proceder da mesma forma que na visualização formulaire.jsp e explicar cada uma das tags presentes no código de confirmation.jsp, caso ainda não tenham sido encontradas na visualização formulaire.jsp. Em primeiro lugar, observemos que a página começa declarando as três bibliotecas de tags que irá utilizar:

<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

Vale lembrar também que essas três bibliotecas devem ser declaradas no arquivo web.xml do aplicativo. Agora, vamos comentar as tags do documento formulaire.jsp:

balise
<bean:write name="dynaFormulaire" scope="session" property="opt"/>
fonction
grava um valor no fluxo HTML atual. A tag bean:write aceita os seguintes atributos:
name: nome do objeto a ser utilizado
scope: escopo (request, session, context) no qual procurar esse objeto
property: campo do objeto designado por name cuja propriedade deve ser gravada. Esse campo pode ser um objeto de qualquer tipo. Será utilizado o método toString do objeto.
Aqui, o valor do campo opt de dynaFormulaire é gravado. O resultado será “sim” se o usuário tiver marcado o botão de opção com o atributo value="sim", ou “não” se tiver marcado o botão de opção com o atributo value="não"
balise
<bean:write name="dynaFormulaire" scope="session" property="chk1"/>
fonction
grava o valor do campo chk1 de dynaFormulaire. O resultado será “on” se o usuário tiver marcado a caixa de seleção, ou “off” caso contrário. O mesmo vale para chk2 e chk3.
balise
<bean:write name="dynaFormulaire" scope="session" property="champSaisie"/>
fonction
grava o valor do campo champSaisie de dynaFormulaire, ou seja, o texto digitado pelo usuário nesse campo. O mesmo vale para mdp, boiteSaisie.
balise
<bean:write name="dynaFormulaire" scope="session" property="combo"/>
fonction
grava o valor do campo de lista suspensa de dynaFormulaire. Teremos o atributo value do elemento <option> selecionado pelo usuário.
balise
<bean:write name="dynaFormulaire" scope="session" property="listeSimple"/>
fonction
grava o valor do campo listeSimple a partir de dynaFormulaire. Será obtido o atributo “value” do elemento <option> selecionado pelo usuário, caso haja algum. Caso contrário, será obtida a string vazia.
balise
            <logic:iterate id="choix" indexId="index" name="dynaFormulaire" property="listeMultiple">
          <tr>
          <td>liste multiple[<bean:write name="index"/>]</td>
          <td><bean:write name="choix"/></td>
        </tr>
            </logic:iterate>
fonction
Aqui, inserimos tags de lógica. Estamos lidando com uma lista de múltipla escolha. O valor do campo listeMultiple do objeto dynaFormulaire é uma matriz de String. Em Java, escreveríamos um loop. A tag logic:iterate nos permite fazer esse mesmo loop sem escrever código Java. A tag logic:iterate tem, no exemplo, os seguintes atributos:
name="dynaFormulaire": nome do objeto a ser utilizado
property="listeMultiple": nome da propriedade que, no objeto indicado por name, contém a coleção que será percorrida no loop. Aqui, essa coleção é a matriz dos valores selecionados em listeMultiple. Essa matriz pode estar vazia.
id="choix": identificador que designa o elemento atual da matriz a cada iteração do loop. Na primeira iteração, “choix” representará listeMultiple[0]; na segunda, listeMultiple[1]; e assim por diante.
indexID="index": identificador que designa o índice do elemento atual da matriz a cada volta do ciclo. Na primeira iteração, index terá o valor 0; na segunda, o valor 1; e assim por diante.
O código HTML contido entre as tags <logic:iterate ...> e </logic:iterate> é repetido para cada elemento da coleção designada pelo par (name,property). A parte dinâmica desse código é a seguinte:
          <td>liste multiple[<bean:write name="index"/>]</td>
          <td><bean:write name="choix"/></td>
Com base no que foi dito anteriormente, na iteração nº i (i>=0), o código HTML gerado é equivalente ao seguinte código:
          <td>liste multiple[<%=i%>]</td>
          <td><%=listeMultiple[i]%></td>
balise
    <html:link page="/affiche.do">
            Retour au formulaire
        </html:link>    
fonction
gera um link relativo ao contexto do aplicativo, o que dispensa a necessidade de conhecê-lo. O código HTML gerado por essa tag é o seguinte:
<a href="/formulaire2/affiche.do">Retour au formulaire</a>

6.5. As classes Java

O arquivo de configuração struts-config.xml faz referência a duas classes Java:

        <form-bean name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
...
      <action
          path="/init"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          type="istia.st.struts.formulaire.InitFormulaireAction"
      >

A classe DynaFormulaire é a classe que conterá os valores da visualização nº 1 formulaire.jsp. A classe InitFormulaireAction é a classe que processará os valores do formulário enviado pelo botão [Envoyer] de formulaire.jsp.

6.5.1. A classe DynaFormulaire

Para armazenar os valores de um formulário, basta um objeto do tipo DynaActionForm, a menos que seja necessário redefinir um dos métodos reset ou validate dessa classe. Neste caso, o método validate não precisa ser redefinido, pois não é realizada nenhuma validação de dados. Mas o método reset precisa ser redefinido. De fato, os campos do objeto DynaFormulaire receberão seus valores do formulário enviado pelo cliente web. No entanto, alguns campos podem não receber nenhum valor se não estiverem presentes na solicitação. Isso ocorre nos seguintes casos:

  • uma caixa de seleção que não foi marcada pelo usuário
  • uma lista com mais de uma opção ou nenhuma opção foi selecionada

Para formulários que contenham esse tipo de componente, o método reset deve

  • atribuir o valor “off” ao campo associado à caixa de seleção
  • atribuir a string vazia ao campo associado a uma lista de seleção única
  • atribuir um array de tamanho zero de cadeias de caracteres ao campo associado a uma lista de seleção múltipla

Assim, se esses campos não receberem um valor da consulta, eles mantêm o valor atribuído pelo método reset, valor esse que corresponde ao estado do componente no formulário validado pelo usuário (caixa de seleção desmarcada, lista sem nenhum item selecionado).

O código da classe DynaFormulaire, classe derivada de DynaActionForm, é o seguinte:

package istia.st.struts.formulaire;

import org.apache.struts.action.DynaActionForm;
import org.apache.struts.action.ActionMapping;
import javax.servlet.http.HttpServletRequest;

public class DynaFormulaire extends DynaActionForm {
  public void reset(ActionMapping mapping, HttpServletRequest request){
    // reinicialização das caixas de seleção — valor desativado
    set("chk1","off");
    set("chk2","off");
    set("chk2","off");
    // reinicialização de listeSimple - string vazia
    set("listeSimple","");
     // reinicialização de listeMultiple - matriz vazia
    set("listeMultiple",new String[]{});
  }
}

6.5.2. A classe InitFormulaireAction

A classe InitFormulaireAction está, no arquivo struts-config.xml, associada à ação /init:

      <action
          path="/init"
            name="dynaFormulaire"
            validate="false" 
            scope="session"
          type="istia.st.struts.formulaire.InitFormulaireAction"
      >
            <forward name="afficherFormulaire" path="/vues/formulaire.jsp"/>
        </action>

A ação /init é utilizada apenas uma vez durante a construção inicial do objeto DynaFormulaire. Seu objetivo é fornecer conteúdo às três listas do formulário de combinação, listeSimple, listeMultiple. Esse conteúdo é fornecido na forma de três tabelas, que são propriedades do objeto dynaFormulaire:

        <form-bean name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
            <form-property name="opt" type="java.lang.String" initial="non"/>
...
            <form-property name="valeursCombo" type="java.lang.String[]" />
            <form-property name="valeursListeSimple" type="java.lang.String[]" />
            <form-property name="valeursListeMultiple" type="java.lang.String[]"/>                                          
        </form-bean>            

Depois que as tabelas valeursCombo, valeursListeSimple e valeursListeMultiple forem inicializadas pela InitFormulaireAction, não será mais necessário inicializá-las novamente. De fato, o objeto dynaFormulaire é inserido na sessão e, portanto, mantém seu valor ao longo dos ciclos de solicitação-resposta. É por isso que a ação /init é executada apenas uma vez. O código de InitFormulaireAction é o seguinte:

package istia.st.struts.formulaire;

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

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

     // prepara o formulário para exibição

     // insere as informações necessárias no bean do formulário
    DynaFormulaire formulaire = (DynaFormulaire) form;
    formulaire.set("valeursCombo", getValeurs(5, "combo"));
    formulaire.set("valeursListeSimple", getValeurs(7, "simple"));
    formulaire.set("valeursListeMultiple", getValeurs(10, "multiple"));
     // retorna o controle
    return mapping.findForward("afficherFormulaire");
  } //executa

   // lista dos valores do menu suspenso
  private String[] getValeurs(int taille, String label) {
    String[] valeurs = new String[taille];
    for (int i = 0; i < taille; i++) {
      valeurs[i] = label + i;
    }
    return valeurs;
  }
}
  • A classe deriva da classe Action. Isso é obrigatório.
  • O controlador Struts utiliza um objeto Action por meio de seu método execute. Portanto, é esse método que deve ser redefinido. Esse método recebe os seguintes parâmetros:
    • ActionMapping mapping: um objeto que representa a configuração da aplicação em struts-config.xml
    • ActionForm form: o formulário associado à ação, caso haja um definido na configuração da ação (atributo name da ação).
    • HttpServletRequest request: a solicitação do cliente
    • HttpServletResponse: a resposta ao cliente
  • a classe InitFormulaireAction deve inicializar o formulário dynaFormulaire. Este chega ao método execute na forma do parâmetro ActionForm form. Vale lembrar que dynaFormulaire é do tipo DynaFormulaire, classe derivada da classe DynaActionForm, que por sua vez é derivada da classe ActionForm.
  • No método `execute`, são atribuídos valores aos três campos valeursCombo, valeursListeSimple e valeursListeMultiple por meio do método `set` da classe DynaActionForm. Esses valores são matrizes arbitrárias por uma questão de simplicidade. Observe que o método `set` atribui um valor a um campo existente. Ele não pode ser usado para criar novos campos. Por isso, é necessário definir os três campos valeursCombo, valeursListeSimple, valeursListeMultiple na definição do objeto dynaFormulaire em struts-config.xml.
  • O método `execute` é concluído retornando ao controlador a chave da visualização a ser exibida como resposta ao cliente. Aqui, trata-se da chave afficherFormulaire, que, no arquivo struts-config.xml, foi associada à visualização /vues/formulaire.jsp.

6.6. Implantação

A estrutura da aplicação é a seguinte:

  

Image

Image

Vale lembrar que o arquivo ApplicationResources.properties acima é necessário para a biblioteca de tags struts-bean. Sabe-se que esse arquivo contém as mensagens do aplicativo. Elas estão acessíveis à biblioteca struts-bean. Aqui, nosso aplicativo não define nenhuma mensagem. Portanto, o arquivo ApplicationResources.properties existe, mas está vazio.

6.7. Conclusão

Nesta lição, detalhamos como gerenciar os diferentes componentes de um formulário HTML. Agora podemos utilizar formulários complexos em nossas aplicações Struts.