Skip to content

6. Formulários HTML

Até agora, utilizámos um único formulário contendo apenas dois campos de entrada. Aqui, propomos criar e processar um formulário utilizando componentes gráficos padrão (botões de opção, caixas de seleção, campos de entrada, caixas combinadas, listas).

6.1. As vistas da aplicação

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

VISTA 1 - formulário

Image

Esta primeira vista, denominada form.jsp, permitir-nos-á implementar várias tags da biblioteca struts-html. O utilizador preenche o formulário:

Image

O botão [Submit] confirma os valores introduzidos. Esta será a segunda vista:

Image

Esta segunda vista permite-nos utilizar duas outras bibliotecas de tags: struts-bean e struts-logic. A ligação [Voltar ao formulário] permite-nos regressar ao formulário tal como o preenchemos. Somos então redirecionados para a primeira vista.

6.2. A arquitetura da aplicação

  • O formulário (vista 1) será representado por um objeto Struts dinâmico chamado dynaFormulaire, uma subclasse de DynaActionForm. Será apresentado pela vista form.jsp.
  • A ação Struts InitFormulaireAction será responsável por recuperar os dados necessários para exibir o formulário
  • O formulário preenchido será processado por uma ForwardAction, que simplesmente redirecionará a solicitação para a segunda vista, confirmation.jsp. Esta vista será responsável por exibir os valores do formulário.

6.3. Configuração da aplicação

6.3.1. O ficheiro server.xml

O contexto da aplicação será denominado /formulaire2. Por conseguinte, adicionaremos a seguinte linha ao ficheiro server.xml do Tomcat:

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

Depois de fazer isto, poderá ser necessário reiniciar o Tomcat para que reconheça o novo contexto. Podemos verificar se está válido solicitando o URL http://localhost:8080/formulaire2:

Image

6.3.2. O ficheiro web.xml

O ficheiro de configuração web.xml da aplicação terá o seguinte conteúdo:

<?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 comparação com os ficheiros de configuração web.xml que já vimos, estamos a fazer algumas alterações:

  • Apresentamos duas novas bibliotecas de tags: struts-bean e struts-logic. Estas serão utilizadas na vista confirmation.jsp. Por outro lado, a vista formulaire.jsp utilizará a biblioteca struts-html.

6.3.3. O ficheiro struts-config.xml

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

Contém três secções principais:

  • a declaração de formulários na secção <form-beans>
  • a declaração de ações na secção <action-mappings>
  • a declaração do ficheiro de recursos em <message-resources>

6.3.4. Os objetos de formulário da aplicação (beans)

Os objetos utilizados para representar os formulários HTML da aplicação são do tipo ActionForm ou de um tipo derivado (DynaActionForm, DynaValidatorForm, etc.). São chamados de beans porque a sua construção segue as regras dos JavaBeans. Existe apenas um bean de formulário na nossa aplicação, chamado dynaFormulaire e derivado de DynaActionForm. Será utilizado nas seguintes situações:

  • para conter os dados necessários para exibir a vista n.º 1
  • para recuperar os valores do formulário na vista n.º 1 quando o utilizador o enviar
  • para conter os dados necessários para exibir a vista #2

A estrutura do bean dynaFormulaire está intimamente ligada ao formulário na vista #1. Vamos examiná-la:

N.º
Tipo de HTML
Função
1
<input name="opt" type="radio" value="yes">
<input name="opt" type="radio" value="no">
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
(não é o mesmo nome)
3
<input type="text" name="inputField">
um campo de texto
4
<input type="password" name="password">
um campo de palavra-passe
5
<textarea name="inputBox">...</textarea>
um campo de entrada com várias linhas
6
<select name="combo" size="1">..</select>
um menu suspenso
7
<select name="simpleList" 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="Limpar"
onclick='clearList("singleList")'>
botão para desmarcar
os itens selecionados na simpleList (7)
10
<input type="button" value="Limpar"
onclick='clearList("multipleList")'>
botão para desmarcar
os itens selecionados na multipleList (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 considerar vários casos:

  1. O objeto dynaFormulaire é utilizado para armazenar os valores do formulário HTML acima, que serão enviados através do botão [Submit]. Por conseguinte, deve ter os mesmos campos que o formulário HTML. O tipo de campo é determinado pela seguinte regra:
  • se o campo HTML fornecer apenas um valor, então o campo 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 ser associado a vários valores (os selecionados pelo utilizador). Por conseguinte, uma definição inicial 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 é que o dynaFormulaire será preenchido com os valores do formulário HTML enviados pelo cliente web?

opt
O campo opt receberá o valor "yes" se o campo HTML <input type="radio" name="opt" value="yes"> tiver sido selecionado, e o valor "no" se o campo <input type="radio" name="opt" value="no"> tiver sido selecionado.
chk1
O campo chk1 receberá o valor "on" se o campo HTML <input name="chk1" type="radio" value="1"> tiver sido selecionado; caso contrário, não receberá nada. Neste último caso, o campo chk1 manterá o seu valor anterior.
chk2
o mesmo
chk3
igual
campo de entrada
O campo `champSaisie` receberá o texto introduzido pelo utilizador no campo HTML `<input type="text" name="champSaisie">`. Este texto pode ser uma cadeia vazia.
password
O campo mdp receberá o texto introduzido pelo utilizador no campo HTML <input type="password" name="mdp">. Este texto pode ser uma cadeia vazia.
textarea
O campo inputBox receberá o texto introduzido pelo utilizador no campo HTML <textarea name="inputBox">...</textarea>. Este texto forma uma única cadeia, composta pelas linhas digitadas pelo utilizador, separadas umas das outras pela sequência de caracteres "\r\n". O texto resultante pode, opcionalmente, ser uma cadeia vazia.
combo
O campo combo receberá a opção selecionada pelo utilizador no campo HTML <select name="combo" size="1">..</select>. A opção selecionada é aquela que aparece na caixa de combinação. Se a opção HTML selecionada for do tipo <option value="XX">YY</option>, o campo combo receberá o valor "XX". Se a opção HTML selecionada for do tipo <option>YY</option>, o campo combo receberá o valor "YY".
simpleList
O campo simpleList receberá a opção selecionada pelo utilizador no campo HTML <select name="simpleList" size="..">..</select> se houver alguma. Se não houver nenhuma, o campo simpleList não receberá nenhum valor e manterá o seu valor anterior. O valor efetivamente atribuído ao campo simpleList segue as regras especificadas para a caixa de combinação.
listeMultiple
O campo listeMultiple, do tipo String[], receberá as opções selecionadas pelo utilizador no campo HTML <select name="listeMultiple" size=".." multiple>..</select>, caso existam. Se não houver nenhuma, a matriz listeMultiple não receberá nenhum valor e o seu conteúdo permanecerá inalterado. Os valores efetivamente atribuídos à matriz listeMultiple seguem as regras especificadas para a caixa combinada.
secret
O campo secret receberá o valor XX do campo HTML <input type="hidden" name="secret" value="XX">. Este texto pode, opcionalmente, ser uma cadeia de caracteres vazia.
  1. O objeto dynaFormulaire é utilizado para fornecer o conteúdo inicial da vista 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 o botão de opção a selecionar
chk1
Se chk1 tiver o valor "on", a caixa de seleção será marcada; caso contrário, não será marcada
chk2
o mesmo
chk3
igual
campo de entrada
o valor do campo será exibido no campo de entrada fieldInput
senha
o valor do campo será exibido no campo de entrada mdp
inputBox
o valor do campo será exibido na caixa de entrada inputBox
combo
O valor deste campo indica qual o item da caixa de combinação que deve ser selecionado quando o formulário for apresentado
simpleList
same
multipleList
Os valores na matriz multipleList indicam quais os itens da lista múltipla que devem ser selecionados quando o formulário é apresentado
secreto
O valor do campo será atribuído ao atributo value do campo HTML secret.

A visualização n.º 1 requer informações adicionais:

  • a lista de valores a apresentar na lista suspensa
  • a lista de valores a apresentar na lista `listeSimple`
  • a lista de valores a apresentar na multipleList

Existem várias formas de fornecer esta informação à vista. Por exemplo, os arrays colocados no pedido passado para a vista funcionariam. Aqui, colocamos esses arrays 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. Este objeto será responsável por criar as três matrizes necessárias para exibir as três listas e colocá-las no bean dynaFormulaire. O ficheiro de configuração define o âmbito deste bean como sessão. Como resultado, o controlador Struts colocará este bean na sessão. Não será, portanto, necessário regenerá-lo entre os ciclos de pedido-resposta. Consequentemente, a ação /init será chamada apenas uma vez.

  1. O objeto dynaFormulaire também é utilizado para preencher a vista n.º 2. Esta vista limita-se a apresentar os valores.

6.3.5. Ações da aplicação

As ações são tratadas por objetos do tipo Action ou tipos 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>

Note que nem sempre existe um formulário associado a uma ação. É o caso, acima, da ação /affiche. Antes de detalhar cada ação, vamos rever como o par ação-formulário funciona dentro de uma tag <action>:

  • Uma ação começa com um pedido de um cliente web e termina com o envio de uma página de resposta. Este é o ciclo de pedido-resposta cliente-servidor da web. O pedido é recebido pelo controlador Struts do tipo ActionServlet ou por uma classe derivada. Este controlador também envia a resposta.
  • O bean de formulário do tipo ActionForm ou de uma classe derivada é criado, caso ainda não exista. O controlador verifica se consegue encontrar um objeto com o nome name no âmbito especificado por scope. Se sim, utiliza-o. Se não, cria-o e coloca-o no âmbito especificado por scope, associado ao atributo especificado por name.

No exemplo da ação /init, por exemplo, o controlador chamará request.getSession().getAttribute("dynaFormulaire") para determinar se dynaFormulaire já foi criado ou não. Caso contrário, irá criá-lo e adicioná-lo à sessão utilizando uma instrução como request.getSession().setAttribute("dynaFormulaire", new DynaFormulaire(...)).

  • O controlador também procurará um objeto Action do tipo especificado pelo atributo type. Se não encontrar nenhum, ele o cria; caso contrário, ele o utiliza.
  • O método reset do bean do formulário será chamado. Este bean, exceto durante a sua criação inicial, é reutilizado. Por isso, contém dados que poderá querer «limpar». Isto é feito no método reset do bean ActionForm ou de uma classe derivada.
  • Se a ação for o destino de um formulário enviado, os valores do formulário encontrados na solicitação do cliente são copiados para os campos com o mesmo nome no bean do formulário. Note que o método reset foi chamado antes desta cópia.
  • Se a configuração especificar o atributo validate="true", o método validate do bean do formulário será chamado. Este método deve então validar os dados no bean. Esta validação ocorre normalmente apenas quando o formulário acaba de receber novos dados através de um formulário enviado e se pretende verificar a validade desses dados. Este método devolve qualquer lista de erros ao controlador num objeto ActionErrors.
  • Se o objeto ActionErrors não estiver vazio, o controlador exibe a vista especificada pelo atributo input da ação.
  • Se a validação de dados não for necessária ou se tiver sido bem-sucedida, o controlador chama o método `execute` do objeto `Action` (ou de uma classe derivada) associado à ação atual. É dentro deste método que o pedido do cliente web é processado. O método `execute` devolve um objeto `ActionForward` indexado por chaves de cadeia de caracteres. Estas chaves são as declaradas pelas tags `forward` da ação configurada. No nosso exemplo, a ação `/init` tem uma única tag `forward`. Ela associa a chave "displayForm" à vista `form.jsp`.
  • O controlador apresenta a vista associada à chave recebida. Esta vista pode, na verdade, ser uma ação, caso em que 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 pedido-resposta, quando o utilizador solicita o URL http://localhost:8080/formulaire2/init.do
  • O objeto dynaForm é criado ou reciclado. É recuperado (reciclagem) ou inserido (criação) na sessão, conforme especificado pelo atributo scope.
  • O seu método reset é chamado. O que deve ele fazer? Normalmente, os campos do objeto ActionForm são repostos para os valores padrão. No entanto, neste caso, não o faremos, porque o objeto dynaFormulaire é colocado na sessão (scope="session"). Os campos do dynaFormulaire devem, portanto, manter os seus valores. Quais são esses valores durante a criação inicial do objeto dynaFormulaire? Existem dois casos:
  • o campo tem um valor inicial especificado no ficheiro de configuração:
            <form-property name="opt" type="java.lang.String" initial="non"/>

Neste caso, o controlador Struts criará este campo com este valor inicial.

  • Se o campo não tiver um valor inicial especificado na configuração: aplicam-se as regras de inicialização do Java. Geralmente, os campos numéricos terão o valor zero, as cadeias de caracteres terão a cadeia vazia e outros objetos terão o valor nulo.

Vejamos a configuração inicial do 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 do dynaFormulaire após a criação serão os seguintes:

Campo
Valor inicial
opt
"não"
chk1, chk2, chk3
cadeia vazia
campo de entrada
cadeia vazia
mdp
cadeia de caracteres vazia
caixa de entrada
cadeia vazia
lista suspensa
cadeia vazia
lista simples
cadeia vazia
lista múltipla
matriz de cadeias vazias
segredo
"xxx"
comboValues, singleList, multipleList
matriz de cadeias de caracteres vazias
  • Pode-se imaginar que o método reset do dynaFormulaire atribua valores às três matrizes que preenchem as três listas na vista formulaire.jsp. Isso seria possível aqui porque os dados nessas três matrizes são gerados arbitrariamente. No entanto, o cenário mais comum é que estes dados provenham do modelo da aplicação, o M em MVC. Aqui, vamos optar por um meio-termo — para manter o exemplo simples — fazendo com que estes valores sejam gerados pela ação InitFormulaireAction, ou seja, pelo C em MVC.
  • Não há necessidade de escrever um método reset no dynaFormulaire, uma vez que a classe ActionForm da qual deriva já possui um método desse tipo que não faz nada (sem inicializações).
  • Assim que o método reset do dynaFormulaire é chamado, o controlador verifica o atributo validate da ação. Aqui, este tem o valor «false». O método validate do dynaFormulaire não será chamado.
  • O objeto InitFormulaireAction é criado ou reutilizado, caso já existisse, e o seu método execute é chamado. Este método atribui valores arbitrários às três matrizes do dynaFormulaire: valeursCombo, valeursListeSimple e valeursListeMultiple. O método retorna um ActionForward com a chave "afficherFormulaire".
  • O controlador apresenta a vista /vues/formulaire.jsp, que foi associada à chave «afficherFormulaire» através de uma 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 utilizador clica no botão [Submit] na vista n.º 1. O navegador, então, "envia" o formulário preenchido pelo utilizador para o controlador Struts.
  • O objeto dynaFormulaire é recuperado da sessão
  • o seu método reset é chamado. Assim que for chamado, o controlador Struts irá copiar os valores dos campos do formulário enviados pelo cliente para os campos com o mesmo nome no dynaFormulaire. Vamos rever a lista de campos no dynaFormulaire e ver como funciona esta cópia:
Campo
Código HTML associado
Valor do campo
após a cópia dos valores do formulário
opt
<input type="radio" name="opt" value="yes">Sim
<input type="radio" name="opt" value="no" checked="checked">Não
- «sim» ou «não», dependendo do botão de opção selecionado
chk1
<input type="checkbox" name="chk1" value="on">
- "on" se a caixa de seleção chk1 tiver sido marcada
- mantém o 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 o 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 seu valor anterior se a caixa de seleção chk3 não tiver sido marcada
campo de entrada
<input type="text" name="inputField" value="">
- valor introduzido pelo utilizador no inputField
password
<input type="password" name="password" value="">
- valor introduzido pelo utilizador no campo password
caixa de entrada
<textarea name="inputBox"></textarea>
- valor introduzido pelo utilizador na caixa de texto
combo
<select name="combo">...</select>
- valor selecionado pelo utilizador na lista suspensa
simpleList
<select name="simpleList" size="3">...</select>
- valor selecionado pelo utilizador na simpleList
multipleList
<select name="listeMultiple" multiple="multiple" size="5">
- matriz de cadeias de caracteres contendo os valores selecionados pelo utilizador em multipleList
secret
<input type="hidden" name="secret" value="xxx">
- "xxx".

Encontramos um problema com campos que não recebem necessariamente um valor na solicitação enviada pelo navegador. Isto aplica-se às caixas de seleção chk1 a chk3 e às duas listas listeSimple e listeMultiple. Neste caso, estes campos mantêm os seus valores anteriores — aqueles obtidos durante o ciclo anterior de solicitação-resposta.

Consideremos, por exemplo, a caixa de seleção chk1 e suponhamos que, no ciclo anterior de pedido-resposta, o utilizador tenha marcado essa caixa. O navegador enviou então a informação chk1="on" na cadeia de parâmetros do seu pedido. O construtor atribuiu, assim, o valor "on" ao campo chk1 do dynaFormulaire. Suponhamos agora que, no ciclo atual, o utilizador não marque a caixa de seleção chk1. Neste caso, na cadeia de parâmetros da nova solicitação, o navegador não envia algo como chk1="off", mas sim nada. Como resultado, o campo chk1 no dynaFormulaire manterá o seu valor "on" e, assim, terá um valor que não reflete o do formulário validado pelo utilizador. Vamos utilizar o método reset do dynaFormulaire para resolver este problema. Neste método, vamos definir os três campos chk1, chk2 e chk3 como "off". No nosso exemplo chk1, ou o utilizador:

  • marca a caixa de seleção chk1. Neste caso, o navegador envia a informação chk1="on" e o campo chk1 no dynaFormulaire muda para "on"
  • não marca a caixa de seleção chk1. Nesse caso, o navegador não envia um valor para o campo chk1, que manterá o seu valor anterior "off". Em ambos os casos, o valor armazenado no campo chk1 do dynaFormulaire está correto.

O problema é semelhante tanto para as listas simpleList como para as multiList. Se nenhuma opção tiver sido selecionada nessas listas, elas não estarão presentes nos parâmetros da solicitação e, portanto, manterão os seus valores anteriores. No método reset do dynaFormulaire, iremos reiniciar a simpleList com uma string vazia e a multiList com uma matriz de strings de comprimento 0.

  • Assim que o método reset do dynaFormulaire é chamado, o controlador copia as informações que lhe foram enviadas na solicitação do cliente de volta para os campos do dynaFormulaire
  • É criado ou reutilizado um objeto ForwardAction, e o seu método execute é chamado. ForwardAction é uma classe predefinida que retorna um objeto ActionForward apontando para a vista definida pelo atributo “parameter” da ação, neste caso /vues/confirmation.jsp.
  • O controlador envia esta vista. O ciclo está completo.

O /display

      <action
          path="/affiche"
          parameter="/vues/formulaire.jsp"
          type="org.apache.struts.actions.ForwardAction"
      />
  • A ação /display é acionada ao clicar no link [Voltar ao formulário] na vista n.º 2.
  • Aqui, não existe nenhum formulário associado à ação. Por isso, passamos diretamente à execução do método `execute` de um objeto `ForwardAction`, que irá devolver um objeto `ActionForward` a apontar para a vista `/vues/formulaire.jsp`.

6.3.6. O ficheiro de mensagens da aplicação

A terceira secção do ficheiro struts-config.xml é o ficheiro de mensagens:

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

O ficheiro ApplicationResources.properties está localizado em WEB-INF/classes. Estará vazio. Apesar de estar vazio, deve ser declarado no ficheiro de configuração; caso contrário, a biblioteca de tags struts-bean, que discutiremos mais adiante, irá gerar um erro. Esta biblioteca é utilizada pela vista confirmation.jsp.

6.4. O código da vista

6.4.1. A vista formulaire.jsp

Lembre-se de que esta vista é apresentada em dois casos:

  • quando a ação /init é chamada durante o primeiro ciclo de pedido-resposta
  • quando a ação /affiche é chamada durante os ciclos subsequentes

O código da vista 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 da biblioteca struts-html. Lembre-se de que, para utilizar uma biblioteca de tags, deve:

  • declará-la no ficheiro web.xml da aplicação utilizando 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 desta biblioteca em algum local na árvore de diretórios da aplicação, neste caso WEB-INF/struts-html.tld
  • Declare a utilização desta biblioteca no início das páginas JSP que a utilizam:
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>

A vista formulaire.jsp utiliza tags que iremos explicar a seguir:

tag
<body background="<html:rewrite page="/images/standard.jpg"/>">
Tradução para HTML
<body background="/formulaire2/images/standard.jpg">
explicação
A tag html:rewrite permite omitir o nome da aplicação dos URLs. Possui um atributo:
página
URL a reescrever
Assim, no exemplo acima, se decidir nomear a aplicação «form3», o código para o atributo background não precisa de ser reescrito. A tag `html:rewrite` irá gerar o novo código HTML
background="/formulaire3/images/standard.jpg"
tag
<html:form action="/confirmation" name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
Tradução para HTML
<form name="dynaFormulaire" method="post" action="/formulaire2/confirmation.do">
explicação
A tag html:form gera a tag de formulário HTML. 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 no struts-config.xml
name
opcional — nome do bean ActionForm ou de uma subclasse do mesmo, no qual os valores do formulário enviado devem ser colocados ou lidos. Se este atributo for omitido, é utilizado o formulário associado à ação definida pelo atributo action. Esta informação encontra-se no ficheiro de configuração (o atributo name da ação).
type
opcional - Classe Java a instanciar para o formulário. Se este atributo for omitido, é utilizada a classe associada à ação definida pelo atributo action. Esta informação encontra-se no ficheiro de configuração (atributo type da ação).
Podemos ver que, por predefinição, o código HTML gerado utiliza o método POST. Neste mesmo código HTML, o URL da ação foi reescrito para incluir o nome da aplicação como prefixo e .do como sufixo.
tag
<html:radio name="dynaFormulaire" property="opt" value="yes">Sim</html:radio>
Tradução para HTML
<input type="radio" name="opt" value="yes">
explicação
A tag html:radio é utilizada para gerar a tag HTML <input type="radio" ...>. Suporta vários atributos:
name
opcional - nome do bean ActionForm ou bean derivado no qual o valor do campo deve ser colocado ou lido. Se este atributo for omitido, é utilizado o formulário associado à tag <html:form>.
property
Nome do campo no bean do formulário associado ao botão de opção para leitura e gravação.
valor
opcional - valor a atribuir 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.
tag
<html:checkbox name="dynaFormulaire" property="chk1">1</html:checkbox>
Tradução para HTML
<input type="checkbox" name="chk1" value="on">
explicação
A tag html:checkbox é utilizada para gerar a tag HTML <input type="checkbox" ...>. Suporta vários atributos:
name
opcional - nome do bean ActionForm ou bean derivado no qual o valor do campo deve ser colocado ou lido. Se este atributo for omitido, é utilizado o formulário associado à tag <html:form>.
property
Nome do campo no bean do formulário associado à caixa de seleção para leitura e gravação.
valor
opcional - valor a atribuir 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.
tag
<html:text name="dynaFormulaire" property="inputField" />
Tradução para HTML
<input type="text" name="inputField" value="">
explicação
A tag html:text é utilizada para gerar a tag HTML <input type="text" ...>. Suporta vários atributos:
name
opcional - nome do bean ActionForm ou de um bean derivado no qual o valor do campo deve ser inserido ou lido. Se este atributo for omitido, é utilizado o formulário associado à tag <html:form>.
propriedade
Nome do campo no bean do formulário associado ao campo de entrada de leitura e escrita.
valor
opcional - valor a atribuir ao campo HTML
etiqueta
<html:password name="dynaFormulaire" property="mdp" />
Tradução para HTML
<input type="password" name="mdp" value="">
explicação
A tag html:password é utilizada para gerar a tag HTML <input type="password" ...>. Suporta vários atributos:
etiqueta
<html:textarea name="dynaFormulaire" property="boiteSaisie" />
Tradução para HTML
<textarea name="boiteSaisie"></textarea>
explicação
A tag HTML:textarea é utilizada para gerar a tag HTML <textarea>...</textarea>. Suporta vários atributos:
name
opcional - nome do bean ActionForm ou bean derivado no qual o valor do campo deve ser colocado ou lido. Se este atributo for omitido, é utilizado o formulário associado à tag <html:form>.
property
Nome do campo no bean do formulário associado ao campo de palavra-passe para leitura e gravação.
valor
opcional - valor a atribuir ao campo HTML
etiqueta
<html:select name="dynaFormulaire" property="combo">....</html:select>
Tradução para HTML
<select name="combo">...</select>
explicação
A tag HTML:select é utilizada para gerar a tag HTML <select>...</select>. Suporta vários atributos:
name
opcional - nome do bean ActionForm ou bean derivado no qual o valor do campo deve ser colocado ou lido. Se este atributo for omitido, é utilizado o formulário associado à tag <html:form>.
property
Nome do campo no bean do formulário associado ao campo de entrada de leitura e escrita.
valor
opcional - valor a atribuir ao campo HTML. A opção da caixa combinada com este valor será selecionada.
etiqueta
<html:select name="dynaFormulaire" property="combo">
<html:options name="dynaFormulaire" property="comboValues"/>
</html:select>
Tradução para HTML
<option value="combo1">combo1</option>
<option value="combo2">combo2</option>

explicação
A tag HTML:options é utilizada para gerar as tags HTML <option>...</option> dentro de uma tag HTML <select>. Existem várias formas de especificar como encontrar os valores para preencher o elemento select. Aqui, utilizámos os atributos name e property:
name
opcional - nome do bean ActionForm ou bean derivado no qual o valor do campo deve ser colocado ou lido. Se este atributo for omitido, é utilizado o formulário associado à tag <html:form>.
property
Nome do campo no bean do formulário que contém os valores de seleção. Deve ser uma matriz de cadeias de caracteres.

As outras duas listas são geradas de forma semelhante à anterior:

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

Acima, especificamos um atributo size diferente de 1 para criar uma lista em vez de uma caixa combinada.

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

Acima, especificamos o atributo multiple="true" para criar uma lista com várias seleções.

tag
<html:hidden name="dynaFormulaire" property="secret"/>
Tradução para HTML
<input type="hidden" name="secret" value="xxx">
explicação
A tag html:hidden é utilizada para gerar a tag HTML <input type="hidden" ...>.
nome
opcional - nome do bean ActionForm ou bean derivado no qual o valor do campo deve ser colocado ou lido. Se este atributo for omitido, é utilizado o formulário associado à tag <html:form>.
propriedade
Nome do campo no bean do formulário associado ao campo oculto. O valor «xxx» atribuído ao campo HTML secreto provém da definição do formulário no ficheiro de configuração. Um valor inicial de «xxx» foi definido nesse ficheiro para o campo secreto.

Para compreender plenamente a relação entre a vista «formulaire.jsp» e o bean «dynaFormulaire» que a representa na memória, é importante ter em conta que o bean «dynaFormulaire» é utilizado tanto para a leitura como para a gravação:

A solicitação ocorre quando o utilizador clica no botão [Submit] no formulário. O navegador, então, «envia» o formulário HTML para a ação /confirmation. Já explicámos o que acontece a seguir e, em particular, que os campos dynaFormulaire receberão os valores dos campos com o mesmo nome no formulário HTML.

O que acontece quando o controlador solicita que a página formulaire.jsp seja apresentada em resposta a um pedido? Vamos analisar as tags uma a uma:

tag
<body background="<html:rewrite page="/images/standard.jpg"/>">
função
gera o código HTML
<body background="/formulaire2/images/standard.jpg">
tag
<html:form action="/confirmation" name="dynaFormulaire" type="istia.st.struts.formulaire.DynaFormulaire">
...
</html:form>
função
gera o código HTML
<form name="dynaFormulaire" method="post" action="/formulaire2/confirmation.do">
tag
<html:radio name="dynaFormulaire" property="opt" value="yes">Sim</html:radio>
<html:radio name="dynaFormulaire" property="opt" value="no">Não</html:radio>
função
Se o campo opt de dynaFormulaire for "sim", gere o código HTML
<input type="radio" name="opt" value="yes" checked="checked">Sim
<input type="radio" name="opt" value="no">Não
tag
<html:checkbox name="dynaFormulaire" property="chk1">1</html:checkbox>
<html:checkbox name="dynaFormulaire" property="chk2">2</html:checkbox>
<html:checkbox name="dynaForm" property="chk3">3</html:checkbox>
função
Se os campos chk1 e chk3 de dynaFormulaire estiverem "ativados" e o campo chk2 estiver "desativado", 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
tag
<html:text name="dynaFormulaire" property="inputField" />
função
se o campo de entrada estiver definido como "isto é um teste", gerar o código HTML
<input type="text" name="inputField" value="isto é um teste">
tag
<html:password name="dynaFormulaire" property="password" />
função
Se o campo da palavra-passe for «azerty», gere o código HTML
<input type="password" name="password" value="azerty">
tag
<html:password name="dynaFormulaire" property="mdp" />
função
Se o campo "mdp" for "azerty", gere o código HTML
<input type="password" name="password" value="azerty">
tag
<html:password name="dynaFormulaire" property="mdp" />
função
Se o campo "mdp" for "azerty", gere o código HTML
<input type="password" name="password" value="azerty">
tag
<html:select name="dynaFormulaire" property="combo">
<html:options name="dynaFormulaire" property="comboValues"/>
</html:select>
função
se o campo combo for "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>
tag
<html:select name="dynaFormulaire" property="simpleList" size="3">
<html:options name="dynaFormulaire" property="simpleListValues"/>
</html:select>
função
se o campo simpleList for "simple1", gera o código HTML
<select name="simpleList" size="3">
    <option value="simple0">simple0</option>
    <option value="simple1" selected="selected">simple1</option>
    <option value="simple2">simple2</option>
...
</select>
tag
<html:select name="dynaFormulaire" property="listeMultiple" size="5" multiple="true">
<html:options name="dynaFormulaire" property="multipleListValues"/>
</html:select>
função
Se o campo listeMultiple for a matriz {"multiple0", "multiple2"}, gera o código HTML
<select name="multipleList" 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>
tag
<html:hidden name="dynaFormulaire" property="secret"/>
função
se o campo secreto tiver o valor "xxx", gerar o código HTML
<input type="hidden" name="secret" value="xxx">
tag
<html:submit>Enviar</html:submit>
função
gera o código HTML
<input type="submit" value="Enviar">

A última coisa a explicar é o código JavaScript incluído na página JSP e associado aos dois botões [Limpar] que desmarcam os itens selecionados nas listas simpleList e multipleList:

<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 compreender o código JavaScript associado aos botões [Limpar], vamos rever como os vários elementos de um documento web são referenciados no código JavaScript que utiliza esse documento:

Dados
Significado
document
refere-se a todo o documento web
document.forms
refere-se ao conjunto de formulários definidos no documento
document.forms[i]
refere-se ao formulário número i no documento
document.forms["formName"]
refere-se ao formulário <form> com o atributo name definido como "formName"
document.formName
refere-se ao formulário <form> cujo atributo name é igual a "formName"
document.[form].elements
refere-se à coleção de elementos pertencentes ao formulário designado pela expressão [form]. Esta coleção inclui todas as tags <input>, <textarea> e <select> no formulário designado.
document.[form].elements[i]
refere-se ao elemento número i de [form]
document.[form].elements["componentName"]
refere-se ao elemento em [form] cujo atributo name é igual a componentName
document.[form]. componentName
refere-se ao elemento no [form] cujo atributo name é igual a componentName
document.[form].[component].value
refere-se ao valor do componente [component] do formulário [form] quando o seu código HTML pode ter um atributo value (<input>, <textarea>)
document.[form].[select].selectedIndex
refere-se ao índice da opção selecionada numa lista. Pode ser utilizado tanto para leitura como para escrita. Definir esta propriedade como -1 desmarca todos os itens da lista.
document.[form].[select].options
refere-se à matriz de opções associadas a uma tag <select>
document.[form].[select].options[i]
refere-se à opção número i da tag <select> especificada
document.[form].[select].options[i].selected
Um valor booleano que indica se a opção n.º i do elemento [select] especificado está selecionada (true) ou não. Pode ser utilizado tanto para leitura como para escrita

Vamos rever o código JavaScript para os 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"/>

Quando o botão é clicado, o código associado ao atributo «onclick» é executado. Aqui, trata-se de código inline. Na maioria das vezes, escrevemos onclick="function(...)", em que function é uma função definida dentro de uma tag <script language="javascript">...</script>. O que faz o código acima? Vamos analisar o código do primeiro botão:

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

6.4.2. A vista confirmation.jsp

Recorde-se que esta vista é apresentada após a ação /confirmation, ou seja, após o formulário contido na vista formulaire.jsp ter sido enviado pelo cliente web. O seu único objetivo é apresentar os valores introduzidos pelo utilizador. O 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>

Aqui apresentamos duas novas bibliotecas de tags: struts-bean e struts-logic. A biblioteca struts-bean fornece acesso a objetos no contexto da solicitação, da sessão ou da aplicação. A biblioteca struts-logic permite implementar lógica de execução utilizando tags. Nenhuma destas bibliotecas é estritamente necessária. 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 elementos dinâmicos no código HTML utilizando variáveis <%= variável %>
  • conter código Java <% código Java %>

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

Vamos proceder da mesma forma que fizemos na vista «formulaire.jsp» e explicar cada uma das tags presentes no código «confirmation.jsp», caso ainda não tenham sido abordadas na vista «formulaire.jsp». Em primeiro lugar, note-se que a página começa por declarar 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" %>

Note também que estas três bibliotecas devem ser declaradas no ficheiro web.xml da aplicação. Vamos agora comentar as tags no documento formulaire.jsp:

tag
<bean:write name="dynaFormulaire" scope="session" property="opt"/>
função
escreve um valor no fluxo HTML atual. A tag bean:write suporta os seguintes atributos:
name: nome do objeto a utilizar
scope: âmbito (request, session, context) no qual procurar este objeto
property: campo do objeto designado pelo nome cuja propriedade deve ser gravada. Este campo pode ser um objeto de qualquer tipo. Será utilizado o método toString do objeto.
Aqui, é gravado o valor do campo opt no dynaFormulaire. O resultado será «yes» se o utilizador tiver marcado o botão de opção com o atributo value="yes", ou «no» se tiver marcado o botão de opção com o atributo value="no"
tag
<bean:write name="dynaFormulaire" scope="session" property="chk1"/>
função
escreve o valor do campo chk1 no dynaFormulaire. O resultado será «on» se o utilizador tiver marcado a caixa, ou «off» caso contrário. O mesmo se aplica a chk2 e chk3.
tag
<bean:write name="dynaFormulaire" scope="session" property="inputField"/>
função
escreve o valor do campo champSaisie em dynaFormulaire, ou seja, o texto digitado pelo utilizador nesse campo. O mesmo se aplica a mdp e boiteSaisie.
tag
<bean:write name="dynaFormulaire" scope="session" property="combo"/>
função
escreve o valor do campo combo em dynaFormulaire. Este será o atributo value do elemento <option> selecionado pelo utilizador.
tag
<bean:write name="dynaFormulaire" scope="session" property="listeSimple"/>
função
grava o valor do campo simpleList no dynaForm. Este valor corresponderá ao atributo «value» do elemento <option> selecionado pelo utilizador, caso tenha sido selecionado algum. Caso contrário, será uma cadeia de caracteres vazia.
tag
            <logic:iterate id="choice" indexId="index" name="dynaForm" property="multipleList">
          <tr>
          <td>lista múltipla[<bean:write name="index"/>]</td>
          <td><bean:write name="choice"/></td>
        </tr>
            </logic:iterate>
função
Aqui, apresentamos as tags de lógica. Estamos a lidar com uma lista de escolha múltipla. O valor do campo listeMultiple do objeto dynaFormulaire é uma matriz de Strings. Em Java, escreveríamos um loop. A tag logic:iterate permite-nos executar este mesmo loop sem escrever código Java. Neste exemplo, a tag logic:iterate tem os seguintes atributos:
name="dynaFormulaire": nome do objeto a utilizar
property="listeMultiple": nome da propriedade no objeto especificado por name que contém a coleção a ser iterada no loop. Aqui, esta coleção é a matriz de valores selecionados em listeMultiple. Esta matriz pode estar vazia.
id="choix": identificador que designa o elemento atual da matriz em cada iteração. Durante a primeira iteração, choix representará listeMultiple[0], durante a segunda listeMultiple[1], e assim por diante.
indexID="index": identificador que designa o índice do elemento atual da matriz em cada iteração do ciclo. Durante a primeira iteração, index terá o valor 0; durante a 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 (nome, propriedade). A parte dinâmica deste código é a seguinte:
          <td>multiple list[<bean:write name="index"/>]</td>
          <td><bean:write name="choice"/></td>
Com base no que foi dito anteriormente, na iteração número i (i>=0), o código HTML gerado é equivalente ao seguinte:
          <td>multiple list[<%=i%>]</td>
          <td><%=multipleList[i]%></td>
tag
    <html:link page="/affiche.do">
            Voltar ao formulário
        </html:link>
função
gera um link relativo ao contexto da aplicação, o que elimina a necessidade de conhecer o contexto. O código HTML gerado por esta tag é o seguinte:
<a href="/formulaire2/affiche.do">Voltar ao formulário</a>

6.5. As classes Java

O ficheiro 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 irá conter os valores da vista n.º 1, formulaire.jsp. A classe InitFormulaireAction é a classe que irá processar os valores do formulário enviados através do botão [Submit] em 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 substituir um dos métodos reset ou validate desta classe. Aqui, o método validate não precisa de ser reescrito, uma vez que não é realizada qualquer validação de dados. No entanto, o método reset precisa de ser reescrito. Isto porque os campos do objeto DynaFormulaire receberão os seus valores do formulário enviado pelo cliente web. No entanto, alguns campos podem não receber um valor se não estiverem presentes na solicitação. Isto ocorre nos seguintes casos:

  • uma caixa de seleção que não tenha sido marcada pelo utilizador
  • uma lista com mais de uma opção, em que nenhuma foi selecionada

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

  • definir o valor «off» para o campo associado à caixa de seleção
  • definir a string vazia no campo associado a uma lista de seleção única
  • atribuir uma matriz vazia de cadeias de caracteres ao campo associado a uma lista de seleção múltipla

Assim, se estes campos não receberem um valor da consulta, mantêm o valor atribuído pela redefinição, que corresponde ao estado do componente no formulário validado pelo utilizador (caixa de seleção desmarcada, lista sem itens selecionados).

O código para a classe DynaFormulaire, uma subclasse 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){
    // reset checkboxes - value off
    set("chk1","off");
    set("chk2","off");
    set("chk2","off");
    // reset listeSimple - empty string
    set("listeSimple","");
     // reset listeMultiple - empty table
    set("listeMultiple",new String[]{});
  }
}

6.5.2. A classe InitFormAction

A classe InitFormAction está associada à ação /init no ficheiro struts-config.xml:

      <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 DynaForm. O seu objetivo é fornecer conteúdo para as três listas combinadas do formulário: simpleList, multipleList e dropdownList. Este conteúdo é fornecido na forma de três matrizes, que são propriedades do objeto dynaForm:

        <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 de as matrizes valuesCombo, valuesSingleList e valuesMultipleList terem sido inicializadas pelo InitFormAction, já não precisam de ser inicializadas. Isto deve-se ao facto de o objeto dynaForm ser colocado na sessão e, por isso, manter o seu valor ao longo dos ciclos de pedido-resposta. É por isso que a ação /init é executada apenas uma vez. O código para o InitFormAction é 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 {

     // prepares the form to be displayed

     // we put the information needed for the form in its bean
    DynaFormulaire formulaire = (DynaFormulaire) form;
    formulaire.set("valeursCombo", getValeurs(5, "combo"));
    formulaire.set("valeursListeSimple", getValeurs(7, "simple"));
    formulaire.set("valeursListeMultiple", getValeurs(10, "multiple"));
     // we give back
    return mapping.findForward("afficherFormulaire");
  } //execute

   // list of combo values
  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 estende a classe Action. Isto é obrigatório.
  • O controlador Struts utiliza um objeto Action através do seu método execute. Este é, portanto, o método que deve ser redefinido. Este método recebe os seguintes parâmetros:
    • ActionMapping mapping: um objeto que representa a configuração da aplicação no struts-config.xml
    • ActionForm form: o formulário associado à ação, caso esteja definido na configuração da ação (atributo name da ação).
    • HttpServletRequest request: o pedido do cliente
    • HttpServletResponse: a resposta ao cliente
  • A classe InitFormulaireAction deve inicializar o formulário dynaFormulaire. Este é passado para o método execute como o parâmetro de formulário ActionForm. Recorde-se que dynaFormulaire é do tipo DynaFormulaire, uma 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 utilizando o método set da classe DynaActionForm. Estes valores são matrizes arbitrárias por uma questão de simplicidade. Note-se que o método set atribui um valor a um campo existente. Não pode ser utilizado para criar novos campos. É por isso que é necessário definir os três campos valeursCombo, valeursListeSimple e valeursListeMultiple na definição do objeto dynaFormulaire no struts-config.xml.
  • O método execute termina devolvendo a chave da vista a ser apresentada ao controlador como resposta ao cliente. Aqui, trata-se da chave afficherFormulaire, que no ficheiro struts-config.xml foi associada à vista /vues/formulaire.jsp.

6.6. Implantação

A estrutura do diretório da aplicação é a seguinte:

  

Image

Image

Note que o ficheiro ApplicationResources.properties acima é exigido pela biblioteca de tags struts-bean. Sabemos que este ficheiro contém as mensagens da aplicação. Estas estão acessíveis à biblioteca struts-bean. Neste caso, a nossa aplicação não define quaisquer mensagens. Por conseguinte, o ficheiro ApplicationResources.properties existe, mas está vazio.

6.7. Conclusão

Nesta lição, detalhámos como gerir os vários componentes de um formulário HTML. Agora podemos utilizar formulários complexos nas nossas aplicações Struts.