9. Exemplo 07 – As tags 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 introdução de texto, aos outros elementos HTML de um 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, o [example.xml]. É este ficheiro que irá configurar as ações.
- linhas 11-19: o pacote default. Define um endereço de redirecionamento para o URL /. Este será redirecionado para o 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, 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 vista /example/Form.JSP seja apresentada.
- linhas 11-13: a execução da ação Form1 resultará na exibição da vista /example/Form1.JSP.
- linhas 14-16: a execução da ação Form2 resultará na exibição da vista /example/Form2.JSP.
9.3. Os ficheiros de mensagens
Não nos deteremos na internacionalização do projeto. Já a abordámos 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] – parte de introdução de dados
A sua apresentação 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. Este atributo especifica para que 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 vista, neste caso a ação [Form].
- linha 27: um campo de introdução de dados. 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:
O nome do parâmetro corresponde a um campo da ação [Form]. O valor do campo de introdução de dados texte_saisi será aqui inserido no campo textfield da ação [Form]. Por outro lado, se a vista [Form.JSP] for apresentada na sequência da ação [Form], o valor do campo de introdução será o do campo textfield da ação [Form]. Este campo é, portanto, utilizado tanto para leitura como para escrita. Para tal, a classe [Form] deve dispor dos métodos getTextField e setTextField.
Este raciocínio aplica-se a todas as etiquetas de introdução de dados que se seguem. Não o repetiremos.
- linha 28: introdução de uma palavra-passe. A cadeia enviada para a ação [Form] terá o seguinte formato
Deve existir um campo password com os seus métodos get/set na ação [Form].
- linha 29: introdução de um texto com várias linhas numa área de 5 linhas e 40 colunas. A cadeia enviada para a ação [Form] terá o seguinte formato
Deve existir um campo textarea com os seus métodos get/set na ação [Form].
- linha 30: uma lista suspensa (size=1) de seleção única. Só é possível selecionar um valor da lista. A cadeia enviada para a ação [Form] terá o seguinte formato:
Deve existir um campo select1 com os 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 incluir no menu suspenso. Aqui, o método getSelect1Values da ação [Form] será chamado para preencher o menu suspenso. Este método pode devolver uma coleção, um dicionário ou um array. Neste caso, irá devolver uma matriz de cadeias de caracteres [chaine1, chaine2, ...] que irá gerar o seguinte código HTML:
<option value="chaine1">chaine1</option>
<option value="chaine2">chaine2</option>
...
O texto entre as balizas <option>...</option> será apresentado na lista suspensa. O atributo value indica o valor a enviar caso a opção seja selecionada pelo utilizador. Aqui, o atributo value e o texto apresentado na lista suspensa são idênticos. Na maioria das vezes, não é esse o caso. Se a segunda opção for selecionada, a seguinte cadeia 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, este 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 apresentar como primeira opção da lista suspensa e headerKey o valor a enviar caso essa opção seja selecionada pelo utilizador.
- 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 serão visíveis 3 elementos da lista. O modo de seleção mantém-se o mesmo. Só é possível selecionar um elemento.
- linha 32: mais uma vez uma lista, mas com seleção múltipla (multiple=true). Neste caso, o valor enviado para a ação [Form] terá o seguinte formato:
se as opções chaine2 e chaine5 tiverem sido selecionadas. Quando são lançados vários valores 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 apresentar a vista [Form.JSP], os valores do campo [Form].select3 determinam as opções da lista select3 que 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 deste atributo é o nome de um método da ação [Form] que deve devolver uma coleção, um dicionário ou um array. Neste caso, o método [Form].getRadioValues irá devolver uma matriz de cadeias de caracteres [chaine1,chaine2,...], que irá gerar as seguintes etiquetas 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 selecionado, 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 cadeia de parâmetros será enviada para a ação [Form]
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 cadeia
tivesse sido enviada.
- linha 35: uma lista de caixas de seleção. É possível selecionar várias. 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 da ação [Form], que deve devolver uma coleção, um dicionário ou um array. Neste caso, o método [Form].getCheckboxlistValues irá devolver uma matriz de cadeias de caracteres [chaine1,chaine2,...], que irá gerar as seguintes etiquetas HTML:
<input type="checkbox" name="checkboxlist" ... value="chaine1"/>chaine1
<input type="checkbox" name="checkboxlist" ... value="chaine2"/>chaine2
...
Se o utilizador selecionar as caixas de seleção denominadas chaine2 e chaine5, a seguinte cadeia de caracteres será enviada para a ação [Form]:
A tabela [chaine2, chaine5] será atribuída ao campo [Form].checkboxlist, que deve, portanto, ser do tipo tabela de cadeias de caracteres, tal como nas listas de seleção múltipla. Por outro lado, na visualização da vista [Form.JSP], os valores do campo [Form].checkboxlist determinam as caixas de seleção que ficarã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 assumirá o 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 neste botão, todos os valores do formulário serão enviados para a ação [Form]. A cadeia de parâmetros enviados terá o seguinte aspeto:
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
O seu código é o seguinte:
package example;
import com.opensymphony.xwork2.ActionSupport;
public class Form extends ActionSupport {
// construtor sem parâmetros
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 à baliza textfield do formulário. Servirá para inicializar este campo de introdução de dados, bem como para recuperar o seu valor. Recebe, no momento da ação POST, o valor introduzido neste campo.
- linha 2: o campo associado à baliza password do formulário. Recebe, no momento do POST, o valor introduzido neste campo.
- linha 13: associada à etiqueta textarea do formulário. Recebe, no momento do POST, o texto introduzido neste campo.
- linha 14: associada à baliza select1 do formulário, uma lista de escolha única. O seu valor inicial seleciona um elemento da lista suspensa. Será selecionado o elemento cujo atributo value seja igual a esse valor. No momento do POST, recebe o atributo value da opção selecionada no menu suspenso.
- linha 15: as cadeias de caracteres que irão alimentar a lista suspensa select1.
- linhas 16 e 17: o mesmo que select1
- linha 18: associada à baliza 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 seja igual a um desses elementos. No momento do POST, recebe os atributos value das diferentes opções selecionadas na lista suspensa.
- linha 19: as cadeias de caracteres que irão alimentar a lista select3
- linha 20: associada à baliza radio do formulário. O seu valor serve para selecionar um dos botões de opção, aquele cujo atributo value é igual a este valor. Recebe, no momento do POST, o valor do botão de opção selecionado.
- linha 21: os diferentes rótulos e valores dos botões de opção.
- linha 22: associada à baliza checkbox do formulário. O 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, false caso contrário.
- linha 23: associada à baliza 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 de seleção marcadas.
- linha 24: as cadeias de caracteres que irão alimentar os rótulos das caixas de seleção de checkboxlist.
- linha 25: associada ao campo oculto hidden. O seu valor inicial irá definir o valor do campo oculto. No momento do POST, receberá esse mesmo valor, uma vez que o utilizador não tem a possibilidade de o alterar.
- linha 26: associado à baliza submit. No momento do POST, recebe o texto do botão. É possível prescindir deste campo.
- Os métodos das linhas 29, 34 e 39 serão comentados mais adiante.
9.6. A vista [Form.JSP] – parte «Confirmação»
A vista [Form.JSP] tem uma parte 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: apresenta o valor do campo [Form].select2
- linha 33: apresenta os valores da tabela [Form].select3. Para tal, utiliza o método [Form].getSelect3SelectedValues.
- linha 37: apresenta o valor do campo [Form].radio
- linha 41: apresenta o valor do campo [Form].checkbox
- linha 45: apresenta os valores da tabela [Form].checkboxlist. Para tal, utiliza o método [Form].getCheckboxlistSelectedValues.
- linha 49: apresenta 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;
}
Limitam-se a concatenar os elementos das tabelas que têm de apresentar.
9.8. Os testes
Ao executar o projeto no NetBeans, obtém-se a seguinte página inicial:
![]() |
Os valores apresentados 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 apresentados em [2B].
Se introduzirmos outros valores no formulário e o validarmos, os valores introduzidos serão lançados nos campos correspondentes da ação [Form]. Em seguida, a vista [Form.JSP] será novamente apresentada. Estamos, portanto, na mesma situação que anteriormente, exceto que os valores iniciais foram substituídos pelos valores lançados. Eis 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>
Nas 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{
// construtor sem parâmetros
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], com a única diferença de que a 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âmetros
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 aqui os campos declarados anteriormente 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 reproduzida abaixo:
<s:textfield name="data.textfield" key="Form.textfield" />
O campo de introdução de dados está ligado, em leitura e 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, é necessário que os dois métodos get anteriores existam.
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>
Nas 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 {
// construtor sem parâmetros
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 implementar, o método getModel da linha 12. Este devolve uma instância da classe [Data] analisada anteriormente.
O facto de a ação [Form2] implementar a interface [ModelDriven] tem a seguinte consequência: a vista exibida na sequência da ação [Form2] tem acesso direto às propriedades do modelo da ação [Form2], sendo este devolvido pelo método getModel(). Assim, a vista [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 esta 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 uma aplicação web gerir uma base de dados de pessoas, é provável que a classe Personne já exista. Se uma ação apresentar um formulário de preenchimento para criar uma nova pessoa, o modelo dessa ação é óbvio: é a classe Personne.
Vimos como foi simples passar 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 poderá aplicar esta abordagem a qualquer ação descrita a seguir.






