AJAX usando JQuery y Struts
Publicado por abunaineko en Septiembre 15, 2008
Hace ya un buen rato que no escribo nada por falta de tiempo y exceso de trabajo. Esta vez me toca escribir algo de programación para quienes requieran un ejemplo rápido de cómo comenzar a incluir AJAX en su aplicación.
Decidí usar Struts (1.x) en este ejemplo ya que muchas aplicaciones existentes usan este framework y es muy comun que en el mantenimiento de estas aplicaciones se desee agregar alguna funcionalidad que utilice AJAX. Por otro lado el uso de la biblioteca JQuery es una forma rápida y eficiente de escribir código Javascript, pues nos evitamos de complicaciones innecesarias excribiendo código javascript para tareas comunes, además de que es muy fácil de entender y aprender.
Dejo el ejemplo de AJAX en el siguiente archivo zip que es un proyecto Web para NetBeans 6.1, espero que les sea de utilidad.
Pueden descargar el archivo desde aquí: Ejemplo de Ajax
Este archivo está alojado con el servicio de http://www.sendspace.com
Brevemente explicaré aquí los archivos más importantes, comenzaremos con el archivo de configuración de struts:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd">
<struts-config>
<form-beans>
</form-beans>
<global-exceptions>
</global-exceptions>
<global-forwards>
<forward name="welcome" path="/Welcome.do"/>
</global-forwards>
<action-mappings>
<action path="/Welcome" forward="/welcomeStruts.jsp"/>
<action path="/saludoAjax" type="corp.neko.ajaxdemo.struts.SaludoAjax"/>
</action-mappings>
<controller processorClass="org.apache.struts.tiles.TilesRequestProcessor"/>
<message-resources parameter="corp/neko/ajaxdemo/struts/ApplicationResource"/>
<plug-in className="org.apache.struts.tiles.TilesPlugin" >
<set-property property="definitions-config" value="/WEB-INF/tiles-defs.xml" />
<set-property property="moduleAware" value="true" />
</plug-in>
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property
property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
</plug-in>
</struts-config>
- En la línea 21 definimos un redireccionamiento para la ruta /Welcome.do que va al archivo jsp que utilizaremos como ejemplo.
- En la línea 22 asociamos una acción para la ruta /SaludoAjax.do definida en la clase “corp.neko.ajaxdemo.struts.SaludoAjax”. Es destacable que no estamos definiendo ningún tipo de redireccionamiento, es decir, la acción se va a realizar sin ningún tipo de redirección una vez que esta se ha ejecutado.
Ahora analicemos la clase “corp.neko.ajaxdemo.struts.SaludoAjax” que realizará la acción:
package corp.neko.ajaxdemo.struts;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
/**
*
* @author abunai
*/
public class SaludoAjax extends Action{
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response){
response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");
String nombre = request.getParameter("nombre");
try {
PrintWriter writer = response.getWriter();
writer.print("<xml><respuesta><![CDATA[¡Hola "+nombre+"! Este es un ejemplo de AJAX]]></respuesta></xml>");
writer.flush();
writer.close();
} catch (IOException ex) {
Logger.getLogger(SaludoAjax.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
}
La idea de esta clase es generar una respuesta de tipo xml recibiendo algunos parámetros vía “Request”.
- En la línea 23 y 24 tomamos el objeto de tipo HttpServletResponse que es pasado como parámetro al método execute y lo preparamos para dar una salida de tipo xml. Es muy importante prevenir que los exploradores guarden en caché el recurso, pues nuestro xml cambiará de acuerdo a los parámetros que se envíen en la petición.
- En las líneas 27-30 generamos la salida xml, hay que destacar que en la respuesta estamos poniendo un CDATA, esto para evitar cualquier problema de interepretación de caracteres reservados y especiales que pudiese contener nuestra respuesta.
Finalmente analizaremos nuestra página de prueba welcomeStruts.jsp:
<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean" %>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html" %>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic" %>
<html:html locale="true">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><bean:message key="welcome.title"/></title>
<script type="text/javascript" src="js/jquery-1.2.6.js"></script>
<script type="text/javascript">
$(function(){
$("#usuario").blur(validaUsuario);
});
function validaUsuario(){
var name = $("#usuario").val();
$.get("/AjaxExample/saludoAjax.do", { nombre: name },
preparaRespuesta
);
}
function preparaRespuesta(data){
var respuesta = $(data).find("respuesta").text();
$("#respuesta").hide();
$("#respuesta").empty();
$("#respuesta").append(respuesta);
$("#respuesta").show("slow");
}
</script>
<html:base/>
</head>
<body style="background-color: white">
<logic:notPresent name="org.apache.struts.action.MESSAGE" scope="application">
<div style="color: red">
ERROR: Application resources not loaded -- check servlet container
logs for error messages.
</div>
</logic:notPresent>
<h3><bean:message key="welcome.heading"/></h3>
<p><bean:message key="welcome.message"/></p>
<input name="usuario" id="usuario" type="text">
<div id="respuesta"></div>
</body>
</html:html>
- En las líneas 14-16 declaramos una función anónima cuyo contenido se ejecutará antes de cargar la página, es decir este es el lugar indicado para escribir toda la funcionalidad requerida por el documento antes de comenzar a interactuar con él.
- En la línea 15 destacan dos cosas, la primera es la forma de hacer referencia a un componente de la página utilizando el id: “#componenteX”, que en este caso hace referencia al componente de entrada de texto con id “usuario”. La segunda es que se aplica una función al elemento de acuerdo al evento que se especifique, en este caso “blur”.
- En las líneas 18-23 se define la función que se ejecutará en el evento “blur”, en la línea 19 se recupera el valor que contenga el elemento “usuario”. Las líneas 20-22 son la llamada Ajax a /saludoAjax.do, se especifica que la llamada va a contener un parámetro de nombre “nombre” y cuyo valor es el de la variable “name”. Finalmente se especifica un tercer parámetro, el cual es la función que se ejecutará una vez recibida la respuesta de la llamada Ajax.
- En las líneas 25-31 definimos la función que se ejecutará con el resultado de la llamada a /SaludoAjax.do la cual recibe como parámetro una variable “data” que es el xml que generamos en el método action. En la línea 26 obtenemos el valor de “respuesta” utilizando el método “find” de JQuery. En las líneas 27-31 se manipula el elemento div con id “respuesta” para insertar y mostrar el contenido obtenido en 26.
aNGeLuS escribió
Me parece interesante, incluso me causa k investigue un poco más al respecto, solo me quede con una duda que creo es importante: ¿Y el archivo zip que mencionas? ¿Como o de donde lo descargo?
Andres escribió
Muchas Gracias por compartir tus conocimientos. Estaba buscando hace semanas algo similar para
trabajar con ajax y struts para mi proyecto de título.
flavin escribió
Podrias poner un breve ejemplo acá y no solo para descargar
Diego escribió
Buenas antes que nada gracias por esto!, estoy trabajando con struts, y me pidieron que mejore las vistas!!!; por lo que empece a pensar en jquery ya que tiene muchas cosas interesantes!!!, asi que tu ayuda me viene de pelos!!! gracias!!.
abunaineko escribió
Además de Jquery podrías considerar usar Dojo, que está un poco mas completo en cuanto a cuestiones visuales, voy a tratar de ponder un ejemplo similar a este pero usando Dojo.
Luz escribió
Mira el archivo que subiste esta dañado por favor si podrias enviarmelo a mi correo o verificar y montarlo de nuevo, te lo agradeceria muchisimo.
Saludos
abunaineko escribió
Hola Luz!
Verifiqué el link hace unos instantes y el archivo no tiene ningún problema. Verifica la descarga por favor!
Saludos
Lolo escribió
Alguien ha probado el código con I Explorer 6? No funciona si se obtienen varias en el Action; (puede que se deba al parseo del xml).
Lolo escribió
Quiero decir que si obtengo varias respuestas en el action (resultado de una consulta con base de datos) no funciona en I Explorer, y en Firefox si. ¿Alguna sugerencia?
abunaineko escribió
Pues he verificado que el código es usable en los exploradores que mencionas e incluso en safari. la idea de las bibliotecas de javascript como JQuery es la compatibilidad entre exploradores.
Mencionas algo de bases de datos, no se si puedas ser mas concreto, de cualquier modo verifica la codificación de caracteres de tu BD y revisa que pases los resultados como CDATA.
Lolo escribió
Utilizo este mismo ejercicio para hacer un combo anidado, en base de datos tengo una tabla con todas provincias de españa y otra con todas las poblaciones y sus respectivos códigos. A el action le paso el id de provincia tras seleccionarlo en el select, tras lo cual realizo una consulta a base de datos y obtengo las poblaciones pertinentes que almaceno en una lista, que luego recorro:
//obtengo todas las poblaciones en funcion de la provincia
PoblacionBO poblacionBO=new PoblacionBO();
poblaciones=new LinkedList(poblacionBO.findbyProvincia(Integer.parseInt(id)));
Iterator iterator=poblaciones.iterator();
writer.print(“”);
while(iterator.hasNext()){
Poblacion poblacion=(Poblacion)iterator.next();
writer.print(“”+poblacion.getIdPoblacion()+”");
}
writer.print(“”);
log.debug(writer);
writer.flush();
writer.close();
En firefox funciona sin ningun problema, el 2º combo cambia bien pero en explorer parece como si ni siquiera entrara en la funcion del jsp tras pasar por el action.
Funcion del jsp que se encarga del recuperar los datos y crea el combo de las poblaciones:
function carga1(data){
$(“#poblaciones”).empty();
var texto=$(data).find(“poblacion”);
//recorre los elementos del array
jQuery.each(texto,function(i){
$(“#poblaciones”).append(“”+texto[i].childNodes[1].firstChild.nodeValue+”–”+texto[i].firstChild.nodeValue+”</option”);
});
Un saludo
Lolo escribió
Disculpar, vuelvo a escribir el codigo obviando la apertura y cierre de etiquetas por – para que no se omitan.
writer.print(“-xml-”);
while(iterator.hasNext()){
Poblacion poblacion=(Poblacion)iterator.next();
writer.print(“-poblacion–![CDATA["+poblacion.getNombrePoblacion()+"]]–id-”+poblacion.getIdPoblacion()+”-/id–/poblacion-”);
}
writer.print(“-/xml-”);
log.debug(writer);
writer.flush();
writer.close();
funcion del jsp:
function carga1(data){
$(“#poblaciones”).empty();
var texto=$(data).find(“poblacion”);
//recorre los elementos del array
jQuery.each(texto,function(i){
$(“#poblaciones”).append(“-option value=\”"+texto[i].childNodes[1].firstChild.nodeValue+”\”-”+texto[i].childNodes[1].firstChild.nodeValue+”–”+texto[i].firstChild.nodeValue+”-/option-”);
});
}
Gracias