9. Ejemplo 07 – Las etiquetas de formulario
Vamos a crear y utilizar el siguiente formulario:


Vamos a ampliar el concepto de inyección de parámetros visto para un campo de entrada de texto a los demás elementos HTML de un formulario.
9.1. El proyecto NetBeans
![]() |
- en [1], las vistas del proyecto [Formx.jsp]
- en [2], el archivo de configuración de Struts y los mensajes internacionalizados
- en [3], las acciones [Formx.java] y otro archivo de configuración de Struts.
9.2. Configuración de Struts
El archivo [struts.xml] es el siguiente:
<?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>
- línea 9: incluye otro archivo de configuración [example.xml]. Este es el que configurará las acciones.
- Líneas 11-19: el paquete default. Define una dirección de redireccionamiento para la URL /. Se redirigirá a la URL /example/Form.action.
El archivo [example.xml] que configura las acciones es el siguiente:
<?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>
- líneas 7-17: definen las acciones /example/Form, /example/Form1, /example/Form2, donde /example es el espacio de nombres (línea 7) y Formx las acciones.
- líneas 8-10: la ejecución de la acción Form provocará la visualización de la vista /example/Form.jsp.
- líneas 11-13: la ejecución de la acción Form1 provocará la visualización de la vista /example/Form1.jsp.
- líneas 14-16: la ejecución de la acción Form2 generará la visualización de la vista /example/Form2.jsp.
9.3. Los archivos de mensajes
No nos detendremos en la internacionalización del proyecto. Ya la hemos estudiado en el ejemplo 01. A continuación, mostramos el contenido del archivo [messages.properties] para que el lector pueda comprender las vistas que siguen.
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. La vista [Form.jsp] – parte de entrada
Su aspecto visual es el siguiente:

Es la siguiente:
<%@ 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>
- El formulario comienza en la línea 26 y termina en la línea 38. En la línea 26, falta el atributo action. Este atributo especifica a qué acción se enviarán los datos del formulario. En ausencia del atributo action, se enviarán a la acción que ha dado lugar a la visualización de la vista, en este caso la acción [Form].
- línea 27: un campo de entrada. El atributo key especifica su etiqueta. El atributo name es el nombre del parámetro que se enviará. La cadena enviada para este campo tendrá el siguiente formato:
textfield=texto_introducido
El nombre del parámetro corresponde a un campo de la acción [Form]. El valor del campo de entrada texte_saisi se insertará aquí en el campo textfield de la acción [Form]. Por el contrario, si se muestra la vista [Form.jsp] tras la acción [Form], el valor del campo de entrada será el del campo textfield de la acción [Form]. Por lo tanto, este campo se utiliza tanto para lectura como para escritura. Para ello, la clase [Form] debe tener los métodos getTextField y setTextField.
Este razonamiento es válido para todas las etiquetas de entrada que siguen. No lo repetiremos.
- línea 28: introducción de una contraseña. La cadena enviada a la acción [Form] tendrá el formato
password=contraseña_introducida
Debe existir un campo password con sus métodos get / set en la acción [Form].
- línea 29: introducción de un texto de varias líneas en un área de 5 filas y 40 columnas. La cadena enviada a la acción [Form] tendrá el formato
textarea=entrada
Debe existir un campo textarea con sus get/set en la acción [Form].
- línea 30: una lista desplegable (size=1) de selección única. Solo se puede seleccionar un valor de la lista. La cadena enviada a la acción [Form] tendrá el siguiente formato:
select1=valor_seleccionado
En la acción [Form] debe existir un campo select1 con sus métodos get y set.
El atributo key es el título de la lista. El atributo list define la lista de valores que se deben incluir en el cuadro combinado. Aquí, se llamará al método getSelect1Values de la acción [Form] para rellenar el cuadro combinado. Este método puede devolver una colección, un diccionario o una matriz. En este caso, devolverá una matriz de cadenas de caracteres [chaine1, chaine2, ...] que generará el siguiente código HTML:
<option value="chaine1">chaine1</option>
<option value="chaine2">chaine2</option>
...
El texto entre las etiquetas <option>...</option> se mostrará en el cuadro combinado. El atributo value designa el valor que se enviará si el usuario selecciona la opción. En este caso, el atributo value y el texto que se muestra en el cuadro combinado son idénticos. En la mayoría de los casos, no es así. Si se selecciona la segunda opción, se enviará la siguiente cadena a la acción [Form]:
select1=cadena2
El campo [Form].select1 recibirá entonces el valor chaine2. Por el contrario, si en el momento de mostrar el formulario este campo tiene el valor chaine3, entonces, visualmente, el tercer elemento
<option value="chaine3">chaine3</option>
aparecerá seleccionado en el cuadro combinado.
El atributo headerValue establece el texto que se mostrará como primera opción del combo y headerKey el valor que se enviará si el usuario elige esta opción.
- línea 31: aquí también hay una lista de tamaño 3 (size=3): a diferencia de la lista anterior, en la que solo se ve un elemento, aquí se verán 3 elementos de la lista. El modo de selección sigue siendo el mismo. Solo se puede seleccionar un elemento.
- línea 32: de nuevo una lista, pero de selección múltiple (multiple=true). En este caso, el valor enviado a la acción [Form] tendrá el siguiente formato:
select3=cadena2&select3=cadena5
si se han seleccionado las opciones chaine2 y chaine5. Cuando se envían varios valores para un mismo parámetro, en este caso select3, la acción debe tener un campo con el nombre del parámetro y ser de tipo tableau. Así, por ejemplo, aquí la acción [Form] podría tener un campo del tipo:
String[] select3;
y los métodos get / set correspondientes. La matriz select3 recibirá entonces la matriz de cadenas de caracteres [chaine2,chaine5]. A la inversa, al mostrar la vista [Form.jsp], los valores del campo [Form].select3 determinan las opciones de la lista select3 que aparecerán seleccionadas. Seguimos en modo lectura/escritura.
- Línea 33: un grupo de botones de radio. El texto del grupo viene dado por el atributo key. Los textos de los botones individuales vienen dados por el atributo list. El valor de este atributo es el nombre de un método de la acción [Form] que debe devolver una colección, un diccionario o una matriz. En este caso, el método [Form].getRadioValues devolverá una matriz de cadenas de caracteres [chaine1,chaine2,...] que generará las siguientes etiquetas HTML:
<input type="radio" name="radio" ... value="chaine1"/>chaine1
<input type="radio" name="radio" ... value="chaine2"/>chaine2
...
Si se marca el botón de radio chaine2, el valor enviado será
radio=cadena2
y este valor se insertará en el campo [Form].radio.
- línea 34: una casilla de verificación. Si está marcada, se enviará la siguiente cadena de parámetros a la acción [Form]
checkbox=true
Si no está marcada, no se envía ninguna cadena de parámetros. Struts 2 cuenta con un mecanismo interno que hace que todo suceda como si la cadena
checkbox=false
se hubiera enviado.
- línea 35: una lista de casillas de selección. Se pueden marcar varias. El texto del grupo se proporciona mediante el atributo key. Los textos de las casillas de selección individuales se proporcionan mediante el atributo list. El valor de este atributo es el nombre de un método de la acción [Form] que debe devolver una colección, un diccionario o una matriz. En este caso, el método [Form].getCheckboxlistValues devolverá una matriz de cadenas de caracteres [chaine1,chaine2,...] que generará las siguientes etiquetas HTML:
<input type="checkbox" name="checkboxlist" ... value="chaine1"/>chaine1
<input type="checkbox" name="checkboxlist" ... value="chaine2"/>chaine2
...
Si el usuario selecciona las casillas denominadas chaine2 y chaine5, se enviará la siguiente cadena de caracteres a la acción [Form]:
checkboxlist=cadena2&checkboxlist=cadena5
La tabla [chaine2, chaine5] se asignará al campo [Form].checkboxlist, que, por lo tanto, debe ser de tipo tabla de cadenas de caracteres, al igual que en las listas de selección múltiple. Por el contrario, al visualizar la vista [Form.jsp], los valores del campo [Form].checkboxlist determinan las casillas de verificación que se marcarán.
- línea 36: un campo oculto. Un campo oculto es un campo que se envía sin que el usuario lo introduzca. Su valor lo fija el programador. Aquí, el campo oculto tomará su valor del campo [Form].hidden. Este mismo valor se enviará en la forma:
hidden=algo
y reasignado al campo [Form].hidden.
- línea 37: un botón de tipo submit. Al hacer clic en este botón, se enviarán todos los valores del formulario a la acción [Form]. La cadena de parámetros enviados tendrá este aspecto:
textfield=texto&password=&textarea=línea1%0D%0Alínea2%0D%0A&select1=cero&select2=tres&select3=cero&select3=dos&__multiselect_select3=&radio=azul&checkbox=true&__checkbox_checkbox=true&checkboxlist=bicicleta&checkboxlist=autobús&__multiselect_checkboxlist=&hidden=inicial&submitText=Validar
9.5. La acción [Form] – parte de introducción de datos
Su código es el siguiente:
package example;
import com.opensymphony.xwork2.ActionSupport;
public class Form extends ActionSupport {
// constructor sin parámetros
public Form() {
}
// campos del formulario
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 seleccionados en el campo select3
public String getSelect3SelectedValues() {
return getValue(select3);
}
// valores seleccionados en el campo checkboxlist
public String getCheckboxlistSelectedValues() {
return getValue(checkboxlist);
}
// método de utilidad
public String getValue(String[] values) {
String result = "";
for (String value : values) {
result += " " + value;
}
return result;
}
// getters y setters de los campos
....
}
- línea 1: el campo asociado a la etiqueta textfield del formulario. Se utilizará para inicializar este campo de entrada, así como para recuperar su valor. Recibe, en el momento de la llamada a POST, el valor introducido en este campo.
- línea 2: el campo asociado a la etiqueta password del formulario. Recibe, en el momento de POST, el valor introducido en este campo.
- línea 13: asociado a la etiqueta textarea del formulario. Recibe, en el momento del POST, el texto introducido en este campo.
- línea 14: asociado a la etiqueta select1 del formulario, una lista de selección única. Su valor inicial selecciona un elemento del combo. Se seleccionará el elemento cuyo atributo value sea igual a este valor. En el momento del POST, recibe el atributo value de la opción seleccionada en el cuadro combinado.
- línea 15: las cadenas de caracteres que alimentarán el combo select1.
- líneas 16 y 17: lo mismo que select1
- línea 18: asociada a la etiqueta select1 del formulario, una lista de selección múltiple. Los valores iniciales de la tabla seleccionan los elementos correspondientes de la lista. Se seleccionarán aquellos elementos cuyo atributo value sea igual a uno de estos elementos. En el momento de la ejecución de POST, recibe los atributos value de las diferentes opciones seleccionadas en el cuadro combinado.
- línea 19: las cadenas de caracteres que alimentarán la lista select3
- línea 20: asociada a la etiqueta radio del formulario. Su valor sirve para marcar uno de los botones de radio, aquel cuyo atributo value sea igual a este valor. Recibe, en el momento de POST, el valor del botón de opción seleccionado.
- línea 21: los diferentes rótulos y valores de los botones de radio.
- línea 22: asociada a la etiqueta checkbox del formulario. Su valor inicial sirve para marcar o desmarcar la casilla. Recibe en el momento de POST el valor true si la casilla ha sido marcada, false en caso contrario.
- línea 23: asociada a la etiqueta checkboxlist del formulario. Los valores iniciales de la tabla seleccionan las casillas de verificación correspondientes. Se marcarán aquellas casillas cuyo atributo value sea igual a uno de esos valores iniciales. En el momento de la ejecución de POST, recibe los atributos value de las diferentes casillas marcadas.
- línea 24: las cadenas de caracteres que alimentarán los rótulos de las casillas de checkboxlist.
- línea 25: asociada al campo oculto hidden. Su valor inicial fijará el valor del campo oculto. En el momento del POST, recibirá este mismo valor, ya que el usuario no tiene la posibilidad de modificarlo.
- línea 26: asociado a la etiqueta submit. En el momento del POST, recibe el texto del botón. Se puede prescindir de este campo.
- Los métodos de las líneas 29, 34 y 39 se comentarán más adelante.
9.6. La vista [Form.jsp] – parte de Confirmación
La vista [Form.jsp] tiene una parte «Confirmación de las entradas» que aún no se ha visto:

Su código es el siguiente:
<%@ 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>
- línea 13: muestra el valor del campo [Form].textfield
- línea 17: muestra el valor del campo [Form].password
- línea 21: muestra el valor del campo [Form].textarea
- línea 25: muestra el valor del campo [Form].select1
- línea 29: muestra el valor del campo [Form].select2
- línea 33: muestra los valores de la tabla [Form].select3. Para ello, utiliza el método [Form].getSelect3SelectedValues.
- línea 37: muestra el valor del campo [Form].radio
- línea 41: muestra el valor del campo [Form].checkbox
- línea 45: muestra los valores de la tabla [Form].checkboxlist. Para ello, utiliza el método [Form].getCheckboxlistSelectedValues.
- línea 49: muestra el valor del campo [Form].hidden
9.7. La acción [Form] – parte de confirmación
Los métodos getSelect3SelectedValues y getCheckboxlistSelectedValues mencionados anteriormente se definen en la clase [Form]:
// valores seleccionados en el campo select3
public String getSelect3SelectedValues() {
return getValue(select3);
}
// valores seleccionados en el campo checkboxlist
public String getCheckboxlistSelectedValues() {
return getValue(checkboxlist);
}
// método de utilidad
public String getValue(String[] values) {
String result = "";
for (String value : values) {
result += " " + value;
}
return result;
}
Se limitan a concatenar los elementos de las tablas que deben mostrar.
9.8. Las pruebas
Al ejecutar el proyecto NetBeans, se obtiene la siguiente página inicial:
![]() |
Los valores mostrados en [1] y [2] proceden de los valores iniciales de los campos de la acción [Form]. Veamos algunos ejemplos:
private String textarea = "ligne1\nligne2\n";
El valor del campo textarea explica las visualizaciones [1A] y [2A].
private String[] select3 = new String[]{"zéro", "deux"};
private String[] select3Values = new String[]{"zéro", "un", "deux", "trois", "quatre"};
El valor del campo select3Values explica el contenido de la lista en [1B]. El valor del campo select3 explica los elementos seleccionados en [1B] y mostrados en [2B].
Si introducimos otros valores en el formulario y lo validamos, los valores introducidos se enviarán a los campos correspondientes de la acción [Form]. A continuación, se volverá a mostrar la vista [Form.jsp]. Por lo tanto, nos encontramos en el mismo caso que anteriormente, salvo que los valores iniciales han sido sustituidos por los valores enviados. He aquí un ejemplo:


9.9. La acción [Form1] y la vista [Form1.jsp]
El archivo de configuración [example.xml] configura la siguiente acción [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>
Líneas 11-13: la llamada a la acción [Form1] genera la vista [Form1.jsp].
La acción [Form1] es la siguiente:
package example;
import com.opensymphony.xwork2.ActionSupport;
public class Form1 extends ActionSupport{
// constructor sin parámetros
public Form1() {
}
// campos del formulario
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;
}
}
La acción [Form1] es idéntica a la acción [Form], salvo que su parte de modelo se ha trasladado a una clase anexa, la clase [Data], línea 11. La clase [Data] es la siguiente:
package example;
public class Data {
// constructor sin parámetros
public Data() {
}
// campos del formulario
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 seleccionados en el campo select3
public String getSelect3SelectedValues() {
return getValue(select3);
}
// valores seleccionados en el campo checkboxlist
public String getCheckboxlistSelectedValues() {
return getValue(checkboxlist);
}
// método de utilidad
public String getValue(String[] values) {
String result = "";
for (String value : values) {
result += " " + value;
}
return result;
}
// getters y setters
....
}
Encontramos los campos declarados anteriormente en la acción [Form].
Como es lógico, la vista [Form1.jsp] es similar a la 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>
La diferencia entre las vistas [Form] y [Form1] puede ilustrarse con la línea 27 que se reproduce a continuación:
<s:textfield name="data.textfield" key="Form.textfield" />
El campo de entrada está vinculado, tanto en lectura como en escritura, al campo data.textfield de la acción [Form1]. Cabe recordar que, tras la ejecución, las propiedades de la acción [Form1] son accesibles desde la vista. Por lo tanto, el atributo name anterior se evaluará como [Form1].getData().getTextField(). Por lo tanto, es necesario que existan los dos métodos get anteriores.
9.10. La acción [Form2] y la vista [Form2.jsp]
El archivo de configuración [example.xml] configura la siguiente acción [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>
Líneas 14-16: la llamada a la acción [Form2] genera la vista [Form2.jsp].
La acción [Form2] es la siguiente:
package example;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
public class Form2 extends ActionSupport implements ModelDriven {
// constructor sin parámetros
public Form2() {
}
// modelo de la acción
public Object getModel() {
return new Data();
}
}
- línea 6: la acción [Form2] implementa la interfaz [ModelDriven]. Solo hay un método que implementar, el método getModel de la línea 12. Este devuelve una instancia de la clase [Data] estudiada anteriormente.
El hecho de que la acción [Form2] implemente la interfaz [ModelDriven] tiene la siguiente consecuencia: la vista mostrada tras la acción [Form2] tiene acceso directo a las propiedades del modelo de la acción [Form2], ya que este es devuelto por el método getModel(). Por lo tanto, la vista [Form2.jsp] vuelve a ser lo que era con la acción [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>
Así, la línea 27, que antes era:
<s:textfield name="data.textfield" key="Form.textfield" />
vuelve a ser:
<s:textfield name="textfield" key="Form.textfield" />
La ventaja de situar el modelo fuera de la vista es que esta arquitectura delimita con mayor claridad las funcionalidades de cada elemento de la arquitectura MVC. El modelo M se identifica claramente mediante una clase. Además, el modelo puede existir antes que las acciones. Así, si una aplicación web gestiona una base de datos de personas, es probable que exista la clase Personne. Si una acción ofrece un formulario de entrada para crear una nueva persona, el modelo de esta acción está claro: es la clase Personne.
Hemos visto lo sencillo que ha sido pasar de la acción [Form] a la acción [Form2]:
- el modelo M de la vista V se ha encapsulado en una clase aparte
- la acción que genera la vista utilizando este modelo implementa la interfaz ModelDriven con el método getModel que devuelve una instancia del modelo M. La acción puede verse entonces como una extensión del controlador C de Struts 2, la clase FilterDispatcher.
El lector podrá aplicar este enfoque a cualquier acción descrita a continuación.

