Struts 2 ofrece una librería de etiquetas que facilitan, entre otras, las tareas de validación e internacionalización. Estas etiquetas, cuyo TLD podemos descubrir en META-INF/struts-tags.tld, en el jar de struts2-core, pueden utilizarse tanto con JSP como con Velocity o FreeMarker. A continuación veremos una lista con las diferentes etiquetas, una pequeña definición, la clase que las implementa, algunos atributos útiles y, cuando se ha considerado necesario, un chico ejemplo (usando JSP). Sin embargo, para eludir repeticiones, comenzaremos primero enumerando algunos atributos comunes a todas las etiquetas de interfaz de usuario: cssClass: El atributo class de HTML. Indica la clase CSS a utilizar para el fundamento HTML generado. cssStyle: El atributo style de HTML. Permite definir el estilo del fundamento inline, en espacio de utilizar un archivo CSS externo o una etiqueta styledisabled : Decide si el control está deshabilitado label: Etiqueta que acompañará al widget. Genera una clásica etiqueta label de HTML. required: Booleano señalando si el tema es obligatorio. Si es así presenta un asterisco al lado de la etiqueta. tabindex: El atributo tabindex de HTML. Utilizado para establecer el orden a seguir al recorrer los controles cuando el usuario pulsa la tecla de Tabulación template: Plantilla a utilizar theme: Tema a utilizar. Ahora si, las etiquetas son las siguientes: action Permite ejecutar una acción desde una vista señalando el nombre de la acción y, opcionalmente, el lugar de nombres. Se puede pasar parámetros utilizando la etiqueta paramorg.apache.struts2.views.jsp.ActionTag executeResult: decide si el fruto de la acción (normalmente otra vista) se debe ejecutar / renderizar también. ignoreContextParams: indica si se deben incluir los parámetros de la petición actual al invocar la acción name (requerido): el nombre de la acción a ejecutar. namespace: el lugar de nombres de la acción a ejecutar. index.jsp %@ taglib uri=?/struts-tags? prefix=?s?%> html> body> Antes de s:actionbr Después de s:action /body> /html> Accion.java import com.opensymphony.xwork2.ActionSupport; @SuppressWarnings(?serial?) public class Accion extends ActionSupport {     private String web;     public String getWeb() {         return web;     public String execute() {         web = ?mundogeek.net?;         return SUCCESS; import com.opensymphony.xwork2.ActionSupport; @SuppressWarnings("serial") public class Accion extends ActionSupport { private String web; public String getWeb() { return web; public String execute() { web = "mundogeek.net"; return SUCCESS; resultado.jsp %@ taglib uri=?/struts-tags? prefix=?s?%> Visita s:property value=?web? %@ taglib uri="/struts-tags" prefix="s"%> Visita s:property value="web" actionerror Presenta los yerros que se produjeron en las acciones, si es que existen. Podemos agregar yerros utilizando el método addActionError(String error) de la interfaz ValidationAware, que ActionSupport implementa. Los métodos y propiedades de ValidationAware también estarán disponibles en la vista, por lo que es probable en su espacio verificar si tienen lugar yerros con el método hasActionErrors() e iterar directamente sobre la colección actionErrors org.apache.struts2.views.jsp.ui.ActionErrorTag Accion.java import com.opensymphony.xwork2.ActionSupport; @SuppressWarnings(?serial?) public class Accion extends ActionSupport {     public String execute() {         addActionError(?Oh dios mío, ¡un error!?);         return ERROR; import com.opensymphony.xwork2.ActionSupport; @SuppressWarnings("serial") public class Accion extends ActionSupport { public String execute() { addActionError("Oh dios mío, ¡un error!"); return ERROR; resultado.jsp %@ taglib uri=?/struts-tags? prefix=?s?%> html> body> s:actionerror  /body> /html> %@ taglib uri="/struts-tags" prefix="s"%> html> body> s:actionerror /body> /html> actionmessage Parecida a actionerror, pero en espacio de yerros en la acción sirve para presentar mensajes de la acción, los cuales añadimos utilizando el método addActionMessage(String mensaje) de la interfaz ValidationAware. Como el anterior, también podríamos utilizar el método hasActionMessages() para verificar la existencia de mensajes e iterar sobre la colección de strings actionMessages org.apache.struts2.views.jsp.ui.ActionMessageTag Accion.java import com.opensymphony.xwork2.ActionSupport; @SuppressWarnings(?serial?) public class Accion extends ActionSupport {     public String execute() {         addActionMessage(?Tengo un mensaje para usted.?);         return SUCCESS; import com.opensymphony.xwork2.ActionSupport; @SuppressWarnings("serial") public class Accion extends ActionSupport { public String execute() { addActionMessage("Tengo un mensaje para usted."); return SUCCESS; resultado.jsp %@ taglib uri=?/struts-tags? prefix=?s?%> html> body> s:actionmessage /body> /html> %@ taglib uri="/struts-tags" prefix="s"%> html> body> s:actionmessage /body> /html> Crea una etiqueta anchor HTML. Se puede utilizar con el asunto ajax para generar llamadas asíncronas al servidor. org.apache.struts2.views.jsp.ui.AnchorTa href: La URL a cargar cuando el usuario pulse sobre el enlace title: Atributo title de HTML. append Crea un nuevo iterador a dividir de varios iteradores pasados como parámetro en manera de etiquetas paramorg.apache.struts2.views.jsp.iterator.AppendIteratorTa var: el nombre que tendrá el iterador resultante en el ValueStack Accion.java import com.opensymphony.xwork2.ActionSupport; import java.util.List; import java.util.ArrayList; @SuppressWarnings(?serial?) public class Accion extends ActionSupport {     private ListString> registrados;     private ListString> vips;     public ListString> getRegistrados() {         return registrados;     public ListString> getVips() {         return vips;     public String execute() {         registrados = new ArrayListString>();         registrados.add(?Juan?);         registrados.add(??);         vips = new ArrayListString>();         vips.add(?Pedro?);         vips.add(?María?);         return SUCCESS; import com.opensymphony.xwork2.ActionSupport; import java.util.List; import java.util.ArrayList; @SuppressWarnings("serial") public class Accion extends ActionSupport { private ListString> registrados; private ListString> vips; public ListString> getRegistrados() { return registrados; public ListString> getVips() { return vips; public String execute() { registrados = new ArrayListString>(); registrados.add("Juan"); registrados.add(""); vips = new ArrayListString>(); vips.add("Pedro"); vips.add("María"); return SUCCESS; resultado.jsp %@ taglib uri=?/struts-tags? prefix=?s?%> html> body> s:append var=?usuarios?>     s:param value=?%{registrados?      s:param value=?%{vips?  /s:append> Usuarios: ul>     s:iterator value=?usuarios?>         li>s:property /li>     /s:iterator> /ul> /body> /html> %@ taglib uri="/struts-tags" prefix="s"%> html> body> s:append var="usuarios s:param value="%{registrados" s:param value="%{vips" /s:append> Usuarios: ul> s:iterator value="usuarios li>s:property /li> /s:iterator> /ul> /body> /html&gt beanInstancia un Java Bean. Se puede pasar valores a las propiedades del bean utilizando etiquetas paramorg.apache.struts2.views.jsp.BeanTa name (requerido): La clase a instanciar var: Nombre con el que se añadirá la instancia a ValueStack Usuario.java view plain copy to clipboar printpublic class Usuario {     private String nombre;     public String getNombre() {         return nombre;     public void setNombre(String nombre) {         this.nombre = nombre; public class Usuario { private String nombre; public String getNombre() { return nombre; public void setNombre(String nombre) { this.nombre = nombre; resultado.jsp view plain copy to clipboar print%@ taglib uri=?/struts-tags? prefix=?s?%> html> body> /s:bean> Bienvenido s:property value=?#miUsuario.nombre? /body> /html> checkbox Crea un checkbox HTML. Para una lista de varios checkboxes relacionados podemos utilizar la etiqueta checkboxlist org.apache.struts2.views.jsp.ui.CheckboxTa value: Booleano que indica si el checkbox está marcado o no. index.jsp view plain copy to clipboar print%@ taglib uri=?/struts-tags? prefix=?s?%> html> body> s:form action=?Accion?>     s:submit value=?Enviar?  /s:form> /body> /html> Accion.java view plain copy to clipboar printimport com.opensymphony.xwork2.ActionSupport; @SuppressWarnings(?serial?) public class Accion extends ActionSupport {     private boolean condiciones;     public boolean isCondiciones() {         return condiciones;     public void setCondiciones(boolean condiciones) {         this.condiciones = condiciones;     public String execute() {         return SUCCESS; import com.opensymphony.xwork2.ActionSupport; @SuppressWarnings("serial") public class Accion extends ActionSupport { private boolean condiciones; public boolean isCondiciones() { return condiciones; public void setCondiciones(boolean condiciones) { this.condiciones = condiciones; public String execute() { return SUCCESS; resultado.jsp view plain copy to clipboar print%@ taglib uri=?/struts-tags? prefix=?s?%> html> body> s:if test=?condiciones?> Muchas gracias. /s:if> s:else> Pues es una lástima. /s:else> /body> %@ taglib uri="/struts-tags" prefix="s"%> html> body> s:if test="condiciones Muchas gracias. /s:if> s:else> Pues es una lástima. /s:else> /body> checkboxlist Crea una lista de checkboxes relacionados (todos con el mismo atributo name). Esto significa que el valor del fundamento no será un booleano señalando si está marcado o no, como en el caso de checkbox, sino una lista con los valores marcados. org.apache.struts2.views.jsp.ui.CheckboxListTa list (requerido): Iterable con los valores con los que generar la lista. listKey : Propiedad de los objetos del iterable del que el checkbox correspondiente tomará su valor. listValue : Exactamente idéntico al anterior, pero en espacio del valor, el contenido name: Nombre de los checkboxes. Accion.java view plain copy to clipboar printimport com.opensymphony.xwork2.ActionSupport; import java.util.List; import java.util.ArrayList; @SuppressWarnings(?serial?) public class Accion extends ActionSupport {     private ListString> lenguajes;     public ListString> getLenguajes() {         return lenguajes;     public String execute() {         lenguajes = new ArrayListString>();         lenguajes.add(?Python?);         lenguajes.add(?Java?);         lenguajes.add(?Ruby?);         lenguajes.add(?C#?);         lenguajes.add(?C++?);         lenguajes.add(?Lisp?);         return SUCCESS; import com.opensymphony.xwork2.ActionSupport; import java.util.List; import java.util.ArrayList; @SuppressWarnings("serial") public class Accion extends ActionSupport { private ListString> lenguajes; public ListString> getLenguajes() { return lenguajes; public String execute() { lenguajes = new ArrayListString>(); lenguajes.add("Python"); lenguajes.add("Java"); lenguajes.add("Ruby"); lenguajes.add("C#"); lenguajes.add("C++"); lenguajes.add("Lisp"); return SUCCESS; resultado.jsp view plain copy to clipboar print%@ taglib uri=?/struts-tags? prefix=?s?%> html> body> body> s:form>     s:submit value=?Enviar?  /s:form> /body> combobox Crea una mezcla de select y caja de texto. El valor de la caja de texto se auto rellena según el fundamento seleccionado en el select. org.apache.struts2.views.jsp.ui.ComboBoxTag emptyOption : Indica si deseamos agregar una alternativa vacía list (requerido): Iterable con los valores con los que generar la lista. listKey : Propiedad de los objetos del iterable del que el checkbox correspondiente tomará su valor. listValue : Exactamente idéntico al anterior, pero en espacio del valor, el contenido name: Nombre a usar para el elemento. readonly : Si deseamos que el usuario pueda escribir sus propios valores en la caja de texto. Accion.java view plain copy to clipboar printimport com.opensymphony.xwork2.ActionSupport; import java.util.List; import java.util.ArrayList; @SuppressWarnings(?serial?) public class Accion extends ActionSupport {     private ListString> lenguajes;     public ListString> getLenguajes() {         return lenguajes;     public String execute() {         lenguajes = new ArrayListString>();         lenguajes.add(?Python?);         lenguajes.add(?Java?);         lenguajes.add(?Ruby?);         lenguajes.add(?C#?);         lenguajes.add(?C++?);         lenguajes.add(?Lisp?);         return SUCCESS; import com.opensymphony.xwork2.ActionSupport; import java.util.List; import java.util.ArrayList; @SuppressWarnings("serial") public class Accion extends ActionSupport { private ListString> lenguajes; public ListString> getLenguajes() { return lenguajes; public String execute() { lenguajes = new ArrayListString>(); lenguajes.add("Python"); lenguajes.add("Java"); lenguajes.add("Ruby"); lenguajes.add("C#"); lenguajes.add("C++"); lenguajes.add("Lisp"); return SUCCESS; resultado.jsp view plain copy to clipboar print%@ taglib uri=?/struts-tags? prefix=?s?%> html> body> body> s:form action=?Otro?>         label=?Lenguaje preferido? readonly=?true?      s:submit value=?Enviar?  /s:form> /body&gt datePermite presentar una fecha almacenada en una alguna variable señalando opcionalmente el formato a utilizar. org.apache.struts2.views.jsp.DateTag format : Formato a utilizar para presentar la fecha. Si deseamos usar siempre el mismo formato podemos crear un archivo properties con una acceso struts.date.format. Por defecto se emplea el formato DateFormat.MEDIU name (requerido): Nombre de la variable que contiene la fecha a presentar nice: Emplea un formato que facilita la lectura. Por defecto se emplea inglés para presentar los mensajes; si deseamos traducirlo a determinado otro idioma tendremos que recurrir a las funciones de internacionalización de Struts 2. Las claves a traducir son las próximos CLAVEVALOR POR DEFECTO struts.date.format.past {0 ago struts.date.format.future in {0 struts.date.format.seconds an instant struts.date.format.minutes {0,choice,1#one minute|1{0 minutes struts.date.format.hours {0,choice,1#one hour|1{0 hours{1,choice,0#|1#, one minute|1, {1 minutes struts.date.format.days {0,choice,1#one day|1{0 days{1,choice,0#|1#, one hour|1, {1 hours struts.date.format.years {0,choice,1#one year|1{0 years{1,choice,0#|1#, one day|1, {1 days Accion.java view plain copy to clipboar printimport com.opensymphony.xwork2.ActionSupport; import java.util.Calendar; import java.util.Date; @SuppressWarnings(?serial?) public class Accion extends ActionSupport {     private Date ahora;     private Date anyoNuevo;     public Date getAhora() {         return ahora;     public Date getAnyoNuevo() {         return anyoNuevo;     public String execute() {         ahora = new Date();         Calendar cal = Calendar.getInstance();         int anyo = cal.get(Calendar.YEAR);         cal.set(anyo + 1, Calendar.JANUARY, 1);         anyoNuevo = cal.getTime();         return SUCCESS; import com.opensymphony.xwork2.ActionSupport; import java.util.Calendar; import java.util.Date; @SuppressWarnings("serial") public class Accion extends ActionSupport { private Date ahora; private Date anyoNuevo; public Date getAhora() { return ahora; public Date getAnyoNuevo() { return anyoNuevo; public String execute() { ahora = new Date(); Calendar cal = Calendar.getInstance(); int anyo = cal.get(Calendar.YEAR); cal.set(anyo + 1, Calendar.JANUARY, 1); anyoNuevo = cal.getTime(); return SUCCESS; resultado.jsp view plain copy to clipboar print%@ taglib uri=?/struts-tags? prefix=?s?%> html> body> body> /body&gt debugImprime información de depuración (entre otros, el contenido de ValueStack org.apache.struts2.views.jsp.ui.DebugTa divCrea un fundamento div de HTML. org.apache.struts2.views.jsp.ui.DivTag doubleselect Crea dos fundamentos select HTML, con el segundo de ellos modificando sus valores dependiendo del valor seleccionado en el primero. org.apache.struts2.views.jsp.ui.DoubleSelectTag doubleList (requerido): Lista con los valores que tendrá el segundo select. doubleMultiple : Decide si en el segundo select se pueden seleccionar varios valores o solo uno. doubleName (requerido): Nombre del fundamento list (requerido): Lista con los valores que tendrá el primer select. Artista.java view plain copy to clipboar printimport java.util.List; public class Artista {     private String nombre;     private ListString> canciones;     public Artista(String nombre, ListString> canciones) {         this.nombre = nombre;         this.canciones = canciones;     public String getNombre() {         return nombre;     public ListString> getCanciones() {         return canciones; import java.util.List; public class Artista { private String nombre; private ListString> canciones; public Artista(String nombre, ListString> canciones) { this.nombre = nombre; this.canciones = canciones; public String getNombre() { return nombre; public ListString> getCanciones() { return canciones; Accion.java view plain copy to clipboar printimport com.opensymphony.xwork2.ActionSupport; import java.util.List; import java.util.ArrayList; @SuppressWarnings(?serial?) public class Accion extends ActionSupport {     private ListArtista> artistas;     public ListArtista> getArtistas() {         return artistas;     public String execute() {         artistas = new ArrayListArtista>();         ListString> canciones_p = new ArrayListString>();         canciones_p.add(?El equilibro es imposible?);         canciones_p.add(?Años 80″);         canciones_p.add(?Promesas que no valen nada?);         Artista piratas = new Artista(?Los piratas?, canciones_p);         artistas.add(piratas);         ListString> canciones_c = new ArrayListString>();         canciones_c.add(?Viva la vida?);         canciones_c.add(?Clocks?);         canciones_c.add(?Life in technicolor?);         Artista coldplay = new Artista(?Coldplay?, canciones_c);         artistas.add(coldplay);         return SUCCESS; import com.opensymphony.xwork2.ActionSupport; import java.util.List; import java.util.ArrayList; @SuppressWarnings("serial") public class Accion extends ActionSupport { private ListArtista> artistas; public ListArtista> getArtistas() { return artistas; public String execute() { artistas = new ArrayListArtista>(); ListString> canciones_p = new ArrayListString>(); canciones_p.add("El equilibro es imposible"); canciones_p.add("Años 80"); canciones_p.add("Promesas que no valen nada"); Artista piratas = new Artista("Los piratas", canciones_p); artistas.add(piratas); ListString> canciones_c = new ArrayListString>(); canciones_c.add("Viva la vida"); canciones_c.add("Clocks"); canciones_c.add("Life in technicolor"); Artista coldplay = new Artista("Coldplay", canciones_c); artistas.add(coldplay); return SUCCESS; resultado.jsp view plain copy to clipboar print%@ taglib uri=?/struts-tags? prefix=?s?%> html> body> body> s:form action=?Otro?>     s:doubleselect label=?Selecciona la canción? list=?artistas?     s:submit value=?Enviar?  /s:form> /body> fielderror Presenta los yerros que se han detectado al cerciorar los campos del formulario. Por defecto se muestran todos los yerros, pero podemos seleccionar que se muestren sólo los relativos a ciertos campos pasándole etiquetas param. El funcionamiento es semejante al de actionerro y actionmessage : podemos agregar yerros utilizando el método addFieldError(String fieldName, String errorMessage) de la interfaz ValidationAware, que ActionSupport implementa. Hay que tener en cuenta, no obstante, que si redirigimos al formulario de acceso el propio formulario imprimará estos yerros por defecto sin necesidad de agregar esta etiqueta. Los métodos y propiedades de ValidationAware también estarán disponibles en la vista, por lo que es probable en su espacio verificar si tienen lugar yerros con el método hasFieldErrors() e iterar directamente sobre la colección fieldErrors org.apache.struts2.views.jsp.ui.FieldErrorTag index.jsp view plain copy to clipboar print%@ taglib uri=?/struts-tags? prefix=?s?%> html> body> s:fielderror  s:form action=?Accion?>     s:submit value=?Enviar?  /s:form> /body> /html> Accion.java view plain copy to clipboar printimport com.opensymphony.xwork2.ActionSupport; @SuppressWarnings(?serial?) public class Accion extends ActionSupport {     private String nombre;     public String getNombre() {         return nombre;     public void setNombre(String nombre) {         this.nombre = nombre;     public String execute() {         if(nombre.length() > 10) {             addFieldError(?nombre?, ?El nombre no puede tener más de 10 caracteres.?);             return ERROR;         return SUCCESS; import com.opensymphony.xwork2.ActionSupport; @SuppressWarnings("serial") public class Accion extends ActionSupport { private String nombre; public String getNombre() { return nombre; public void setNombre(String nombre) { this.nombre = nombre; public String execute() { if(nombre.length() > 10) { addFieldError("nombre", "El nombre no puede tener más de 10 caracteres."); return ERROR; return SUCCESS; resultado.jsp view plain copy to clipboar print%@ taglib uri=?/struts-tags? prefix=?s?%> html> body> body> s:fielderror  /body> %@ taglib uri="/struts-tags" prefix="s"%> html> body> body> s:fielderror /body&gt fileMuestra un tema file de HTML. Para facilitarnos la vida podemos aprovechar el interceptor fileUpload que se descubre en la selección de interceptores por defecto ( defaultStack ) y que funciona de manera similar al interceptor param. Basta crear setters y getters en la acción para las nuevas propiedades nombre (el archivo en si), nombre ContentType (el tipo MIME del archivo subido) o nombre FileName (el nombre del archivo subido) para tener entrada a estos valores en la acción. org.apache.struts2.views.jsp.ui.FileTag accept : atributo del mismo nombre de HTML que faculta indicar los tipos MIME que acepta el campo. index.jsp view plain copy to clipboar print%@ taglib uri=?/struts-tags? prefix=?s?%> html> body>         accept=?text/txt?      s:submit value=?Enviar?  /s:form> /body> /html> Accion.java view plain copy to clipboar printimport com.opensymphony.xwork2.ActionSupport; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; @SuppressWarnings(?serial?) public class Accion extends ActionSupport {     private File archivoTexto;     private String archivoTextoContentType;     private String archivoTextoFileName;     private String contenido;     public String getContenido() {         return contenido;     public File getArchivoTexto() {         return archivoTexto;     public void setArchivoTexto(File archivoTexto) {         this.archivoTexto = archivoTexto;     public String getArchivoTextoContentType() {         return archivoTextoContentType;     public void setArchivoTextoContentType(String archivoTextoContentType) {         this.archivoTextoContentType = archivoTextoContentType;     public String getArchivoTextoFileName() {         return archivoTextoFileName;     public void setArchivoTextoFileName(String archivoTextoFileName) {         this.archivoTextoFileName = archivoTextoFileName;     public String execute() throws IOException {         BufferedReader input = new BufferedReader(new FileReader(archivoTexto));         String linea = ?";         contenido = ?";         while ((linea = input.readLine()) != null)             contenido = contenido + linea;         return SUCCESS; import com.opensymphony.xwork2.ActionSupport; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; @SuppressWarnings("serial") public class Accion extends ActionSupport { private File archivoTexto; private String archivoTextoContentType; private String archivoTextoFileName; private String contenido; public String getContenido() { return contenido; public File getArchivoTexto() { return archivoTexto; public void setArchivoTexto(File archivoTexto) { this.archivoTexto = archivoTexto; public String getArchivoTextoContentType() { return archivoTextoContentType; public void setArchivoTextoContentType(String archivoTextoContentType) { this.archivoTextoContentType = archivoTextoContentType; public String getArchivoTextoFileName() { return archivoTextoFileName; public void setArchivoTextoFileName(String archivoTextoFileName) { this.archivoTextoFileName = archivoTextoFileName; public String execute() throws IOException { BufferedReader input = new BufferedReader(new FileReader(archivoTexto)); String linea = ""; contenido = ""; while ((linea = input.readLine()) != null) contenido = contenido + linea; return SUCCESS; action: Acción a la que se enviará la petición con los datos del formulario. También se puede unir otras páginas o servlets. Si no empleamos el atributo para especificar el destino se emplea la misma página del formulario. namespace: Lugar de nombres al que pertenece la acción a la que se enviará la petición. Por defecto se emplea el lugar de nombres actual. validate: Si deseamos cerciorar los campos del formulario antes de enviarlos. component Utilizado para crear nuestras particulares etiquetas sin tener que recurrir a la API de etiquetas de JSP. org.apache.struts2.views.jsp.ui.ComponentTa headEtiqueta auxiliar que se coloca dentro de la etiqueta head de HTML y se encarga de generar diferentes fundamentos necesarios para otras etiquetas, como las etiquetas para la carga de hojas de estilo o scripts. org.apache.struts2.views.jsp.ui.HeadTag hidden Crea un tema oculto. org.apache.struts2.views.jsp.ui.HiddenTa i18nCarga un archivo de recursos adicional con la traducción de vuestros mensajes y los coloca en ValueStack de manera que puedan ser accedidos fácilmente por el código que se encuentre dentro de la etiqueta. org.apache.struts2.views.jsp.I18nTa name (requerido): Nombre del ResourceBundle a cargar.