9. Exemplo 07 – As tags de formulário
Vamos construir e utilizar o seguinte formulário:
![]() | ![]() |
Vamos estender o conceito de injeção de parâmetros, visto para um campo de entrada de texto, aos demais elementos HTML de um formulário.
9.1. O projeto NetBeans
![]() |
- em [1], as visualizações do projeto [Formx.JSP]
- em [2], o arquivo de configuração do Struts e as mensagens internacionalizadas
- em [3], as ações [Formx.java] e outro arquivo de configuração do Struts.
9.2. Configuração do Struts
O arquivo [struts.xml] é o seguinte:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.custom.i18n.resources" value="messages" />
<include file="example/example.xml"/>
<package name="default" namespace="/" extends="struts-default">
<default-action-ref name="index" />
<action name="index">
<result type="redirectAction">
<param name="actionName">Form</param>
<param name="namespace">/example</param>
</result>
</action>
</package>
</struts>
- linha 9: inclui outro arquivo de configuração, o [example.xml]. É ele que vai configurar as ações.
- linhas 11-19: o pacote default. Define um endereço de redirecionamento para o URL/. Ele será redirecionado para o URL/example/Form.action.
O arquivo [example.xml], que configura as ações, é o seguinte:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="example" namespace="/example" extends="struts-default">
<action name="Form" class="example.Form">
<result name="success">/example/Form.JSP</result>
</action>
<action name="Form1" class="example.Form1">
<result name="success">/example/Form1.JSP</result>
</action>
<action name="Form2" class="example.Form2">
<result name="success">/example/Form2.JSP</result>
</action>
</package>
</struts>
- linhas 7-17: definem as ações /example/Form, /example/Form1 e /example/Form2, em que /example é o namespace (linha 7) e Formx são as ações.
- linhas 8-10: a execução da ação Form fará com que a visualização /example/Form.JSP seja exibida.
- linhas 11-13: a execução da ação Form1 resultará na exibição da visualização /example/Form1.JSP.
- linhas 14-16: a execução da ação Form2 resultará na exibição da visualização /example/Form2.JSP.
9.3. Os arquivos de mensagens
Não nos deteremos na internacionalização do projeto. Já a estudamos no exemplo 01. Apresentamos o conteúdo do arquivo [messages.properties] para que o leitor possa compreender as visualizações a seguir.
Form.francais=Fran\u00E7ais
Form.anglais=Anglais
Form.titre=Struts 2 - les tags de formulaire
Form.message=Struts 2 - les tags de formulaire
Form.langues=langues
Form.textfield=1-textfield
Form.password=2-password
Form.textarea=3-textarea
Form.select1=4-select (multiple=false, size=1)
Form.select1.header=<-- select1 -->
Form.select2=5-select (multiple=false, size=3)
Form.select3=6-select (multiple=true, size=3)
Form.radio=7-radio
Form.checkbox=8-checkbox
Form.checkboxlist=9-checkboxlist
Form.hidden=10-hidden
Form.submitText=Valider
Form.buttonRazText=Raz
Confirmation.message=Confirmation des valeurs saisies
Confirmation.champ=champ
Confirmation.valeur=valeur
Confirmation.textfield=1-textfield
Confirmation.password=2-password
Confirmation.textarea=3-textarea
Confirmation.select1=4-select (multiple=false, size=1)
Confirmation.select2=5-select (multiple=false, size=3)
Confirmation.select3=6-select (multiple=true, size=3)
Confirmation.radio=7-radio
Confirmation.checkbox=8-checkbox
Confirmation.checkboxlist=9-checkboxlist
Confirmation.hidden=10-hidden
9.4. A tela [Form.JSP] – parte de entrada
Sua aparência visual é a seguinte:
![]() |
É a seguinte:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title><s:text name="Form.titre"/></title>
<s:head/>
</head>
<body background="<s:url value="/ressources/standard.jpg"/>">
<h2><s:text name="Form.message"/></h2>
<h3><s:text name="Form.langues"/></h3>
<ul>
<li>
<s:url id="URL" action="Form">
<s:param name="request_locale">en</s:param>
</s:url>
<s:a href="%{URL}"><s:text name="Form.anglais"/></s:a>
</li>
<li>
<s:url id="URL" action="Form">
<s:param name="request_locale">fr</s:param>
</s:url>
<s:a href="%{URL}"><s:text name="Form.francais"/></s:a>
</li>
</ul>
<s:form name="formulaire">
<s:textfield name="textfield" key="Form.textfield" />
<s:password name="password" key="Form.password"/>
<s:textarea name="textarea" key="Form.textarea" cols="40" rows="5"/>
<s:select name="select1" list="select1Values" size="1" key="Form.select1" headerValue="<-- select 1 -->" headerKey="-1" />
<s:select name="select2" size="3" list="select2Values" key="Form.select2"/>
<s:select name="select3" size="3" list="select3Values" key="Form.select3" multiple="true"/>
<s:radio name="radio" list="radioValues" key="Form.radio"/>
<s:checkbox name="checkbox" key="Form.checkbox"/>
<s:checkboxlist name="checkboxlist" list="checkboxlistValues" key="Form.checkboxlist"/>
<s:hidden name="hidden" key="Form.hidden"/>
<s:submit key="Form.submitText" name="submitText"/>
</s:form>
<hr/>
...
</body>
</html>
- O formulário começa na linha 26 e termina na linha 38. Na linha 26, o atributo action está ausente. Esse atributo especifica para qual ação os dados do formulário serão enviados. Na ausência do atributo action, os dados serão enviados para a ação que levou à exibição da visualização, neste caso, a ação [Form].
- linha 27: um campo de entrada. O atributo key especifica seu rótulo. O atributo name é o nome do parâmetro que será enviado. A string enviada para este campo terá o seguinte formato:
O nome do parâmetro corresponde a um campo da ação [Form]. O valor do campo de entrada texte_saisi será aqui inserido no campo textfield da ação [Form]. Por outro lado, se a visualização [Form.JSP] for exibida após a ação [Form], o valor do campo de entrada será o do campo textfield da ação [Form]. Portanto, esse campo é utilizado tanto para leitura quanto para gravação. Para isso, a classe [Form] deve possuir os métodos getTextField e setTextField.
Esse raciocínio se aplica a todas as tags de entrada que virão a seguir. Não vamos repeti-lo.
- linha 28: inserção de uma senha. A string enviada para a ação [Form] terá o formato
Deve existir um campo password com seus métodos get/set na ação [Form].
- linha 29: inserção de um texto com várias linhas em uma área de 5 linhas e 40 colunas. A string enviada para a ação [Form] terá o formato
Um campo textarea com seus métodos get/set deve existir na ação [Form].
- linha 30: uma lista suspensa (size=1) com seleção única. Apenas um valor da lista pode ser selecionado. A string enviada para a ação [Form] terá o formato:
Deve existir um campo select1 com seus métodos get/set na ação [Form].
O atributo key é o título da lista. O atributo list define a lista de valores a serem inseridos no combo box. Aqui, o método getSelect1Values da ação [Form] será chamado para preencher o combo box. Esse método pode retornar uma coleção, um dicionário ou um array. Nesse caso, ele retornará uma matriz de cadeias de caracteres [chaine1, chaine2, ...] que gerará o seguinte código HTML:
<option value="chaine1">chaine1</option>
<option value="chaine2">chaine2</option>
...
O texto entre as tags <option>...</option> será exibido na lista suspensa. O atributo value indica o valor a ser enviado caso a opção seja selecionada pelo usuário. Aqui, o atributo value e o texto exibido na lista suspensa são idênticos. Na maioria das vezes, esse não é o caso. Se a segunda opção for selecionada, a seguinte sequência de caracteres será enviada para a ação [Form]:
O campo [Form].select1 receberá, então, o valor chaine2. Por outro lado, se, no momento da exibição do formulário, esse campo tiver o valor chaine3, então, visualmente, o terceiro elemento
<option value="chaine3">chaine3</option>
aparecerá selecionado na lista suspensa.
O atributo headerValue define o texto a ser exibido como a primeira opção da lista suspensa e headerKey define o valor a ser enviado caso essa opção seja escolhida pelo usuário.
- linha 31: mais uma vez, uma lista de tamanho 3 (size=3): ao contrário da lista anterior, em que apenas um elemento é visível, aqui três elementos da lista estarão visíveis. O modo de seleção permanece o mesmo. Só é possível selecionar um elemento.
- linha 32: novamente uma lista, mas com seleção múltipla (multiple=true). Nesse caso, o valor enviado para a ação [Form] terá o seguinte formato:
se as opções chaine2 e chaine5 tiverem sido selecionadas. Quando vários valores são lançados para um mesmo parâmetro, neste caso select3, a ação deve ter um campo com o nome do parâmetro e ser do tipo tableau. Assim, por exemplo, neste caso, a ação [Form] poderia ter um campo do tipo:
e os métodos get/set correspondentes. A matriz select3 receberá, então, a matriz de cadeias de caracteres [chaine2,chaine5]. Por outro lado, ao exibir a visualização [Form.JSP], os valores do campo [Form].select3 determinam quais opções da lista select3 aparecerão selecionadas. Estamos sempre em modo de leitura/gravação.
- linha 33: um grupo de botões de opção. O rótulo do grupo é fornecido pelo atributo key. Os rótulos dos botões individuais são fornecidos pelo atributo list. O valor desse atributo é o nome de um método da ação [Form], que deve retornar uma coleção, um dicionário ou uma matriz. Aqui, o método [Form].getRadioValues retornará uma matriz de cadeias de caracteres [chaine1,chaine2,...], que gerará as seguintes tags HTML:
<input type="radio" name="radio" ... value="chaine1"/>chaine1
<input type="radio" name="radio" ... value="chaine2"/>chaine2
...
Se o botão de opção chaine2 estiver marcado, o valor enviado será
e esse valor será inserido no campo [Form].radio.
- linha 34: uma caixa de seleção. Se estiver marcada, a seguinte sequência de parâmetros será enviada para a ação [Form]
Se não estiver marcada, nenhuma sequência de parâmetros será enviada. O Struts 2 possui um mecanismo interno que faz com que tudo ocorra como se a sequência
tivesse sido enviada.
- linha 35: uma lista de caixas de seleção. É possível marcar várias delas. O texto do grupo é fornecido pelo atributo key. Os rótulos das caixas de seleção individuais são fornecidos pelo atributo list. O valor desse atributo é o nome de um método da ação [Form], que deve retornar uma coleção, um dicionário ou um array. Nesse caso, o método [Form].getCheckboxlistValues retornará uma matriz de cadeias de caracteres [chaine1,chaine2,...], que gerará as seguintes tags HTML:
<input type="checkbox" name="checkboxlist" ... value="chaine1"/>chaine1
<input type="checkbox" name="checkboxlist" ... value="chaine2"/>chaine2
...
Se o usuário marcar as caixas de seleção denominadas chaine2 e chaine5, a seguinte sequência de caracteres será enviada para a ação [Form]:
A tabela [chaine2, chaine5] será atribuída ao campo [Form].checkboxlist, que, portanto, deve ser do tipo tabela de cadeias de caracteres, assim como nas listas de seleção múltipla. Por outro lado, na exibição da vista [Form.JSP], os valores do campo [Form].checkboxlist determinam quais caixas de seleção estarão marcadas.
- linha 36: um campo oculto. Um campo oculto é um campo que é enviado sem ser preenchido pelo usuário. Seu valor é definido pelo programador. Aqui, o campo oculto receberá seu valor do campo [Form].hidden. Esse mesmo valor será enviado na forma:
e reatribuído ao campo [Form].hidden.
- linha 37: um botão do tipo submit. Ao clicar nesse botão, todos os valores do formulário serão enviados para a ação [Form]. A sequência de parâmetros enviados terá a seguinte forma:
textfield=texte&password=&textarea=ligne1%0D%0Aligne2%0D%0A&select1=z%C3%A9ro&select2=trois&select3=z%C3%A9ro&select3=deux&__multiselect_select3=&radio=bleu&checkbox=true&__checkbox_checkbox=true&checkboxlist=v%C3%A9lo&checkboxlist=bus&__multiselect_checkboxlist=&hidden=initial&submitText=Valider
9.5. A ação [Form] – parte de preenchimento
Seu código é o seguinte:
package example;
import com.opensymphony.xwork2.ActionSupport;
public class Form extends ActionSupport {
// construtor sem parâmetro
public Form() {
}
// campos do formulário
private String textfield = "texte";
private String password = "secret";
private String textarea = "ligne1\nligne2\n";
private String select1 = "zéro";
private String[] select1Values = new String[]{"zéro", "un", "deux"};
private String select2 = "trois";
private String[] select2Values = new String[]{"zéro", "un", "deux", "trois", "quatre"};
private String[] select3 = new String[]{"zéro", "deux"};
private String[] select3Values = new String[]{"zéro", "un", "deux", "trois", "quatre"};
private String radio = "bleu";
private String[] radioValues = new String[]{"bleu", "blanc", "rouge"};
private Boolean checkbox = false;
private String[] checkboxlist = new String[]{"vélo", "bus"};
private String[] checkboxlistValues = new String[]{"voiture", "tram", "vélo", "bus", "métro"};
private String hidden = "initial";
private String submitText;
// valores selecionados no campo select3
public String getSelect3SelectedValues() {
return getValue(select3);
}
// valores selecionados no campo checkboxlist
public String getCheckboxlistSelectedValues() {
return getValue(checkboxlist);
}
// método utilitário
public String getValue(String[] values) {
String result = "";
for (String value : values) {
result += " " + value;
}
return result;
}
// getters e setters dos campos
....
}
- linha 1: o campo associado à tag textfield do formulário. Servirá para inicializar esse campo de preenchimento, bem como para recuperar seu valor. Recebe, no momento da ação POST, o valor inserido nesse campo.
- linha 2: o campo associado à tag password do formulário. Recebe, no momento do POST, o valor inserido nesse campo.
- linha 13: associada à tag textarea do formulário. Recebe, no momento do POST, o texto digitado nesse campo.
- linha 14: associada à tag select1 do formulário, uma lista de seleção única. Seu valor inicial seleciona um elemento da lista suspensa. Será selecionado o elemento cujo atributo value for igual a esse valor. No momento do POST, recebe o atributo value da opção selecionada no menu suspenso.
- linha 15: as sequências de caracteres que irão alimentar a lista suspensa select1.
- linhas 16 e 17: o mesmo que select1
- linha 18: associada à tag select1 do formulário, uma lista de seleção múltipla. Os valores iniciais na tabela selecionam os elementos correspondentes da lista. Serão selecionados os elementos cujo atributo value for igual a um desses elementos. No momento do POST, recebe os atributos value das diferentes opções selecionadas na lista suspensa.
- linha 19: as sequências de caracteres que irão alimentar a lista select3
- linha 20: associada à tag radio do formulário. Seu valor serve para marcar um dos botões de opção, aquele cujo atributo value for igual a esse valor. Recebe, no momento do POST, o valor do botão de opção marcado.
- linha 21: os diferentes rótulos e valores dos botões de opção.
- linha 22: associada à tag checkbox do formulário. Seu valor inicial serve para marcar/desmarcar a caixa de seleção. Recebe, no momento do POST, o valor true se a caixa tiver sido marcada; caso contrário, recebe o valor false.
- linha 23: associada à tag checkboxlist do formulário. Os valores iniciais na tabela selecionam as caixas de seleção correspondentes. Serão marcadas as caixas de seleção cujo atributo value for igual a um desses valores iniciais. No momento do POST, recebe os atributos value das diferentes caixas marcadas.
- linha 24: as sequências de caracteres que irão alimentar os rótulos das caixas de seleção de checkboxlist.
- linha 25: associada ao campo oculto hidden. Seu valor inicial definirá o valor do campo oculto. No momento do POST, receberá esse mesmo valor, pois o usuário não tem a possibilidade de alterá-lo.
- linha 26: associada à tag submit. No momento do POST, recebe o texto do botão. É possível dispensar esse campo.
- Os métodos das linhas 29, 34 e 39 serão comentados mais adiante.
9.6. A visualização [Form.JSP] – seção Confirmação
A visualização [Form.JSP] possui uma seção “Confirmação das entradas” que ainda não foi abordada:
![]() |
Seu código é o seguinte:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
...
<hr/>
<h2><s:text name="Confirmation.message"/></h2>
<table border="1">
<tr>
<th><s:text name="Confirmation.champ"/></th>
<th><s:text name="Confirmation.valeur"/></th>
</tr>
<tr>
<td><s:text name="Form.textfield"/></td>
<td><s:property value="textfield"/>
</tr>
<tr>
<td><s:text name="Form.password"/></td>
<td><s:property value="password"/>
</tr>
<tr>
<td><s:text name="Form.textarea"/></td>
<td><s:property value="textarea"/>
</tr>
<tr>
<td><s:text name="Form.select1"/></td>
<td><s:property value="select1"/>
</tr>
<tr>
<td><s:text name="Form.select2"/></td>
<td><s:property value="select2"/>
</tr>
<tr>
<td><s:text name="Form.select3"/></td>
<td><s:property value="select3SelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.radio"/></td>
<td><s:property value="radio"/>
</tr>
<tr>
<td><s:text name="Form.checkbox"/></td>
<td><s:property value="checkbox"/>
</tr>
<tr>
<td><s:text name="Form.checkboxlist"/></td>
<td><s:property value="checkboxlistSelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.hidden"/></td>
<td><s:property value="hidden"/>
</tr>
</table>
</body>
</html>
- linha 13: exibe o valor do campo [Form].textfield
- linha 17: exibe o valor do campo [Form].password
- linha 21: exibe o valor do campo [Form].textarea
- linha 25: exibe o valor do campo [Form].select1
- linha 29: exibe o valor do campo [Form].select2
- linha 33: exibe os valores da tabela [Form].select3. Para isso, utiliza o método [Form].getSelect3SelectedValues.
- linha 37: exibe o valor do campo [Form].radio
- linha 41: exibe o valor do campo [Form].checkbox
- linha 45: exibe os valores da tabela [Form].checkboxlist. Para isso, utiliza o método [Form].getCheckboxlistSelectedValues.
- linha 49: exibe o valor do campo [Form].hidden
9.7. A ação [Form] – parte de confirmação
Os métodos getSelect3SelectedValues e getCheckboxlistSelectedValues mencionados anteriormente estão definidos na classe [Form]:
// valores selecionados no campo select3
public String getSelect3SelectedValues() {
return getValue(select3);
}
// valores selecionados no campo checkboxlist
public String getCheckboxlistSelectedValues() {
return getValue(checkboxlist);
}
// método utilitário
public String getValue(String[] values) {
String result = "";
for (String value : values) {
result += " " + value;
}
return result;
}
Elas se limitam a concatenar os elementos das tabelas que devem exibir.
9.8. Os testes
Ao executar o projeto no NetBeans, obtém-se a seguinte página inicial:
![]() |
Os valores exibidos em [1] e [2] provêm dos valores iniciais dos campos da ação [Form]. Vejamos alguns exemplos:
private String textarea = "ligne1\nligne2\n";
O valor do campo textarea explica as exibições [1A] e [2A].
private String[] select3 = new String[]{"zéro", "deux"};
private String[] select3Values = new String[]{"zéro", "un", "deux", "trois", "quatre"};
O valor do campo select3Values explica o conteúdo da lista em [1B]. O valor do campo select3 explica os elementos selecionados em [1B] e exibidos em [2B].
Se inserirmos outros valores no formulário e o validarmos, os valores inseridos serão lançados nos campos correspondentes da ação [Form]. Em seguida, a visualização [Form.JSP] será exibida novamente. Estamos, portanto, na mesma situação que anteriormente, exceto que os valores iniciais foram substituídos pelos valores lançados. Veja um exemplo:
![]() | ![]() |
9.9. A ação [Form1] e a visualização [Form1.JSP]
O arquivo de configuração [example.xml] configura a seguinte ação [Form1]:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="example" namespace="/example" extends="struts-default">
<action name="Form" class="example.Form">
<result name="success">/example/Form.JSP</result>
</action>
<action name="Form1" class="example.Form1">
<result name="success">/example/Form1.JSP</result>
</action>
<action name="Form2" class="example.Form2">
<result name="success">/example/Form2.JSP</result>
</action>
</package>
</struts>
Nas linhas 11 a 13, a chamada à ação [Form1] gera a visualização [Form1.JSP].
A ação [Form1] é a seguinte:
package example;
import com.opensymphony.xwork2.ActionSupport;
public class Form1 extends ActionSupport{
// construtor sem parâmetro
public Form1() {
}
// campos do formulário
private Data data=new Data();
/**
* @return the data
*/
public Data getData() {
return data;
}
/**
* @param data the data to set
*/
public void setData(Data data) {
this.data = data;
}
}
A ação [Form1] é idêntica à ação [Form], exceto que sua parte de modelo foi transferida para uma classe anexa, a classe [Data], linha 11. A classe [Data] é a seguinte:
package example;
public class Data {
// construtor sem parâmetro
public Data() {
}
// campos do formulário
private String textfield = "texte";
private String password = "secret";
private String textarea = "ligne1\nligne2\n";
private String select1 = "zéro";
private String[] select1Values = new String[]{"zéro", "un", "deux"};
private String select2 = "trois";
private String[] select2Values = new String[]{"zéro", "un", "deux", "trois", "quatre"};
private String[] select3 = new String[]{"zéro", "deux"};
private String[] select3Values = new String[]{"zéro", "un", "deux", "trois", "quatre"};
private String radio="bleu";
private String[] radioValues = new String[]{"bleu", "blanc", "rouge"};
private Boolean checkbox = false;
private String[] checkboxlist = new String[]{"vélo", "bus"};
private String[] checkboxlistValues = new String[]{"voiture", "tram", "vélo", "bus", "métro"};
private String hidden = "initial";
private String submitText;
// valores selecionados no campo select3
public String getSelect3SelectedValues() {
return getValue(select3);
}
// valores selecionados no campo checkboxlist
public String getCheckboxlistSelectedValues() {
return getValue(checkboxlist);
}
// método utilitário
public String getValue(String[] values) {
String result = "";
for (String value : values) {
result += " " + value;
}
return result;
}
// getters e setters
....
}
Encontramos os campos declarados anteriormente na ação [Form].
Como era de se esperar, a visualização [Form1.JSP] é semelhante à visualização [Form.JSP]:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title><s:text name="Form.titre"/></title>
<s:head/>
</head>
<body background="<s:url value="/ressources/standard.jpg"/>">
<h2><s:text name="Form.message"/></h2>
<h3><s:text name="Form.langues"/></h3>
<ul>
<li>
<s:url id="URL" action="Form">
<s:param name="request_locale">en</s:param>
</s:url>
<s:a href="%{URL}"><s:text name="Form.anglais"/></s:a>
</li>
<li>
<s:url id="URL" action="Form">
<s:param name="request_locale">fr</s:param>
</s:url>
<s:a href="%{URL}"><s:text name="Form.francais"/></s:a>
</li>
</ul>
<s:form name="formulaire">
<s:textfield name="data.textfield" key="Form.textfield" />
<s:password name="data.password" key="Form.password"/>
<s:textarea name="data.textarea" key="Form.textarea" cols="40" rows="5"/>
<s:select name="data.select1" list="data.select1Values" size="1" key="Form.select1" headerValue="<-- select 1 -->" headerKey="-1" />
<s:select name="data.select2" size="3" list="data.select2Values" key="Form.select2"/>
<s:select name="data.select3" size="3" list="data.select3Values" key="Form.select3" multiple="true"/>
<s:radio name="data.radio" list="data.radioValues" key="Form.radio"/>
<s:checkbox name="data.checkbox" key="Form.checkbox"/>
<s:checkboxlist name="data.checkboxlist" list="data.checkboxlistValues" key="Form.checkboxlist"/>
<s:hidden name="data.hidden" key="Form.hidden"/>
<s:submit key="Form.submitText" name="data.submitText"/>
</s:form>
<hr/>
<h2><s:text name="Confirmation.message"/></h2>
<table border="1">
<tr>
<th><s:text name="Confirmation.champ"/></th>
<th><s:text name="Confirmation.valeur"/></th>
</tr>
<tr>
<td><s:text name="Form.textfield"/></td>
<td><s:property value="data.textfield"/>
</tr>
<tr>
<td><s:text name="Form.password"/></td>
<td><s:property value="data.password"/>
</tr>
<tr>
<td><s:text name="Form.textarea"/></td>
<td><s:property value="data.textarea"/>
</tr>
<tr>
<td><s:text name="Form.select1"/></td>
<td><s:property value="data.select1"/>
</tr>
<tr>
<td><s:text name="Form.select2"/></td>
<td><s:property value="data.select2"/>
</tr>
<tr>
<td><s:text name="Form.select3"/></td>
<td><s:property value="data.select3SelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.radio"/></td>
<td><s:property value="data.radio"/>
</tr>
<tr>
<td><s:text name="Form.checkbox"/></td>
<td><s:property value="data.checkbox"/>
</tr>
<tr>
<td><s:text name="Form.checkboxlist"/></td>
<td><s:property value="data.checkboxlistSelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.hidden"/></td>
<td><s:property value="data.hidden"/>
</tr>
</table>
</body>
</html>
A diferença entre as visualizações [Form] e [Form1] pode ser ilustrada pela linha 27 reproduzida abaixo:
<s:textfield name="data.textfield" key="Form.textfield" />
O campo de entrada está vinculado, para leitura e gravação, ao campo data.textfield da ação [Form1]. Vale lembrar que, após a execução, as propriedades da ação [Form1] ficam acessíveis à visualização. Assim, o atributo name anterior será avaliado como [Form1].getData().getTextField(). Portanto, é necessário que os dois métodos get anteriores existam.
9.10. A ação [Form2] e a visualização [Form2.JSP]
O arquivo de configuração [example.xml] configura a seguinte ação [Form2]:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="example" namespace="/example" extends="struts-default">
<action name="Form" class="example.Form">
<result name="success">/example/Form.JSP</result>
</action>
<action name="Form1" class="example.Form1">
<result name="success">/example/Form1.JSP</result>
</action>
<action name="Form2" class="example.Form2">
<result name="success">/example/Form2.JSP</result>
</action>
</package>
</struts>
Nas linhas 14 a 16, a chamada à ação [Form2] gera a visualização [Form2.JSP].
A ação [Form2] é a seguinte:
package example;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
public class Form2 extends ActionSupport implements ModelDriven {
// construtor sem parâmetro
public Form2() {
}
// modelo da ação
public Object getModel() {
return new Data();
}
}
- linha 6: a ação [Form2] implementa a interface [ModelDriven]. Há apenas um método a ser implementado: o método getModel da linha 12. Esse método retorna uma instância da classe [Data], analisada anteriormente.
O fato de a ação [Form2] implementar a interface [ModelDriven] tem a seguinte consequência: a visualização exibida após a ação [Form2] tem acesso direto às propriedades do modelo da ação [Form2], que é retornado pelo método getModel(). Assim, a visualização [Form2.JSP] volta a ser o que era com a ação inicial [Form]:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title><s:text name="Form.titre"/></title>
<s:head/>
</head>
<body background="<s:url value="/ressources/standard.jpg"/>">
<h2><s:text name="Form.message"/></h2>
<h3><s:text name="Form.langues"/></h3>
<ul>
<li>
<s:url id="URL" action="Form">
<s:param name="request_locale">en</s:param>
</s:url>
<s:a href="%{URL}"><s:text name="Form.anglais"/></s:a>
</li>
<li>
<s:url id="URL" action="Form">
<s:param name="request_locale">fr</s:param>
</s:url>
<s:a href="%{URL}"><s:text name="Form.francais"/></s:a>
</li>
</ul>
<s:form name="formulaire">
<s:textfield name="textfield" key="Form.textfield" />
<s:password name="password" key="Form.password"/>
<s:textarea name="textarea" key="Form.textarea" cols="40" rows="5"/>
<s:select name="select1" list="select1Values" size="1" key="Form.select1" headerValue="<-- select 1 -->" headerKey="-1" />
<s:select name="select2" size="3" list="select2Values" key="Form.select2"/>
<s:select name="select3" size="3" list="select3Values" key="Form.select3" multiple="true"/>
<s:radio name="radio" list="radioValues" key="Form.radio"/>
<s:checkbox name="checkbox" key="Form.checkbox"/>
<s:checkboxlist name="checkboxlist" list="checkboxlistValues" key="Form.checkboxlist"/>
<s:hidden name="hidden" key="Form.hidden"/>
<s:submit key="Form.submitText" name="submitText"/>
</s:form>
<hr/>
<h2><s:text name="Confirmation.message"/></h2>
<table border="1">
<tr>
<th><s:text name="Confirmation.champ"/></th>
<th><s:text name="Confirmation.valeur"/></th>
</tr>
<tr>
<td><s:text name="Form.textfield"/></td>
<td><s:property value="textfield"/>
</tr>
<tr>
<td><s:text name="Form.password"/></td>
<td><s:property value="password"/>
</tr>
<tr>
<td><s:text name="Form.textarea"/></td>
<td><s:property value="textarea"/>
</tr>
<tr>
<td><s:text name="Form.select1"/></td>
<td><s:property value="select1"/>
</tr>
<tr>
<td><s:text name="Form.select2"/></td>
<td><s:property value="select2"/>
</tr>
<tr>
<td><s:text name="Form.select3"/></td>
<td><s:property value="select3SelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.radio"/></td>
<td><s:property value="radio"/>
</tr>
<tr>
<td><s:text name="Form.checkbox"/></td>
<td><s:property value="checkbox"/>
</tr>
<tr>
<td><s:text name="Form.checkboxlist"/></td>
<td><s:property value="checkboxlistSelectedValues"/>
</tr>
<tr>
<td><s:text name="Form.hidden"/></td>
<td><s:property value="hidden"/>
</tr>
</table>
</body>
</html>
Assim, a linha 27, que anteriormente era:
<s:textfield name="data.textfield" key="Form.textfield" />
volta a ser:
<s:textfield name="textfield" key="Form.textfield" />
A vantagem de colocar o modelo fora da vista é que essa arquitetura delimita mais claramente as funcionalidades de cada elemento da arquitetura MVC. O modelo M é claramente identificado por uma classe. Além disso, o modelo pode existir antes das ações. Assim, se um aplicativo web gerencia um banco de dados de pessoas, é provável que a classe Personne já exista. Se uma ação oferece um formulário de preenchimento para criar uma nova pessoa, o modelo dessa ação já está definido: é a classe Personne.
Vimos como foi simples passar da ação [Form] para a ação [Form2]:
- o modelo M da visualização V foi encapsulado em uma classe separada
- a ação que gera a visualização utilizando esse modelo implementa a interface ModelDriven com o método getModel, que retorna uma instância do modelo M. A ação pode, então, ser vista como uma extensão do controlador C do Struts 2, a classe FilterDispatcher.
O leitor poderá aplicar essa abordagem a qualquer ação descrita a seguir.






