VERSIONES
- 18/09/2013 (Primera publicación)
- 24/12/2013:
- Pequeñas mejoras y actualizaciones.
18/09/2013
Como complemento a las etiquetas de Struts2 que nos ayudan a construir la vista, disponemos de un plugin que encapsula numerosos widgets gráficos basados en jQuery en etiquetas JSP fácilmente integrables con nuestro framework. Vamos a hacer la primera toma de contacto con este subproyecto de Struts 2 ver con el componente que más he usado y todo un clásico, el selector de fechas.
En primer lugar, debemos incluir la librería correspondiente en nuestro proyecto. Si usamos Maven, la versión actual es la siguiente:
<dependency> <groupId>com.jgeppert.struts2.jquery</groupId> <artifactId>struts2-jquery-plugin</artifactId> <version>3.6.1</version> </dependency>
Este es el paquete con el grueso de componentes, existen otros tal y como vemos en página de descargas, incluyendo un plugin para jQuery Mobile.
Hay que tener en cuenta además que el plugin tiene como dependencia struts2-core, y es posible que no haya sido actualizado a la última versión. En el ejemplo, la versión 3.6.1 del plugin importa la versión 2.3.15.1 de Struts 2 mientras que usamos la 2.3.15.3. No debería haber problemas de conflictos, pero podemos evitarlos con la siguiente exclusión si fuera necesario:
<dependency> <groupId>com.jgeppert.struts2.jquery</groupId> <artifactId>struts2-jquery-plugin</artifactId> <version>3.6.1</version> <exclusions> <exclusion> <groupId>org.apache.struts</groupId> <artifactId>struts2-core</artifactId> </exclusion> </exclusions> </dependency>
Nota:La versión de 2.3.16 de Struts 2 es incompatible con la versión 3.6.1 del plugin por lo que hay que esperar se publique una nueva versión del plugin antes de actualizar Struts 2 o bien utilizar la última SNAPSHOT. Más información aquí.
Para hacer uso de los widgets, debemos incluir en el head de nuestras páginas la etiqueta sj:head que se encargará de enlazar jQuery y realizar las configuraciones requeridas por el plugin. La versión que se importa es anterior a la serie 2 por lo que es compatible con IE 8. Esta etiqueta tiene varios atributos, el único que vamos a necesitar es el del locale para que el selector de fechas muestre el calendario debidamente localizado. Usaremos el locale que por defecto haya tomado Struts 2 (si no usamos ninguna configuración especial se toma el locale del navegador). La JSP completa que usaremos en la demo es la siguiente y en la misma he resaltado lo más destacado. Obsérvese que se utilizará lo visto en el tip #05 para la visualización de errores.
<%@ page contentType="text/html; charset=UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags"%> <%@ taglib prefix="sj" uri="/struts-jquery-tags"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <%@include file="/jsp/head.jsp" %> <sj:head locale="%{locale.language}" loadAtOnce="true"/> <STYLE type="text/css"> .div-error { background-color: #ea9184; border: 2px solid #ea523b; font-weight: bold; padding: 6px 6px 6px 6px; text-align: left; font-size: 1em; width: 99%; margin-top: 10px; display:none; } .div-error li { list-style-type: none; } </STYLE> <s:if test="hasActionErrors()"> <script type="text/javascript"> $(document).ready(function() { $(".div-error").slideDown(500); }); </script> </s:if> </head> <body> <s:if test="hasActionErrors()"> <div class="div-error"> <s:actionerror /> </div> </s:if> <form action="submitDateAction" method="post"> <div style="float:left"> <s:text name="date"/>: <sj:datepicker name="dateString" displayFormat="%{getText('pattern')}" cssStyle="width: 150px" maxlength="10" yearRange="2013:2020" changeYear="true" changeMonth="true" readonly="false" title="%{getText('date')}" showAnim="slideDown" duration="fast"/> </div> <div style="clear:both"/> <div style="float:left"> <s:submit value="%{getText('submit')}"/> </div> </form> <%@include file="/jsp/footer.jsp" %> </body> </html>
Se ha usado una configuración básica del widget sj:datepicker sólo para la fecha (también se puede utilizar para seleccionar la hora). Los atributos más interesantes son:
- name: el atributo del Action que recogera el valor. Para evitar problemas, yo siempre uso un String en lugar de Date o Calendar.
- displayFormat: el formato de la fecha, en este caso recogido de los properties de i18n.
- readonly: indica si se puede introducir una fecha manualmente o deberá seleccionarse únicamente del calendario que por defecto se desplegará al pulsar el input de la fecha o el botón. Esta visualización y comportamiento del calendario también es totalmente configurable.
- showAnim: se usará una animación para mostrar y ocultar el calendario selector
La etiqueta admite cerca de 100 atributos, por lo que recomiendo revisar a fondo la documentación oficial.
Con respecto al Action, validará que la fecha recogida es correcta, y si no es mostrará un mensaje de error y la reseteará.
package com.danielme.tips.struts2.tip8.actions; import java.text.ParseException; import java.text.SimpleDateFormat; import org.apache.commons.lang.StringUtils; import com.opensymphony.xwork2.ActionSupport; /** * * @author danielme.com * */ public class MainAction extends ActionSupport { private static final long serialVersionUID = 33466065079709970L; private String dateString = ""; public String execute() { return SUCCESS; } public String submitDate() { SimpleDateFormat dateFormat = new SimpleDateFormat(getText("pattern")); if (!StringUtils.isBlank(dateString)) { if (dateString.length() != 10) { addActionError(getText("error")); dateString = ""; } else { try { dateFormat.parse(dateString); } catch (ParseException e) { addActionError(getText("error")); dateString = ""; } } } return SUCCESS; } public String getDateString() { return dateString; } public void setDateString(String date) { dateString = date; } }
El resultado final se muestra en el siguiente video. Primero se muestra la aplicación en Chromium en Ubuntu configurado en inglés, y en segundo lugar Windows XP con IE8 en español. Obsérvese cómo la localización funciona correctamente, algo problemático en versiones bastantes anteriores del plugin pero que afortunadamente ahora ya parece solucionado.
Con respecto a los estilos, el plugin está diseñado para utilizar alguno de los temas que se proporcionan por defecto o que desarrollemos un tema para el mismo pero se pueden sobreescribir sólo los estilos que queramos. Por ejemplo, en el caso del selector de fecha el estilo para el botón se denomina ui-datepicker-trigger. Si simplemente queremos utilizar una imagen para mostrar el calendario, usaremos los siguientes atributos de sj:date:
buttonImage="../images/calendario.png" buttonImageOnly="true"
.
El proyecto completo para Maven se encuentra en Github. Para más información sobre cómo utilizar GitHub, consultar este artículo.