Master J2EE de Oracle: Paso 8 de 12: Diseñar Mejores Interfaces de Usuario

Puede encontrar la versión original de este artículo en Inglés en:

http://www.oracle.com/technology/pub/articles/masterj2ee/index.html

Aprenda cómo añadir componentes JavaServer Faces a Aplicaciones Struts.

Beneficios del Marco de Trabajo Struts

El marco de trabajo Struts es muy popular para construir aplicaciones Web basadas en Java. Entre sus características clave se incluyen:

  • Una arquitectura general basada en los principios de diseño de Modelo-Vista-Controlador (MVC) en el que todas las peticiones son procesadas por el controlador que realiza todo el control y despacha las peticiones a los componentes de la aplicación apropiados, basándose en los indentificadores lógicos que reducen el acoplamiento entre capas.
  • Capacidades de manejo de formularios, como el JavaBean ActionForm que representa el estado del lado del servidor de los campos de entrada de un formulario, y un marco de trabajo de validación que externaliza la configuración de un conjunto de chequeos de exactitud que se aplican a los valores de los campos de entrada, además implementa estos chequeos tanto en el lado del cliente como en el lado del servidor.
  • El marco de trabajo Tiles para el control de la distribución de componentes, que soporta la creación de sofisticadas plantillas que se pueden reutilizar entre varias páginas, esto permite una fácil modificación del aspecto y comportamiento general de toda la aplicación.
  • Un conjunto de etiquetas JSP personalizadas que simplifican el proceso de crear las etiquetas HTML de la aplicación para la capa "Vista", y que trabaja sinergicamente con las capacidades de manejo de formularios y la arquitectura general del controlador.

Esta combinación de características sumadas a la madurez de la implementación de Struts (se creó originalmente en el año 2000), y el importante ecosistema de soporte que hay alrededor de Struts (documentación, libros, artículos, consultores, forums de soporte, etc...) son algunas de las razones por las que Struts se ha convertido en la arquitectura 'de facto' para los desarrolladores J2EE.

El Camino de Futuro de Struts

Según ha ido evolucionando Struts, sus desarrolladores (entre los que me incluyo) han favorecido fuertemente la estabilidad del API sobre otros objetivos, para asegurar que portar aplicaciones Struts desde versiones anteriores sería fácil y no requeriría que los desarrolladores hicieran cambios importantes en su código. Las dos últimas transiciones entre versiones (desde la 1.0 a la 1.1, y desde la 1.1 a la 1.2) son evidencias de este objetivo, que permenece como énfasis principal en el esfuerzo actual hacia la versión 1.3 de Struts: el foco de desarrollo ha sido la remodelación del interior de Struts para hacerlo más fácil de configurar y utilizar, mientras mantiene la compatibilidad con versiones anteriores del API para que los desarrolladores quieran migrar sus aplicaciones existentes a la nueva versión.

Es decir, el futuro desarrollo de Struts debe tener en cuenta dos factores principales:

  • En los últimos cuatro años se han implementado muchas innovaciones en los marcos de trabajo de aplicaciones Web, ofreciendo elegancia en algunas áreas a las que Struts no llegaba por culpa de nuestro comprimiso de compatibilidad con versiones anteriores.
  • En el último año ha aparecido JavaServer Faces, un API estándar de Java para construir componentes de interface de usuario para aplicaciones Web; esencialmente se ha liberado un marco de trabajo con un solapamiento importante con Struts.

Por estas razones, más allá del trabajo que se realiza en la versión 1.3 de Struts, sus desarrolladores también han comenzado conversaciones sobre cómo debería ser la versión 2.0; el cambio en el número de versión mayor indica que estamos pensando en enfocarnos más en el diseño de Struts, actualizándolo con las tendencias tecnológicas actuales, y menos en la compatibilidad con versiones anteriores.

De hecho, yo he realizado una propuesta particular (cuyo nombre clave es "Shale") que 'visiona' un Struts 2.0 que está construido alrededor de JavaServer Faces, que proporciona características de valor añadido que el propio JavaServer Faces no proporciona. (Puede encontrar más información sobre Shale en http://wiki.apache.org/struts/StrutsShale). Veamos algo sobre los beneficios de JavaServer Faces antes de entrar en el modo de unir ámbas tecnologías en sus aplicaciones J2EE basadas en Struts.

Beneficios de JavaServer Faces

Como habrá observado arriba, JavaServer Faces es el API Java estándar para construir interfaces de usuario en aplicaciones Web. Se enfoca en la capa de la Vista de la arquitectura Modelo-Vista-Controlador, aunque proporciona suficiente capacidad de control para escribir aplicaciones moderadamente complejas utilizando un único API. Entre sus características clave se incluyen:

  • APIs fundamentales para componentes de interface de usuario, además de un conjunto básico de componentes estándar que está garantizado que existan en cualquier implementación de JavaServer Faces.
  • Modelo basado en eventos y oyentes para manejar los eventos del lado del servidor, basado en los patrones de diseño estándar de JavaBeans.
  • Expresiones de uniones de valores y de métodos basadas en un superconjunto del lenguaje de expresión presentado en JSP Standard Tag Library (JSTL) 1.0, e incorporado a JavaServer Pages (JSP) 2.0. Estas expresiones le permiten unir propiedades de componentes a objetos de su modelo de datos y/o incluso manejar métodos de su lógica de negocio, sin requerir que los componentes tengan conocimiento detallado de las clases Java implicadas.
  • Ciclo de vida del procesamiento de peticiones bien definido que implementa el patrón de diseño Front Controller (el mismo patrón implementando en el controlador de Struts), con conectores para la lógica de aplicación que pueden responder a los eventos ocurridos durante el procesamiento de cada petición.
  • Soporte de navegación de páginas básico, con una implementación por defecto que elige la siguiente vista (o página) basándose en tres factores:
    • La vista que está procesando la petición actual.
    • El método action que fue llamado (normalmente, cada método action corresponde con un botón de envío de un formulario).
    • El string lógico outcome devuelto por el método action y que describe los resultados de esta acción.
  • Facilidades de manejo de beans que, en el proceso de evaluación de expresiones uniones de valores y de métodos, puede hacer que se ejemplaricen nuevos beans bajo demanda, tener sus propiedades configuradas, y opcionalmente almacenarlos en algún ámbito. La facilidad de manejo de beans implementa el estilo de configuración basado en Inversión de Control (IoC) conocido con inyección de selecciones.

El Camino de Futuro de JSF

Inicialmente liberado en Marzo de 2004, JavaServer Faces 1.0 fue rápidamente seguido por una versión 1.1 de mantenimiento que eliminaba algunos errores tipográfios e inconsistencias de la versión inicial, y también corregía algunos graves errores en la correspondiente implementación de referencia.

JavaServer Faces 1.2 está en desarrollo actualmente (bajo los auspicios del grupo de expertos JSR-252). La mayor parte del esfuerzo de desarrollo se está enfocando en mejorar el alineamiento entre JavaServer Faces y JavaServer Pages (versión 2.1 que también está desarrollándose), particularmente en las áreas de resolución de diferencias entre la sintaxis y la semántica del lenguaje de expresión, y los problemas de interoperabilidad entre los componentes JavaServer Faces y las plantillas de texto JSP.

Cuando esté terminado, el soporte de JavaServer Faces 1.2 será obligatorio en cualquier plataforma Java 2 Enterprise Edition (J2EE) 5.0: las aplicaciones basadas en J2EE 5.0 podrán asumir que el servidor de aplicaciones soportará JSF. Mientras tanto, JavaServer Faces ya ha ganado el apoyo de los desarrolladores (incluyendo aquellos que están creando librerías de componentes personalizados sobre los APIs estándar), así como robustas herramientas de soporte como Oracle JDeveloper 10g, Sun Java Studio Creator, e IBM WebSphere Application Developer. Está claro que esta tecnología será incluso más mayoritaria en un futuro.

¿Qué Tecnología Usar?

Cuando una tecnología se estandariza en un área funcional que solapa un estándar 'de facto' existente, como es el caso de JavaServer Faces y Struts, los desarrolladores y arquitectos naturalmente quieren consejo sobre cuál de las dos tecnologías utilizar, o, de hecho, si puede utilizarlas juntas. El autor de este artículo ha respondido ampliamente a esta cuestión en su blog.

Dejemos esta cuestión en la blogosfera, asumamos que usted tiene una o más aplicaciones basadas en Struts. Usted ha visto el potencial de usar algunos de los sofisticados componentes de JavaServer Faces para mejorar el interface de usuario de su aplicación pero no tiene tiempo de reescribir completamente la aplicación para basarla en los APIs de JavaServer Faces. ¿Hay una forma en la que usted pueda tener lo mejor de ámbos mundos, utilizando los nuevos componentes de interface de usuario mientras preserva sus inversiones en la lógica de negocio, la validación y todo el resto?

La respuesta es "SI", utilizando la librería de integración Struts-Faces creada expresamente para este própósito. El objetivo principal de esta librería es permitir a los desarrolladores migrar componentes de interface de usuario de aplicaciones existentes desde Struts a JSF, página a página, con cambios mínimos en los ficheros de configuración existentes (struts-config.xml) y sin cambios en las lógicas de negocio o de persistencia.

La librería funciona con Struts 1.1 o el más reciente Struts 1.2.x. Pronto se liberará una versión final de la librería pero mientras tanto están disponibles las construcciones nocturnas.

Observe que JavaServer Faces require una plataforma que soporte Servlet 2.3 (o posterior) y JSP 1.2 (o superior), ambos están soportados por cualquier plataforma J2EE 1.3 (o superior).

Introducción a la Librería de Integración Struts-Faces

Veamos un sencillo ejemplo. Primero, descargue la Librería de Integración de Struts-Faces, y siga las instrucciones del fichero README.txt para configurar su entorno e incorporar la nueva librería a su aplicación.

Para entender el proceso de migración, veamos un ejemplo de una página JSP que define la pantalla de login para su aplicación. La versión actual basada en Struts se podría parecer a esto:

<%@ taglib uri="/tags/struts-bean" prefix="bean" %>
<%@ taglib uri="/tags/struts-html" prefix="html" %>
<html:html>
<head>
<title><bean:message key="logon.title"/></title>
</head>
<body>
<html:errors/>
<html:form action="/logon"/>
<table border="0">
  <tr>
    <td align="right">
      <bean:message key="prompt.username"/>
    </td>
    <td align="left">
      <html:text property="username"/>
    </td>
  </tr>
  <tr>
    <td align="right">
      <bean:message key="prompt.password"/>
    </td>
    <td align="left">
      <html:password property="password"/>
    </td>
  </tr>
  <tr>
    <td align="right">
      <html:submit value="Log On"/>
    </td>
    <td align="left">
      <html:reset/>
    </td>
  </tr>
</table>
</html:form>
</body>
</html:html>
		

En los siguientes pasos, verá que necesitará hacer algunas simples modificaciones para usar las librerías de etiquetas de JSF, para cambiar el modo en que las páginas manejan la localización para los mensajes, y otros detalles.

Paso 1: Cambiar las Declaraciones de Librerías de Etiquetas

Reemplace las declaraciones de las librerías de etiquetas que hay en la parte superior de la página (y cambie la etiqueta <html:html> por un elemento normal <html>) con las siguientes declaraciones:

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://struts.apache.org/tags-faces" prefix="s" %>
<f:view>
<html>
			

Las primeras dos librerías de etiquetas son las estándars proporcionadas por cualquier implementación de JavaServer Faces. La tercera es la librería de integración que contiene etiquetas específicamente diseñadas para hacer la migración más fácil.

Asegúrese también de reemplazar el elemento </html:html> al final de la página con </html>, y añada la siguiente etiqueta de cierre </f:view>.

Paso 2: Modificar las Declaraciones para Mensajes Localizados

La página Struts original del listado 1 sigue las mejores prácticas y usa la etiqueta <bean:message> para soportar la localización del título de la página y los campos del formulario. Para activar los mensajes personalizados en la página migrada, añada la siguiente declaración inmediatamente debajo del nuevo elemento <f:view>:

<f:loadBundle var="messages" basename="com.mycompany.myapp.ApplicationResources"/>
			

Reemplaze el valor del atributo basename con el nombre del paquete de recursos que contiene los recursos (mensajes) para esta página. La etiqueta hará que los mansajes estén disponibles dentro de esta página, con el nombre messages.

Luego, reemplace todos los usos de la etiqueta <bean:message> por el componente <h:outputText>. Por ejemplo, el título de la página se especificaría como:

<title>
  <h:outputText value="#{messages['logon.title']"/>
</title>
			

Esto instruye a JavaServer Faces para que busque un mensaje almacenado con la clave logon.title en el fichero de recursos de la aplicación. La respuesta será localizada basándose en la Locale seleccionada por el usuario.

Paso 3: Cambiar las Etiquetas de los Errores y de los Componentes del Formulario

Los componentes JavaServer Faces ni pueden leer los mensajes ActionError y ActionMessage proporcionados por Struts, ni sus componentes de formulario puede cargar automáticamente un bean ActionForm (como hace la etiqueta form estándar de Struts). Esto es por lo que la librería de integración proporciona componentes especializados para soportar estas funciones de la forma esperada por una aplicación Struts. Para usar estos componentes, reemplace las etiquetas <html:errors/> y <html:form> por:

<s:errors/>
<s:form action="/logon">
			

No olvide cambiar la etiqueta de cierre </html:form> por </s:form>.

Paso 4: Utilizar JSF EL para los campos de entrada

Cada campo de entrada de un formulario Struts está unido a una propiedad de su bean form. Para conseguir lo mismo con componentes JavaServer Faces, utilizamos expresiones de unión de valores. Como JavaServer Faces no sabe como buscar una definición de un bean de formulario, debe referenciarlos explícitamente en las expresiones. Por ejemplo, asumiendo que el nombre del bean form (registrado en struts-config.xml) es logonForm, usted debería reemplazar las etiquetas <html:text> y <html:password> con:

<h:inputText id="username" value="#{logonForm.username}"/>
...
<h:inputSecret id="password" value="#{logonForm.password}"/>
			

Paso 5: Cambiar las etiquetas de los Botones de Envío y Reset

El último cambio que necesitamos hacer en el JSP original del Listado 1 es reemplazar las etiquetas de los dos botones con sus correspondientes versiones en JavaServer Faces:

<h:commandButton id="submit" type="SUBMIT"
    value="#{messages['button.logon']"/>
...
<h:commandButton id="reset" type="RESET"
    value="#{messages['button.reset']"/>
			

Observe que JavaServer Faces nos permite localizar las etiquetas de los botones utilizando el mismo mecanismo utilizado para los campos de entrada (Debe asegurarse de definir las propiedades en su paquete de recursos para las claves button.logon y button.reset, si no lo hace, no funcionará). El listado 2 muestra la página JSP con todos los cambios realizados. Pero todavía hay más cambios que hacer en la infraestructura de su servidor de aplicaciones.

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://struts.apache.org/tags-faces" prefix="s" %>
<f:view>
<f:loadBundle var="messages" basename="com.mycompany.myapp.ApplicationResources"/>
<html>
<title><h:outputText value="#{messages['logon.title']"/></title>
</head>
<body>
<s:errors/>
<s:form action="/logon"/>
<table border="0">
  <tr>
    <td align="right">
      <h:outputText value="{messages['prompt.username']"/>
    </td>
    <td align="left">
      <html:text property="username"/>
    </td>
  </tr>
  <tr>
    <td align="right">
      <h:outputText value="#{messages['prompt.password']"/>
    </td>
    <td align="left">
      <h:inputSecret id="password" value="#{logonForm.password}"/>
    </td>
  </tr>
  <tr>
    <td align="right">
        <h:commandButton id="submit" type="SUBMIT" value="#{messages['button.logon']"/>
    </td>
    <td align="left">
      <h:commandButton id="reset" type="RESET" value="#{messages['button.reset']"/>
    </td>
  </tr>
</table>
</s:form>
</body>
</html>
</f:view>
			

Paso 6: Cambios en el Descriptor de Despliegue de la Aplicación Web

Antes de poder ejecutar la página migrada, debe modificar los ficheros de configuración para referenciar los recursos JSF en vez de los JSP. En struts-config.xml, cambie cualquier punto de reenvió lógico a /logon.jsp como /logon.faces y añada las declaraciones del servlet JavaServer Faces y el mapeo del servlet a su fichero web.xml (en los sitios adecuados):

<servlet>
  <servlet-name>faces</servlet-name>
  <servlet-class>
    javax.faces.webapp.FacesServlet
  <servlet-class>
</servlet>
...
<servlet-mapping>
  <servlet-name>faces</servlet-name>
  <url-pattern>*.faces</url-pattern>
</servlet-mapping>
			

Estas selecciones le dirán al contenedor Servlet que reenvíe todas las URLs que terminen en .faces al procesador del ciclo de vida de JavaServer Faces.

Durante la ejecución, la librería de intergración Struts-Faces personalizará ese ciclo de vida (utilizando puntos de extensión estándar proporcionados por JavaServer Faces) así JavaServer Faces procesará todos eventos de usuario orientados al interface (como expandir o contraer un nodo en un árbol de control), pero los envíos de formularios serán reenviados al procesador de peticiones de Struts, que realizará las tareas habituales de Struts, como realizar validaciones del lado del servidor, invocar la acción correcta, y navegar a la página adecuada.

Empezar a Probar

No se debe modificar ninguno de los beans o acciones, por eso podemos continuar y simplemente probar si está página tiene una operación correcta. Cuando esta págia funcione, modifique la siguiente. O simplemente migre y despliegue sólo las páginas más importantes, si no tiene tiempo de hacerlas todas a la vez.

Conclusión

Como ha visto en este sencillo ejemplo, aprovecharse de las ventajas de las capacidades de los componentes de JavaServer Faces mientras mantiene su inversión en la capa del modelo y en las funcionalidades de la lógica de negocio es bastante sencillo. En una aplicación integrada JSF-Struts, los componentes JSP manejan la orientación vistual de la petición HTTP; por ejemplo pulsar un control de árbol para expandir su contenido; mientras los eventos de transaciones de negocio van através del ciclo estándar de procesamiento de peticiones de Struts.

En esta aplicación modificada, no estámos utilizando las capacidades de control proporcionadas por JavaServer Faces, ya que continuamos utilizando las facilidades de Struts. También es técnicamente posible migrar el procesamiento interno desde una arquitectura basada en Struts a otra basada en JavaServer Faces; y es una estrategia razonable si quiere limitar el número de marcos de trabajo presentes en su aplicación. A pesar de todo, como transición será más sencillo si migra primero las páginas de la capa 'Vista", como hemos realizado en este artículo.

Próximos Pasos

Oracle JDeveloper abraza marcos de trabajo y herrammientas de código abierto, proporciona características internas para Struts, Ant, JUnit, y CVS. Dicha integración permite a los desarrolladores utilizar estas herramientas de código abierto para perfilar sus procesos de desarrollo. Por ejemplo, Oracle JDeveloper proporciona un modelador de flujo de páginas para Struts; una aproximación visual que simplifica el desarrollo del flujo de la aplicación. Los desarrolladores modelan el flujo de páginas simplemente arrastrando y soltando componentes Struts en un diagrama que automáticamente se sincroniza con el código fuente del fichero struts-config.xml. Otro ejemplo, Oracle ADF usa un controlador Struts para menejar el flujo de aplicaciones Web.

Recursos adicionales (en Inglés):

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP