9. Exemplo 07 – Etiquetas de formulário
Vamos criar e utilizar o seguinte formulário:


Vamos alargar o conceito de injeção de parâmetros visto para um campo de entrada de texto a outros elementos HTML num formulário.
9.1. O projeto NetBeans
![]() |
- em [1], as vistas do projeto [Formx.jsp]
- em [2], o ficheiro de configuração do Struts e as mensagens internacionalizadas
- em [3], as ações [Formx.java] e outro ficheiro de configuração do Struts.
9.2. Configuração do Struts
O ficheiro [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 ficheiro de configuração [example.xml]. Este ficheiro configura as ações.
- Linhas 11–19: o pacote padrão. Define um endereço de redirecionamento para a URL /. Será redirecionado para a URL /example/Form.action.
O ficheiro [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, /example/Form2, onde /example é o namespace (linha 7) e Formx são as ações.
- Linhas 8-10: a execução da ação Form exibirá a vista /example/Form.jsp.
- Linhas 11–13: a execução da ação Form1 exibirá a vista /example/Form1.jsp.
- Linhas 14–16: A execução da ação Form2 exibirá a vista /example/Form2.jsp.
9.3. Ficheiros de mensagens
Não nos deteremos na internacionalização do projeto. Já abordámos este tema no Exemplo 01. Apresentamos o conteúdo do ficheiro [messages.properties] para que o leitor possa compreender as vistas que se seguem.
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 vista [Form.jsp] – secção de entrada
Tem o seguinte aspeto:

É o 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, falta o atributo `action`. Este atributo especifica a ação para a qual os dados do formulário serão enviados. Se o atributo `action` estiver em falta, os dados serão enviados para a ação que fez com que a vista fosse exibida, neste caso a ação `[Form]`.
- Linha 27: um campo de entrada. O atributo `key` especifica o seu rótulo. O atributo `name` é o nome do parâmetro que será enviado. A cadeia de caracteres enviada para este campo terá o seguinte formato:
textfield=text_entered
O nome do parâmetro corresponde a um campo na ação [Form]. O valor do campo de entrada text_saisi será inserido no campo textfield da ação [Form]. Por outro lado, se a vista [Form.jsp] for exibida após a ação [Form], o valor do campo de entrada será o do campo textfield na ação [Form]. Este campo é, portanto, utilizado tanto para leitura como para escrita. A classe [Form] deve possuir os métodos getTextField e setTextField para este fim.
Este raciocínio aplica-se a todas as tags input subsequentes. Não o repetiremos.
- Linha 28: introdução da palavra-passe. A cadeia de caracteres enviada para a ação [Form] terá o formato
password=entered_password
Deve existir um campo de palavra-passe com os seus métodos get/set na ação [Form].
- Linha 29: Introdução de texto multilinha numa área de 5 linhas e 40 colunas. A string enviada para a ação [Form] terá o formato
textarea=input
Deve existir um campo textarea com os seus métodos get/set na ação [Form].
- linha 30: uma lista suspensa de seleção única (size=1). Apenas um valor da lista pode ser selecionado. A string enviada para a ação [Form] terá o seguinte formato:
select1=valor_selecionado
Deve existir um campo select1 com os seus métodos get/set na ação [Form].
O atributo key é o rótulo da lista. O atributo list define a lista de valores a colocar na caixa combinada. Aqui, o método getSelect1Values da ação [Form] será chamado para preencher a caixa combinada. Este método pode devolver uma coleção, um dicionário ou uma matriz. Aqui, devolverá uma matriz de cadeias de caracteres [string1, string2, ...] que irá gerar o seguinte código HTML:
<option value="string1">string1</option>
<option value="string2">string2</option>
...
O texto entre as tags <option>...</option> será exibido na caixa de combinação. O atributo value especifica o valor a ser enviado se a opção for selecionada pelo utilizador. Aqui, o atributo value e o texto exibido na caixa de combinação são idênticos. Na maioria das vezes, este não é o caso. Se a segunda opção for selecionada, a seguinte string será enviada para a ação [Form]:
select1=string2
O campo [Form].select1 receberá então o valor string2. Por outro lado, se, no momento em que o formulário é exibido, este campo estiver definido como string3, então, visualmente, o terceiro elemento
<option value="string3">string3</option>
aparecerá selecionado na caixa combinada.
O atributo headerValue define o texto a ser exibido como a primeira opção na caixa de combinação, e headerKey define o valor a ser enviado se esta opção for selecionada pelo utilizador.
- Linha 31: mais uma vez, uma lista de tamanho 3 (size=3): ao contrário da lista anterior, onde apenas um item é visível, aqui serão visíveis 3 itens da lista. O modo de seleção permanece o mesmo. Apenas um item pode ser selecionado.
- Linha 32: outra lista, mas desta vez com seleção múltipla (multiple=true). Neste caso, o valor enviado para a ação [Form] terá o seguinte formato:
select3=string2&select3=string5
se as opções string2 e string5 tiverem sido selecionadas. Quando são enviados vários valores para o mesmo parâmetro — neste caso, select3 — a ação deve ter um campo com o nome do parâmetro e ser do tipo matriz. Assim, por exemplo, aqui a ação [Form] poderia ter um campo como:
String[] select3;
e os métodos get/set correspondentes. A matriz select3 receberá então a matriz de cadeias de caracteres [string2, string5]. Por outro lado, quando a vista [Form.jsp] é apresentada, os valores do campo [Form].select3 determinam quais as opções da lista select3 que aparecerão selecionadas. Esta é sempre uma operação 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 deste atributo é o nome de um método na ação [Form] que deve devolver uma coleção, um dicionário ou uma matriz. Aqui, o método [Form].getRadioValues devolverá uma matriz de cadeias de caracteres [string1, string2, ...] que irá gerar as seguintes tags HTML:
<input type="radio" name="radio" ... value="string1"/>string1
<input type="radio" name="radio" ... value="string2"/>string2
...
Se o botão de opção string2 for selecionado, o valor enviado será
radio=string2
e este valor será inserido no campo [Form].radio.
- Linha 34: uma caixa de seleção. Se marcada, a seguinte cadeia de parâmetros será enviada para a ação [Form]
checkbox=true
Se não estiver marcada, não é enviada nenhuma cadeia de parâmetros. O Struts 2 possui um mecanismo interno que faz com que tudo aconteça como se a caixa de seleção
checkbox=false
tivesse sido enviada.
- Linha 35: uma lista de caixas de seleção. É possível selecionar várias caixas de seleção. O rótulo do grupo é fornecido pelo atributo key. Os rótulos das caixas de seleção individuais são fornecidos pelo atributo list. O valor deste atributo é o nome de um método na ação [Form] que deve devolver uma coleção, um dicionário ou uma matriz. Aqui, o método [Form].getCheckboxlistValues devolverá uma matriz de cadeias de caracteres [string1, string2, ...] que irá gerar as seguintes tags HTML:
<input type="checkbox" name="checkboxlist" ... value="string1"/>string1
<input type="checkbox" name="checkboxlist" ... value="string2"/>string2
...
Se o utilizador selecionar as caixas de seleção rotuladas como string2 e string5, a seguinte string será enviada para a ação [Form]:
checkboxlist=string2&checkboxlist=string5
A matriz [string2, string5] será atribuída ao campo [Form].checkboxlist, que deve, portanto, ser do tipo matriz de cadeias de caracteres, tal como acontece com as listas de seleção múltipla. Por outro lado, quando a vista [Form.jsp] é apresentada, os valores do campo [Form].checkboxlist determinam quais as caixas de seleção que serão marcadas.
- Linha 36: um campo oculto. Um campo oculto é um campo que é enviado sem ser preenchido pelo utilizador. O seu valor é definido pelo programador. Aqui, o campo oculto irá obter o seu valor do campo [Form].hidden. Este mesmo valor será enviado no formulário:
hidden=something
e reatribuído ao campo [Form].hidden.
- Linha 37: um botão de envio. Clicar neste botão enviará todos os valores do formulário para a ação [Form]. A sequência de parâmetros enviados terá o seguinte aspeto:
textfield=text&password=&textarea=line1%0D%0Aline2%0D%0A&select1=zero&select2=three&select3=zero&select3=two&__multiselect_select3=&radio=blue&checkbox=true&__checkbox_checkbox=true&checkboxlist=v%C3%A9lo&checkboxlist=bus&__multiselect_checkboxlist=&hidden=initial&submitText=Validate
9.5. A ação [Form] – secção de entrada
O seu código é o seguinte:
package example;
import com.opensymphony.xwork2.ActionSupport;
public class Form extends ActionSupport {
// constructor without parameters
public Form() {
}
// form fields
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;
// values selected in select3 field
public String getSelect3SelectedValues() {
return getValue(select3);
}
// values selected in checkboxlist field
public String getCheckboxlistSelectedValues() {
return getValue(checkboxlist);
}
// utilitarian method
public String getValue(String[] values) {
String result = "";
for (String value : values) {
result += " " + value;
}
return result;
}
// field getters and setters
....
}
- linha 1: o campo associado à tag textfield do formulário. Utilizado para inicializar este campo de entrada, bem como para recuperar o seu valor. Recebe o valor introduzido neste campo no momento da solicitação POST.
- linha 2: o campo associado à tag password do formulário. Recebe o valor introduzido neste campo durante a solicitação POST.
- linha 13: associada à tag textarea do formulário. Recebe o texto inserido neste campo durante a solicitação POST.
- Linha 14: Associada à tag `select1` do formulário, uma lista de seleção única. O seu valor inicial seleciona um item da lista suspensa. O item com um atributo `value` que corresponda a este valor será selecionado. Após o POST, recebe o atributo `value` da opção selecionada na lista suspensa.
- Linha 15: As cadeias de caracteres que irão preencher o menu suspenso select1.
- Linhas 16 e 17: Igual a select1
- Linha 18: associada à tag `select1` do formulário, uma lista de seleção múltipla. Os valores iniciais na matriz selecionam os elementos correspondentes na lista. Os elementos cujo atributo `value` corresponda a um desses valores serão selecionados. Após o POST, recebe os atributos `value` das várias opções selecionadas no menu suspenso.
- Linha 19: as cadeias de caracteres que irão preencher a lista select3
- Linha 20: Associada à tag radio do formulário. O seu valor é utilizado para selecionar um dos botões de opção — aquele cujo atributo value corresponda a este valor. Recebe o valor do botão de opção selecionado durante a solicitação POST.
- Linha 21: Os vários rótulos e valores dos botões de opção.
- Linha 22: Associada à tag checkbox do formulário. O seu valor inicial é utilizado para marcar ou desmarcar a caixa. Após o POST, recebe o valor true se a caixa estiver marcada, false caso contrário.
- Linha 23: Associada à tag checkboxlist do formulário. Os valores iniciais na matriz selecionam as caixas de seleção correspondentes. As caixas de seleção cujo atributo value corresponda a um desses valores iniciais serão marcadas. Após o POST, recebe os atributos value das várias caixas de seleção marcadas.
- Linha 24: As cadeias de caracteres que irão preencher os rótulos das caixas de seleção da checkboxlist.
- Linha 25: associada ao campo oculto. O seu valor inicial define o valor do campo oculto. Após o POST, receberá este mesmo valor, uma vez que o utilizador não o pode modificar.
- Linha 26: Associado à tag submit. Durante a solicitação POST, recebe o rótulo do botão. Este campo é opcional.
- Os métodos nas linhas 29, 34 e 39 serão discutidos mais adiante.
9.6. A vista [Form.jsp] – Secção de confirmação
A vista [Form.jsp] tem uma secção intitulada «Confirmação das entradas» que ainda não foi abordada:

O 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: apresenta o valor do campo [Form].textfield
- linha 17: apresenta o valor do campo [Form].password
- linha 21: apresenta o valor do campo [Form].textarea
- linha 25: apresenta o valor do campo [Form].select1
- linha 29: exibe o valor do campo [Form].select2
- Linha 33: Exibe os valores da matriz [Form].select3. Para tal, 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 matriz [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] – secção de confirmação
Os métodos getSelect3SelectedValues e getCheckboxlistSelectedValues mencionados acima estão definidos na classe [Form]:
// valeurs sélectionnées dans champ select3
public String getSelect3SelectedValues() {
return getValue(select3);
}
// valeurs sélectionnées dans champ checkboxlist
public String getCheckboxlistSelectedValues() {
return getValue(checkboxlist);
}
// méthode utilitaire
public String getValue(String[] values) {
String result = "";
for (String value : values) {
result += " " + value;
}
return result;
}
Eles simplesmente concatenam os elementos das matrizes que precisam de exibir.
9.8. Testes
Quando o projeto NetBeans é executado, é exibida a seguinte página inicial:
![]() |
Os valores apresentados em [1] e [2] provêm dos valores iniciais dos campos na 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 itens selecionados em [1B] e exibidos em [2B].
Se introduzirmos outros valores no formulário e o enviarmos, os valores introduzidos serão enviados para os campos correspondentes da ação [Form]. Em seguida, a vista [Form.jsp] será novamente apresentada. Estamos, portanto, na mesma situação que antes, exceto que os valores iniciais foram substituídos pelos valores enviados. Aqui está um exemplo:


9.9. A ação [Form1] e a vista [Form1.jsp]
O ficheiro 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>
Linhas 11–13: A chamada à ação [Form1] gera a vista [Form1.jsp].
A ação [Form1] é a seguinte:
package example;
import com.opensymphony.xwork2.ActionSupport;
public class Form1 extends ActionSupport{
// constructor without parameters
public Form1() {
}
// form fields
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 a sua parte de modelo foi movida para uma classe separada, a classe [Data], na linha 11. A classe [Data] é a seguinte:
package example;
public class Data {
// constructor without parameters
public Data() {
}
// form fields
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;
// values selected in select3 field
public String getSelect3SelectedValues() {
return getValue(select3);
}
// values selected in checkboxlist field
public String getCheckboxlistSelectedValues() {
return getValue(checkboxlist);
}
// utilitarian method
public String getValue(String[] values) {
String result = "";
for (String value : values) {
result += " " + value;
}
return result;
}
// getters and setters
....
}
Encontramos os campos previamente declarados na ação [Form].
Como seria de esperar, a vista [Form1.jsp] é semelhante à vista [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 vistas [Form] e [Form1] pode ser ilustrada pela linha 27 apresentada abaixo:
<s:textfield name="data.textfield" key="Form.textfield" />
O campo de entrada está vinculado, tanto para leitura como para escrita, ao campo data.textfield da ação [Form1]. Recorde-se que, após a execução, as propriedades da ação [Form1] ficam acessíveis à vista. Assim, o atributo name anterior será avaliado como [Form1].getData().getTextField(). Por conseguinte, os dois métodos get anteriores têm de existir.
9.10. A ação [Form2] e a vista [Form2.jsp]
O ficheiro 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>
Linhas 14–16: A chamada à ação [Form2] gera a vista [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 {
// constructor without parameters
public Form2() {
}
// action model
public Object getModel() {
return new Data();
}
}
- Linha 6: A ação [Form2] implementa a interface [ModelDriven]. Há apenas um método a implementar: o método getModel na linha 12. Este método devolve uma instância da classe [Data] discutida anteriormente.
O facto de a ação [Form2] implementar a interface [ModelDriven] tem a seguinte consequência: a vista apresentada após a ação [Form2] tem acesso direto às propriedades do modelo da ação [Form2], que é devolvido pelo método getModel(). Assim, a vista [Form2.jsp] volta a ser o que era com a ação [Form] inicial:
<%@ 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>
Portanto, a linha 27, que anteriormente era:
<s:textfield name="data.textfield" key="Form.textfield" />
passa a ser:
<s:textfield name="textfield" key="Form.textfield" />
A vantagem de colocar o modelo fora da vista é que esta arquitetura delineia 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 uma aplicação web gerir uma base de dados de pessoas, é provável que a classe Pessoa exista. Se uma ação fornecer um formulário de entrada para criar uma nova pessoa, o modelo para esta ação é óbvio: é a classe Pessoa.
Vimos como foi simples mudar da ação [Form] para a ação [Form2]:
- o modelo M da vista V foi encapsulado numa classe separada
- a ação que gera a vista utilizando este modelo implementa a interface ModelDriven com o método getModel, que devolve 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 pode aplicar esta abordagem a qualquer ação descrita abaixo.

