Traducción por Jesús-E.Conde Núñez

 

El ciclo de recarga de página presenta uno de los mayores obstáculos de usabilidad en el desarrollo de aplicaciones web y es un serio desafío para los desarrolladores de Java™. En estas series, el autor, Philip McCarthy nos introduce en un innovador método para crear operativas aplicaciones dinámicas Web. Ajax ( Asynchronous JavaScript and XML) es una técnica de programación que nos permite combinar tecnologías Java, XML, y JavaScript para aplicaciones Web basadas en Java que rompen con el paradigma de recarga de página.

Ajax, o Asynchronous JavaScript and XML, es un método para el desarrollo de aplicaciones Web que usa código de lado del cliente para intercambiar datos con el servidor Web. Como resultado, las páginas Web son actualizadas dinámicamente sin una completa actualización de la página interrumpiendo el flujo de la interacción. Con Ajax, podemos crear interfaces de usuario de aplicaciones Web más dinámicas que se acercan a la inmediatez y usabilidad de las originales aplicaciones de escritorio.

Ajax no es una tecnología, Es más un patrón (un modo de identificar y describir una técnica de diseño útil). Ajax es nuevo en el sentido que muchos desarrolladores están empezando a darse cuenta de esto, pero todos los componentes que se implementan en una aplicación Ajax existen desde hace varios años. Su gran presencia actual se debe a la emergencia en el 2004 y 2005 de algunas grandes Interfaces de Usuarios de Web dinámicas basadas en la tecnología Ajax, sobre todo aplicaciones de mapas y GMail de Google y sitio Flickr para compartir fotos Online. Estas interfaces de usuarios fueron lo suficientemente avanzadas para ser denominadas "Web 2.0" por algunos desarrolladores, con el resultado de que el interés por las aplicaciones Ajax está subiendo como un cohete.

En estas series, te daré todas las herramientas que necesitas para empezar a desarrollar tus propias aplicaciones usando Ajax. En este primer artículo, explicaremos los conceptos detrás de Ajax y mostraremos los pasos fundamentales para crear una interface Ajax para una aplicación Web basada en Java. Usaré ejemplos de código para mostrar tanto el código Java de lado del servidor y el Java-Script de lado del cliente que hace las aplicaciones Ajax tan dinámicas. Finalmente. Por último, indicaré algunas de las dificultades del método Ajax, así como temás más amplios de funcionalidad y accesibilidad que deberemos considerar cuando creamos aplicaciones Ajax.

 

 

UN CARRITO DE COMPRA MEJOR

Podemos usar Ajax para mejorar aplicaciones Web tradicionales, acelerando la interacción eliminando la carga de páginas. Para demostrar esto, usaré el ejemplo simple de un carrito de compra que es actualizado dinámicamente cuando se le añaden nuevos artículos. Incorporado dentro de una tienda online, este método permitirá a los usuarios continuar navegando y añadiendo artículos a su carrito sin tener que esperar con cada click a que se actualice la página. Mientras que el código en este artículo es específico para el ejemplo del carrito de compra, las técnicas ilustradas pueden ser aplicadas a cualquier aplicación Ajax. Listing 1 muestra el código HTML relevante que usa el ejemplo del carrito de compra. Me referiré a este HTML a lo largo del artículo.

EL CICLO AJAX

Una interacción Ajax empieza con un JavaScript llamado XMLHttpRequest. Como sugiere el nombre, permite a un script de lado del cliente llevar a cabo una petición HTTP, y analizará una respuesta XML del servidor. El primer paso en este Ciclo Ajax es crear una instancia XMLHttpRequest. El método HTTP usado para la petición (GET o POST) y la URL de destino son luego configurados en el objeto XMLHttpRequest.

Ahora, ¿recuerdas que lo primero en el nombre de Ajax es Asincrónico? Cuando envías esta petición HTTP, no quieres que el navegador se quede ahí esperando la respuesta del servidor. En su lugar, quieres que continúe reaccionando a la interacción del usuario con la página y que se ocupe por la respuesta del servidor cuando eventualmente llegue. Para llevar a cabo esto, puedes registrar una función de respuesta con la XMLHttpRequest y luego enviar la XMLHttpRequest asincrónicamente. El control entonces vuelve al navegador, pero la función de respuesta será llamad cuando la respuesta del servidor llegue.

En el servidor Web Java, la petición llega como cualquier otra HttpServletRequest. Después de analizar los parámetros de petición, el servidor invoca la necesaria aplicación lógica, serializa su respuesta en XML, y lo escribe a la HttpServletResponse.

De vuelta en el lado del cliente, la función de respuesta registrada en la HMLHttpRequest es ahora invocada para procesar el documento XML devuelto por el servidor. Finalmente, la interface del usuario es actualizada en respuesta a los datos del servidor, usando JavaScript para manipular el DOM HTML de la página. La figura 1 es un diagrama de secuencia del ciclo Ajax.

Ahora que ya tienes una perspectiva de alto nivel del ciclo Ajax, haré "zoom acercar" para una mirada más detallada para cada paso a lo largo del camino. Vuelve a situarte sobre la Figura 1 si te pierdes ( La secuencia no es enteramente directa debido a la naturaleza asincrónica del método Ajax.)

ENVIAR UNA XMLHttpRequest

Empezaremos por el principio de una secuencia Ajax: creando y enviando una XMLHttpRequest desde el navegador. Desafortunadamente, el método para crear una XMLHttpRequest difiere de navegador a navegador. La función JavaScript en Listing 2 suaviza estas dificultades de dependencia del navegador, detectando el método correcto según el navegador utilizado y devolviendo una XMLHttpRequest preparada para usar. Es mejor pensar en esto como un código estandarizado: simplemente copialo en tu librería JavaScript y usalo cuando necesites una XMLHttpRequest.

Más adelante discutiremos técnicas para manejar navegadores que no admiten XMLHttpRequest. Por ahora, los ejemplos asumen que la función newXMLHttpRequest de Listing 2 siempre devolverá una instancia XMLHttpRequest.

Volviendo al escenario del carrito de compra del ejemplo, quiero invocar una interacción Ajax en cualquier momento que el usuario pulse el botón añadir a carro para un artículo del catálogo. La función del gestor de onclick llamada addToCart( ) es responsable de actualizar el estado del carro a través de una llamada Ajax (ver Listing 1). Como se muestra en Listing 3, lo primero que addToCart( ) necesita hacer es obtener una instancia de XMLHttpRequest llamando a la función newXMLHttpRequest()de Listing 2. Lo siguiente, registra una función de respuesta para recibir la respuesta del servidor (explicaré esto en detalle más tarde; ver Listing 6).

Como la petición modificará el estado en el servidor, usaré un HTTP POST para llevar a cabo la acción. Enviar datos a través de POST requiere tres pasos. Primero, necesita abrir una conexión POST con el recurso del servidor con el que comunico (en este caso un servidor vinculado a la URL del carro). A continuación, coloco un encabezado en la XMLHttpRequest indicando que el contenido de la petición es formulario de datos codificados. Finalmente, envío la petición con el formulario de datos codificado como el cuerpo.

Listing 3 Juntar todos estos pasos.

Y con eso, has visto la primera parte de la configuración del ciclo Ajax ( es decir crear y enviar la petición HTTP desde el cliente). A continuación el código Java servlet usado para gestionar la petición.

GESTIONAR LA PETICIÓN AL SERVIDOR

Manejar una XMLHttpRequest con un servlet es en gran medida lo mismo que manejar una petición HTTP normal desde un navegador. Los datos en forma codificada enviados en el cuerpo de la petición POST pueden ser obtenidos con una llamada HttpServletRequest.getParameter(), Las peticiones Ajax toman parte del mismo modo en la HttpSession como en la petición Web de la aplicación. Esto es útil para el escenario de ejemplo del carrito de compra porque me permite encapsular el estado del carrito de compra del usuario en un JavaBean y persiste ese estado de la sesión entre peticiones.

Listing 4 es parte de un servlet simple que maneja peticiones Ajax para actualizar el carrito de compra. Se recuepra un "Cart Bean" de la sesión del usuario y su estado es actualizado de acuerdo a los parámetros de la petición. El Carro es entonces serializado a XML, y ese XML es escrito a la ServletResponse. Es importante configurar el tipo de contenido de la respuesta para "application/xml", en otro caso la XMLHttpRequest no analizará el contenido de la respuesta en un XML DOM.

Listing 5 muestra un ejemplo del XML producido por el método Cart.toXml( ). Es bastante directo. Observa que el atributo generado en el elemento cart, que es una marca de tiempo producida por System.currentTimeMillis().

Si le echas un vistazo al Cart.java en el código fuente de la aplicación disponible en la sección Descargas, verás que el xml se produce simplemente añadiendo strings juntos. Aunque es suficiente para este ejemplo, es casi el peor modo de producir XML para código Java. Sugeriré algún método mejor en las siguientes entregas de estas series.

Así que de momento ya sabes como responde el CartServlet a una XMLHttpRequest. Lo siguiente es volver al lado del cliente, donde podemos ver como la respuesta XML es usada para actualizar el estado de la página.

RESPUESTA GESTIONADA CON JAVASCRIPT

La propiedad readyState de XMLHttpRequest es un valor numérico que da el status del ciclo de vida de la petición. Cambia de 0 para "no iniciado" hasta 4 para "completo". Cada vez que readyState cambia, el evento readystatechange se enciende y la función gestora vinculada a través de la propiedad onreadystatechange es llamada.

En Listing 3, vimos como la función getReadyStateHandler() fue llamada para crear una función gestora. Esta función gestora fue luego asignada a la propiedad onreadystatechange. getReadyStateHandler() aprovecha el hecho que las funciones son objetos de primera clase en JavaScript. Lo que significa que estas funciones pueden ser parámetros para otras funciones y pueden también crear y devolver otras funciones. Éste es el trabajo de getReadyStateHandler() para devolver una función que comprueba si la XMLHttpRequest ha completado y pasado la respuesta XML a la función gestora especificada por el llamador. Listing 6 es el código para getReadyStateHandler().

SOBRE getReadyStateHandler( )

getReadyStateHandler() es un trozo relativamente complejo de código, especialmente si no es usado para leer JavaScript. La compensación es que incluyendo esta función y tu librería JavaScript, puedes de modo simple manejar respuestas Ajax del servidor sin tener que tratar con las XMLHttpRequest internas. Lo importante es que entiendas como usar getReadyStateHandler()con tu propio código.

En Listing 3, vimos la llamada a getReadyStateHandler()del siguiente modo: handlerFunction = getReadyStateHandler(req, updateCart). La función devuelta por getReadyStateHandler()en este caso comprobará si la XMLHttpRequest en la variable req ha completado y luego llamado una función llamada updateCart con la respuesta XML.

EXTRAER LOS DATOS DEL CARRO

Listing 7 es el código mismo de updateCart( ). La función interroga el documento XML del carrito de compra usando llamadas DOM y actualizando la página Web (Ver Listing 1) para reflejar el nuevo contenido del carro. Centrado aquí en las llamadas usadas para extraer datos del XML DOM. El atributo generado en el elemento cart, una marca de tiempo creado cuando el Carro fue serializado a XML, es comprobado para asegurarse que los nuevos datos del carro son escritos sobre los viejos datos. Las peticiones Ajax son intrínsicamente asincrónicas, de modo que esta comprobación nos protege contra las respuestas del servidor que llegan fuera de secuencia.

Y con eso, el recorrido por el ciclo Ajax está completo, aunque puede que quieres tener la aplicación web ejecutándose y verla en acción (ver la sección Descargas). El ejemplo es muy simple, con multitud de cosas por mejorar. Por ejemplo, he incluido código del lado del cliente para eliminar artículos del carrito, pero no el modo para acceder a esto desde la interface del usuario. Como un buen ejercicio, intenta construir en la aplicación existente código JavaScript para implementar esta funcionalidad.

DESAFÍOS DE USAR AJAX

Como con cualquier tecnología, hay muchas formas de cometer errores con Ajax. Alguno de los problemas que traraté aquí actualmente carecen de soluciones fáciles pero mejorarán cuando Ajax madure. A medida que la comunidad de desarrolladores gane experiencia desarrolllando aplicaciones Ajax, se irán documentando mejores prácticas y directivas.

DISPONIBILIDAD DE XMLHttpRequest

Uno de los principales problemas al que deben enfrentarse los desarrolladores Ajax es como responder cuando XMLHttpRequest no está disponible. Aunque la mayoría de los navegadores modernos admiten XMLHttpRequest, siempre habrá una minoría de usuarios cuyos navegadores no lo hagan, o cuya configuración de seguridad de su navegador impida el uso de XMLHttpRequest. Si estás usando una aplicación Web para ser mostrada en una intranet corporativa, probablemente te podrás permitir el lujo de especificar que navegadores son admitidos y asumir que XMLHttpRequest están siempre disponibles. Si lo estás mostrando en una Web pública, por el contrario, debes ser consciente que presumir que XMLHttpRequest está disponible, potencialmente estás impidiendo a usuarios de viejos navegadores, navegadores de personas con discapacidades, o navegadores simples de uso en dispositivos manuales, por ejemplo, usar tu aplicación.

Por tanto, deberías empeñarte en hacer tu aplicación "con calidad escalable" y mantener la funcionalidad en navegadores que no admitan XMLHttpRequest. En el ejemplo del carrito de compra, el mejor modo para escalar la aplicación sería tener el botón de añadir a carro configurado para un envío normal de formulario, actualizando la página para reflejar el estatus de actualización del carrito. El comportamiento Ajax puede ser añadido a la página a través de JavaScript una vez que la página ha sido cargada, vinculando una función gestora JavaScript para cada botón añadir a carro sólo si XMLHttpRequest está disponbible. Otro método podría ser detectar XMLHttpRequest cuando un usuario se loguea, y luego servirle bien una versión Ajax de la aplicación o bien una versión normal basada en formularios según sea lo apropiado.

TEMAS DE FUNCIONALIDAD

Algunos de los temas de funcionalidad en torno a las aplicaciones Ajax son más generales. Por ejemplo, es importante hacer saber a los usuarios si sus entradas han sido registradas, porque el mecanismo usual de contestación del reloj de arena del cursor y la paulatina aparición en el navegador no se aplican a las XMLHttpRequests. Una técnica es reemplazar los botones Submit con un mensaje del tipo "Ahora actualizando......" de modo que el usuario no pulse repetidamente en los botones mientras espera una respuesta.

Otro tema es que los usuarios puede que no sean capaces de ver que partes de la página que está viendo han sido actualizadas. Puedes aminorar este problema usando distintas técnicas visuales para sutilmente llevar los ojos del usuario a las áreas actualizadas de la página. Otros problemas causados por la actualización de página con Ajax incluyen no ruptura del botón atrás del navegador, y la URL en la barra de direcciones que no reflejan el estado completo de la página, evitando marcadores. Ver la sección Recursos para artículos que especificamente se dirigen a temas de funcionalidad de las aplicaciones Ajax.

CARGA DEL SERVIDOR

Implementar una Interface de Usuario Ajax en lugar de una normal basada en formularios puede aumentar espectacularmente el número de peticiones hechas al servidor. Por ejemplo, una búsqueda Web Google normal da lugar a un uso en el servidor, que tiene lugar cuando el usuario envía el formulario de búsqueda. Sin embargo, Google Suggest, que intenta autocompletar los términos de búsqueda, envía varías peticiones de búsqueda al servidor con lo que el usuario va escribiendo. Cuando desarrollamos una aplicación Ajax, debemos tener en cuenta cuantas peticiones enviaremos al servidor y las consecuencias que la sobrecarga del servidor puede provocar. Podemos mitigar la carga del servidor almacenando peticiones en el cliente y guardando en reserva las respuestas del servidor en el cliente, cuando sea posible. Debemos también intentar diseñar aplicaciones Web Ajax del modo más lógico posible para ser ejecutadas en el cliente, sin necesidad de contactar al servidor.

TRABAJAR CON ASINCRONÍA

Es muy importante entender que no existe garantía que esa XMLHttpRequests se completará en el orden en el cual fue enviada. Desde luego, deberías asumir que no y diseñar tu aplicación con esto en mente. En el ejemplo del carrito de compra, una última actualización de la marca de tiempo fue usada para asegurarnos que los nuevos datos del carro no serán sobrescritos por viejos datos (ver Listing 7). Este método muy rudimentario funciona para el escenario del carrito de compra, pero quizás no para otros. Debes considerar en tiempo de diseño como vas trabajar con respuestas asincrónicas del servidor.

EN CONCLUSIÓN

Deberías ahora tener un buen entendimiento de los principios fundamentales de Ajax y un conocimiento de los entresijos de los componentes de lado del cliente y del servidor que participan en una interacción Ajax. Estos son los bloques de construcción de una aplicación Web Java basada en Ajax. Además, deberías entender algunos de los asuntos de diseño de alto nivel que incorpora el método Ajax. Crear una aplicación Ajax que triunfe requiere un método integral (desde el diseño de la Interface de Usuario al diseño de la arquitectura JavaScript de lado del servidor) pero ahora deberías estar ya preparado con el conocimiento del núcleo Ajax necesario para considerar estos otros aspectos.

Hay buenas noticias si te sientes desanimado por la complejidad de escribir una aplicación Ajax larga usando las técnicas mostradas aquí. Simplemente con marcos como Struts, Spring, e Hibernate han evolucionado para abstraer el desarrollo de aplicaciones Web más allá de los detalles de bajo nivel de los Servlet API y JDBC, apareciendo paquetes de herramientas para hacer más sencillo el desarrollo Ajax. Algunos de estos paquetes se centran exclusivamente en el lado del cliente, proyeyendo con modos sencillos para añadir efectos visuales a tus páginas o acelerando el uso de XMLHttpRequest. Otros van más allá, proveyendo medios para generar automáticamente interfaces Ajax a partir de código de lado del servidor. Estos marcos hacen el trabajo pesado por ti, de modo que puedas acceder a un nivel más alto en el método Ajax. Iremos viendo algunos de ellos en estas series.

La comunidad Ajax se mueve muy rápido, y hay una gran cantidad de información disponible por ahí. Antes de leer la siguiente entrega de este serie, te recomiendo que consultes los artículos listados en la sección Recursos, especialmente si eres nuevo en el desarrollo de Ajax o de lado del cliente. Deberías también tomarte algún tiempo para estudiar el código fuente del ejemplo y pensar sobre modos para mejorarlo.

En el siguiente artículo en estas series, trataré el API XMLHttpRequest con más detalle y sugeriré modos para crear XML fácilmente desde tus JavaBeans. Mostraré también alternativas a XML para la transferencia de datos Ajax, tales como el JSON (JavaScript Object Notation) ,formato ligero de intercambio de datos.

DESCARGAS, RECURSOS Y ENLACES VISITAR PÁGINA ORIGINAL