Download - Guia_DWR
CURSO DE DIRECT WEB REMOTING (DWR)
1 Guía con Ejemplos
Guía sobre DWR con Ejemplos
DWR (Direct Web Remoting)es una librería Javascript que
permite el uso de Ajax (Asynchronous JavaScript and XML) de
forma mucho más simple (Este artículo asume que se
entiende los conceptos de Ajax, y de Java).
DWR es una librería más orientada a apoyar la integración,
que a apoyar la parte gráfica, de hecho si se buscan Widgets
(objetos gráficos) esta no es la librería, pero por otro lado lo
fuerte de DWR es que permite “publicar” fácilmente
funcionalidad de clases Java para accederlas vía Javascript.
Luego si nuestra funcionalidad o lógica de negocio está en
Java, DWR es una de las mejores opciones para aprovecharla,
ya que usar una clase Java que tenemos en un servidor de
aplicaciones vía Javascript es tan fácil como definir un archivo
de configuración en el servidor.
Ahora si se requiere además darle una interfaz más rica (rich
interface) a los usuarios, es bueno combinar DWR con otras
librerías Ajax como YUI (Yahoo User Interface), JQuery,
Prototype, Scriptaculous, Dojo, o Spry.
Con Ajax se terminan las paginas JSP, o ASP (o deberían
terminarse), porque Ajax solo necesita Javascript y HTML para
la parte de presentación, esto lo explicaremos mejor en otro
artículo, pero por ahora créannos. Y con DWR ni siquiera son
necesarios los Servlets, esto en el sentido de que no se
necesitan desarrollar servlets para implementar la lógica de
negocio, porque DWR si internamente está basado en
Servlets, en otras palabras gracias a DWR no necesitamos
CURSO DE DIRECT WEB REMOTING (DWR)
2 Guía con Ejemplos
implementar nuestros servlets sino solo necesitamos clases
Java (POJO).
Si se conoce la tecnología Axis, que permite publicar clases
Java como Webservices, este es el símil para publicar clases
Java como objetos Ajax (objetos Javascripts), de hecho es
muy fácil publicar con DWR un servicio realizado para Axis.
Incluso las buenas prácticas o blueprints de Axis para publicar
clases como Webservices se aplican totalmente para publicar
clases para Ajax., ya que hay que tener los mismos cuidados
en cuanto a seguridad y manejo de desempeño
(performance).
La definición oficial de DWR es:
DWR permite a Javascript (en un Browser) interactuar con las clases Java
en un Servidor, y ayuda a manipular las páginas Web con los resultados.
Sí, porque otra característica importante de DWR es que
ofrece funcionalidades Javascript que permiten fácilmente
manipular el HTML de la página: como obtener los datos de
un formulario (HTML Form), o de cualquier otro tag HTML, o
setear fácilmente los valores de los tags HTML, además
aporta facilidades para clonar tags, lo que permite por
ejemplo crear nuevas filas (rows) en una tabla (HTML Table),
muy útil para mostrar una consulta. DWR no nos provee
ningún objeto grafico pre-hecho, pero si nos permite la
flexibilidad para hacer cualquier cosa con el HTML.
Bueno basta de conceptos y vamos directo al código.
Esta guía cumple con lo siguiente:
CURSO DE DIRECT WEB REMOTING (DWR)
3 Guía con Ejemplos
Es lo más simple posible, tiene lo justo y necesario para
entender el concepto principal de DWR, y como funciona.
Esta actualizado, otros ejemplos están basados en
versiones anteriores de DWR.
Esta completo, otros ejemplo ponen solo parte del
código.
Usa clases y colecciones de clases (Collection) como
parámetros de entrada y parámetros de salida, que es lo
que típicamente se va a usar en un sistema real, otros
ejemplos usan datos más básicos. De esta forma
también se muestra como se manejan las colecciones y
las clases en Javascript.
CURSO DE DIRECT WEB REMOTING (DWR)
4 Guía con Ejemplos
DWR en 10 Simples Pasos
1. Lo primero es bajar DWR de la dirección mostrada a
continuación: (http://getahead.org/dwr/download), basta
bajar solo la librería (dwr.jar).
2. Luego hay que modificar el archivo “web.xml”, este se
encuentra bajo el directorio “WEB-INF”, ejemplo:
”\dwrEasy\WEB-INF”, se debe incluir las definiciones de los
servlets que atienden los requerimientos DWR-AJAX.
Web.xml:
01.< ?xml version="1.0" encoding="UTF-8"?> 02.< !DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> 03.<web_app> 04. <display_name>dwrEasy</display_name> 05. <servlet> 06. <servlet_name>dwr-invoker</servlet_name> 07. <display_name>DWR Servlet</display_name> 08. <description>Direct Web Remoter Servlet</description> 09. <servlet_class>org.directwebremoting.servlet.DwrServlet </servlet_class> 10. <init_param> 11. <param_name>debug</param_name> 12. <param_value>true</param_value> 13. </init_param> 14. </servlet> 15. <servlet_mapping> 16. <servlet_name>dwr-invoker</servlet_name> 17. <url_pattern>/dwr/*</url_pattern> 18. </servlet_mapping> 19.</web_app>
CURSO DE DIRECT WEB REMOTING (DWR)
5 Guía con Ejemplos
3. A continuación se debe implementar la clase Java que va a
ofrecer los servicios, esta basta que sea un clase Java simple
(POJO), con un constructor sin parámetros, y donde cada
método de la clase es un “potencial” servicio Ajax.
Esta clase va a estar del lado del servidor de aplicaciones
(ejemplo: Tomcat, JBoss, o Websphere) no tiene que ser
necesariamente un servidor J2EE.
La Clase EasyService, se muestra en la Siguiente página:
CURSO DE DIRECT WEB REMOTING (DWR)
6 Guía con Ejemplos
EasyService.java:
01.package com.soaagenda.services; 02. 03.import com.soaagenda.valueobjects.*; 04. 05.public class EasyService { 06.public EasyService() { 07.} 08. 09.public EasyResponse getProducts(EasyParameter parametersX){ 10.EasyResponse responseX= new EasyResponse(); 11. 12. 13.// si parametros vacios devuelve error, error if empty parameters 14.if (parametersX==null || parametersX.getClientID()==null || parametersX.getClientID().length()< =0){ 15.responseX.setErrorCode(10001); 16.responseX.setErrorDescription("Debe indicar ID Cliente. Give us Client ID"); 17.return responseX; 18.} 19. 20.//crea lista productos del cliente, fill the client product list 21.//para ejemplo en duro, for the example fixed data 22.Product[] productsListX= new Product[2]; 23. 24.Product productX= new Product(); 25.productX.setBarCode("0001"); 26.productX.setName("Tarjeta Visa, Visa Credit Card"); 27.productsListX[0]= productX; 28. 29.productX= new Product(); 30.productX.setBarCode("0002"); 31.productX.setName("Tarjeta American Express, American Express Credit Card"); 32.productsListX[1]= productX; 33. 34.//respuesta exitosa, sucessfull response 35.responseX.setErrorCode(0); 36.responseX.setErrorDescription("Consulta Banco Exitosa, Succesfull Bank Query"); 37.responseX.setProducts(productsListX); 38. 39.return responseX; 40.} 41.}
CURSO DE DIRECT WEB REMOTING (DWR)
7 Guía con Ejemplos
Este ejemplo simula una consulta de los productos
bancarios de un cliente como Tarjetas de Crédito (VISA,
Master Card, Dinners, American Express), Cuentas
Corrientes, o Créditos de Consumo, para esto se le pasa
como parámetro un objeto que tiene el ID del cliente, y
el tipo de producto a consultar, el servicio (o método)
devuelve otra clase con el código de error, mensaje de
error, y la lista de productos (un arreglo de clases
producto).
4. También hay que definir las clases de datos (Value Objects)
que va a utilizar el servicio, esta clases deben ser javabeans
(atributo privados, con getters y setters):
EasyParameter.java: define los parámetros de entrada del
servicio.
01.package com.soaagenda.valueobjects; 02. 03.public class EasyParameter { 04.private String clientID; 05.private String productType; 06.public EasyParameter() { 07.} 08. 09.public void setClientID(String clientID) { 10.this.clientID = clientID; 11.} 12. 13.public void setProductType(String productType) { 14.this.productType = productType; 15.} 16. 17.public String getClientID() { 18.return clientID; 19.} 20. 21.public String getProductType() { 22.return productType; 23.} 24.}
CURSO DE DIRECT WEB REMOTING (DWR)
8 Guía con Ejemplos
EasyResponse.java: define la estructura para los resultados
del servicio.
01.package com.soaagenda.valueobjects; 02. 03.public class EasyResponse { 04.private int errorCode; 05.private String errorDescription; 06.private Product[] products; 07. 08.public EasyResponse() { 09.} 10. 11.public void setErrorCode(int errorCode) { 12.this.errorCode = errorCode; 13.} 14. 15.public void setErrorDescription(String errorDescription) { 16.this.errorDescription = errorDescription; 17.} 18. 19.public void setProducts(Product[] products) { 20.this.products = products; 21.} 22. 23.public int getErrorCode() { 24.return errorCode; 25.} 26. 27.public String getErrorDescription() { 28.return errorDescription; 29.} 30. 31.public Product[] getProducts() { 32.return products; 33.} 34.}
CURSO DE DIRECT WEB REMOTING (DWR)
9 Guía con Ejemplos
Product.java: define la estructura de un producto.
01.package com.soaagenda.valueobjects; 02. 03.public class Product { 04.private String barCode; 05.private String name; 06.public Product() { 07.try { 08.jbInit(); 09.} catch (Exception ex) { 10.ex.printStackTrace(); 11.} 12.} 13. 14.private void jbInit() throws Exception { 15.} 16. 17.public void setBarCode(String barCode) { 18.this.barCode = barCode; 19.} 20. 21.public void setName(String name) { 22.this.name = name; 23.} 24. 25.public String getBarCode() { 26.return barCode; 27.} 28. 29.public String getName() { 30.return name; 31.} 32.}
CURSO DE DIRECT WEB REMOTING (DWR)
10 Guía con Ejemplos
5. Vamos a indicarle a DWR que clases vamos a publicar para
Javascript (Ajax), esto se hace en el archivo “dwr.xml”, y
también corresponde a un esquema de seguridad porque
podemos llegar a especificar solo que métodos de una clase
queremos exponer, y que atributos.
Para nuestro ejemplo vamos a publicar toda la clase
servicio (com.soaagenda.services.EasyService), es decir
todos sus métodos, y todas las clases de datos
(com.soaagenda.valueobjects.*).
dwr.xml
01.< ?xml version="1.0" encoding="UTF-8"?> 02.< !DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" "http://getahead.org/dwr/dwr20.dtd"> 03.<dwr> 04.<allow> 05.<!-- define la clase de servicios que se va a publicar mediante DWR --> 06.<!-- defines the service class to share across DWR --> 07.<create creator="new" javascript="EasyService"> 08.<param name="class"value="com.soaagenda.services.EasyService"/> 09.</create> 10.<!-- define las clases de datos que utiliza el servicio --> 11.<!-- defines the data classes to share across DWR --> 12.<convert converter="bean"match="com.soaagenda.valueobjects.*"/> 13.</allow> 14.</dwr>
CURSO DE DIRECT WEB REMOTING (DWR)
11 Guía con Ejemplos
6. Ahora si compilamos las clases, y publicamos nuestro ejemplo
Web (deploy), DWR nos presta una utilidad para probar que
todo anda bien, esta se accede desde un Browser, en el path
“/dwr/”, dentro de nuestro sitio (ejemplo:
http://localhost:8028/dwrEasy/dwr/)
Seleccionado el servicio, nos aparece primero las librerías
javascript necesarias para implementar una página Web,
luego la lista de servicios (métodos de las clase servicio) a los
que tenemos acceso (getProducts).
CURSO DE DIRECT WEB REMOTING (DWR)
12 Guía con Ejemplos
Como no restringimos los métodos de la clase, incluso
nos aparecen los métodos que hereda por ser una clase
Java (como hashCode, getClass).
Si presionamos el botón “Execute”, ejecuta el servicio, y
para el caso de nuestro ejemplo este retorna un error
“Debe indicar ID Cliente”, lo que está bien porque no le
hemos indicado parámetros de entrada, con esto
sabemos que todo anda bien, porque esa respuesta la da
nuestra clase que está en el servidor, es decir,
ejecutamos desde Javascript (Browser) una clase que
está del lado del servidor, eso es Ajax y DWR!!.
CURSO DE DIRECT WEB REMOTING (DWR)
13 Guía con Ejemplos
7. Lo siguiente es crear nuestra página HTML que va a consultar
los resultados y mostrarlos, esta página es sumamente
simple, tiene un formulario (Html Form), en realidad solo
tiene las variables del form, porque ya no es necesario el tag
“<form>” (recuerden que con Ajax la forma de hacer request
al Server cambia, ahora es asíncrona), y tiene una tabla (html
table) para mostrar el resultado.
CURSO DE DIRECT WEB REMOTING (DWR)
14 Guía con Ejemplos
dwrEasyPage.html
01.< !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 02.<html xmlns="http://www.w3.org/1999/xhtml"> 03.<head> 04.<title>Editable Table Demo</title> 05.<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" /> 06.<script type='text/javascript'src='/dwrEasy/dwr/interface/EasyService.js'></script> 07.<script type='text/javascript' src='/dwrEasy/dwr/engine.js'></script> 08.<script type='text/javascript' src='/dwrEasy/dwr/util.js'> </script> 09.<script type="text/javascript" src='dwrEasyJS.js'> </script> 10.</head> 11. 12.<body> 13.<h1>Easy DRW Demo</h1> 14.<h3>Buscar / Search</h3> 15. 16.<table> 17.<tr> 18.<td>ID Cliente / Client ID:</td> 19.<td><input name="formClientID" type="text"id="formClientID" size="15"/></td> 20.</tr> 21.<tr> 22.<td>Tipo Producto / Product Type</td> 23.<td><input name="formProductType" type="text"id="formProductType" size="15"/></td> 24.</tr> 25.<tr> 26.<td colspan="2" align="right"> 27.<input type="button" value="OK"onclick="javascript:submitProductsRequest()"/> 28.</td> 29.</tr> 30.</table> 31. 32.<h3>Productos / Products</h3> 33.<p>Respuesta / Response: 34.<input name="serviceResponse" type="text"id="serviceResponse" size="50"/> 35.</p>
Continúa…
.
CURSO DE DIRECT WEB REMOTING (DWR)
15 Guía con Ejemplos
36. 37.<table border="1"> 38.<thead> 39.<tr> 40.<th>Codigo / BarCode</th> 41.<th>Nombre / Name</th> 42.</tr> 43.</thead> 44.<tbody id="myTable"> 45.<tr id="myPattern" style="display:none"> 46.<td> 47.<span id="codePattern">code example</span></td> 48.<td> 49.<span id="namePattern">name example</span></td> 50.</tr> 51.</tbody> 52.</table> 53.</body> 54.</html>
Si analizamos el código, lo primero es la referencia a las
librerías Javascript (“EasyService.js”, “engine.js”,
“util.js”), estas fueron generadas por DWR, luego
aparece la librería (“dwrEasyJS.js”) que ya es propietaria
(custom), y que debemos construir para realizar la lógica
de interacción (esta redescribe a continuación).
Luego aparecen las variables del formulario a solicitar
(formClientID, formProductType), y el botón que define
la acción de consulta, ejecuta la función Javascript
“javascript: submitProductsRequest()”, esta función es la
que se encuentra definida en la librería (“dwrEasyJS.js),
la cual vamos a tener que construir.
Después viene la tabla que mostrará los datos
(myTable).
CURSO DE DIRECT WEB REMOTING (DWR)
16 Guía con Ejemplos
Podemos ver que hay ciertas características especiales
en el código Html, estas le van a servir a DWR para
encontrar donde obtener, o donde mostrar los datos:
Los “Id” de los tags html le sirven a DWR para manejar
los datos:
Los id “formClientID”, “formProductType” le
permiten encontrar loas parámetros de entrada.
El id “myTable”, le servirá para saber que tabla
limpiar.
El id “myPattern”, le indicará a DWR que filas
(rows) debe “clonar” para mostrar cada registro de
producto de la lista, como es un “patrón” en
principio va oculto (style=”display:none”).
Los id “codePattern”, “namePattern” servirán para
qeu DWR sepa dónde colocar los datos de cada
producto, en este caso se usan tags “<span>”.
Como vemos esta página es solo Html, y Javascript, que
“hermosamente simple”, nada de JSP, ni de ASP, una
página que se puede publicar en cualquier servidor Web.
8. Lo que sigue es la librería Javascript propia.
CURSO DE DIRECT WEB REMOTING (DWR)
17 Guía con Ejemplos
dwrEasyJS.js
01.function submitProductsRequest() { 02.var idX=dwr.util.getValue("formClientID"); 03.var typeX=dwr.util.getValue("formProductType"); 04. 05.var parametersX={clientID:idX,productType:typeX}; 06. 07.EasyService.getProducts(parametersX,showProducts); 08. 09.} 11. 12.function showProducts(responseX) { 13. 14.// borro filas excepto el patron, delete rows except pattern row 15.dwr.util.removeAllRows("myTable", { filter:function(tr) {return (tr.id != "myPattern");}}); 16. 17.if (responseX.errorCode!=0){ 18.alert('Error: '+responseX.errorDescription); 19.return; 20.}; 21.var productsX=responseX.products; 22.var lengthX=productsX.length; 23.var itemProductX; 24. 25.if (lengthX==0){ 26.alert('No hay productos, Cant find products'); 27.return; 28.}; 29. 30.dwr.util.setValue("serviceResponse", responseX.errorDescription); 31. 32.var id="00"; 33.for (var i=0 ; i<lengthx ; i++) { 35.temProductX= productsX[i]; 36.id="00"+i; 37.dwr.util.cloneNode("myPattern", { idSuffix:id }); 38.dwr.util.setValue("codePattern" + id, itemProductX.barCode); 39.dwr.util.setValue("namePattern" + id, itemProductX.name); 40.$("myPattern" + id).style.display = ""; 41.} 42.}
CURSO DE DIRECT WEB REMOTING (DWR)
18 Guía con Ejemplos
9. Esta librería tiene dos funciones: “submitProductsRequest” la
que obtiene los parámetros de entrada y ejecuta el servicio
correspondiente (clase Java EasyService.getProducts() vía
DWR), y la función que muestra los datos (showProducts).
Finalmente hay que subir las páginas (Deploy) en el sitio
Web, quedando el proyecto con la siguiente estructura:
.
Ejecutamos la pagina de prueba “dwrEasyPage” en
nuestro Browser (ejemplo
“http://localhost:8028/dwrEasy/dwrEasyPage.html”),
ponemos un dato en “ID Cliente”, presionamos “OK”, y
listo!, nuestra primera aplicación Ajax-DWR.
10. The End
CURSO DE DIRECT WEB REMOTING (DWR)
19 Guía con Ejemplos
OTROS EJEMPLOS
AJAX es un acrónimo que significa "Asynchonous JavaScript XML". En si, AJAX es una técnica de programación web mediante la cual una página web puede intercambiar información con el servidor en forma asincrónica, de manera tal que la página puede actualizarse sin necesidad de ser recargada. El cliente (browser con la página web) y el servidor mantienen una
comunicación asincrónica y en background. AJAX es netamente JavaScript pero en este capítulo vamos a explicar un framework que permite invocar desde JavaScript (browser, cliente) métodos remotos, en el servidor implementados en Java.
Manipulación de Objetos HTML
Como vemos, DWR resuelve de manera extremadamente
simple la invocación remota de métodos entre la página HTML
(o JSP) y la clase Java que los implementa. Por lo tanto la
mayor complejidad está dada en poder actualizar
dinámicamente el contenido HTML con la información que
llega desde el servidor.
Para esto DWR provee una librería de funciones JavaScript
llamada: util.js. Veremos algunos ejemplos de cómo
actualizar contenido dinámicamente utilizando esta librería.
CURSO DE DIRECT WEB REMOTING (DWR)
20 Guía con Ejemplos
Combos Dependientes
En este ejemplo veremos cómo actualizar el contenido de un
combo dependiendo de lo que el usuario selecciona en otro
combo.
Para esto programamos la siguiente clase que basicamente
proveerá dos métodos:
Collection obtenerArtistas();
Collection obtenerDiscos(String artista);
Es decir: el primer método retornará una Collection de Strings
con los nombres de los artistas "registrados en una base de
datos" y el segundo método, dado un nombre de artista
retornará todos los discos de ese artista que "tenemos
registrados".
Para simplificar, los datos los hardcodearemos en una
Hashtable.
CatalogoCD.java
1: 2:package test; 3:import java.util.*; 4: 5:public class CatalogoCD 6:{ 7: private Hashtable artistas; 8: 9: public CatalogoCD() 10: { 11: artistas=new Hashtable(); 12: _cargarInformacion(); 13: } 14:
CURSO DE DIRECT WEB REMOTING (DWR)
21 Guía con Ejemplos
15: // retorna una Collection de Strins con los 16: // artistas que tenemos registrados 17: public Collection obtenerArtistas() 18: { 19: Vector v=new Vector(); 20: for(Enumeration e=artistas.keys() 21: ;e.hasMoreElements();) 22: { 23: v.add(e.nextElement()); 24: } 25: return v; 26: } 27: 28: // dado un artista, retorna una Collection de 29: // Strings con los titulos de los discos del 30: // artista especificado 31: public Collection obtenerDiscos(String artista) 32: { 33: return (Collection) artistas.get(artista); 34: } 35: 36: // todo harcodeado... 37: private void _cargarInformacion() 38: { 39: Vector v1=new Vector(); 40: v1.add("Please Please Me"); 41: v1.add("Abbey Road"); 42: v1.add("Magical Mistery Tour"); 43: artistas.put("The Beatles",v1); 44: 45: Vector v2=new Vector(); 46: v2.add("Demasiado Ego"); 47: v2.add("La Hija de la Lagrima"); 48: v2.add("Say No More"); 49: v2.add("Kill Gil"); 50: artistas.put("Charly Garcia",v2); 51: 52: // sexo Ibiza Locomia...! 53: Vector v3=new Vector(); 54: v3.add("A Ibiza con Locomia"); 55: v3.add("Abanicos Por Doquier!"); 56: artistas.put("Locomia",v3); 57: } 58:} 59:
CURSO DE DIRECT WEB REMOTING (DWR)
22 Guía con Ejemplos
Para registrar la clase como servicio en DWR tenemos que
agregar las siguientes líneas en el archivo dwr.xml.
1: 2: <create creator="new" javascript="CatalogoCD"> 3: <param name="class" value="test.CatalogoCD"/> 4: </create> 5:
Ahora vamos a:
http://localhost:8080/[YOUR-WEBAPP]/dwr/test/CatalogoCD
Para ver los scripts que debemos incluir en la página JSP.
Y ahora veamos la página JSP:
CURSO DE DIRECT WEB REMOTING (DWR)
23 Guía con Ejemplos
discos.jsp 1:
2:<html>
3: <head>
4: <script
5: type='text/javascript'
6: src='/TestAjax/dwr/interface/CatalogoCD.js'>
7: </script>
8: <script
9: type='text/javascript'
10: src='/TestAjax/dwr/engine.js'>
11: </script>
12: <script
13: type='text/javascript'
14: src='/TestAjax/dwr/util.js'>
15: </script>
16:
17: <script>
18: function obtenerArtistas()
19: {
20: CatalogoCD.obtenerArtistas(function(data){
21: dwr.util.removeAllOptions("cbArtista");
22: dwr.util.addOptions("cbArtista", data);
23: obtenerDiscos();
24: });
25: }
26:
27: function obtenerDiscos()
28: {
29: var art = dwr.util.getValue("cbArtista");
30: CatalogoCD.obtenerDiscos(art,function(data)
31: {
32: dwr.util.removeAllOptions("cbDisco");
33: dwr.util.addOptions("cbDisco", data);
34: });
35: }
36: </script>
37: </head>
38:
39: <body>
40: <input type="button"
41: value="Cargar"
42: onclick="obtenerArtistas()" />
43: <select id="cbArtista"
44: onChange="obtenerDiscos()" />
45: <select id="cbDisco" />
46: </body>
47:</html>
48:
CURSO DE DIRECT WEB REMOTING (DWR)
24 Guía con Ejemplos
Como vemos, la página en si comienza a partir de la línea 39.
Tenemos dos select (combos), uno con id="cbArtista" y el
otro con id="idDisco" y un button.
En el evento onclick del botón invocamos a la función
obtenerArtistas, y en el evento onChange del combo de
artistas invocamos a la funciónobtenerDiscos.
Analicemos entonces la función obtenerArtistas (que se
encuentra a partir de la línea 18).
17: 18: function obtenerArtistas() 19: { 20: CatalogoCD.obtenerArtistas(function(data){ 21: dwr.util.removeAllOptions("cbArtista"); 22: dwr.util.addOptions("cbArtista", data); 23: obtenerDiscos(); 24: }); 25: } 26:
La función invoca a CatalogoCD.obtenerArtistas pasándole
una función callback en la que primero removemos todos los
items del combo y luego seteamos en el combo de artistas la
colección que retorna el método Java. Por último invocamos a
la función obtenerDiscos para cargargar los discos del artistas
que quedó seleccionado.
El código de la función obtenerDiscos está a partir de la línea
27 y lo podemos ver a continuación.
CURSO DE DIRECT WEB REMOTING (DWR)
25 Guía con Ejemplos
26: 27: function obtenerDiscos() 28: { 29: var art = dwr.util.getValue("cbArtista"); 30: CatalogoCD.obtenerDiscos(art,function(data) 31: { 32: dwr.util.removeAllOptions("cbDisco"); 33: dwr.util.addOptions("cbDisco", data); 34: }); 35: } 36:
En esta función tomamos el valor que se encuentra
seleccionado en el combo de artistas y lo asignamos a la
variable art. Luego invocamos a la función
CatalogoCD.obtenerDiscos pasándole art y una función
callback dentro de la cual borramos los items del combo de
discos y seteamos en dicho combo la colección que retorna el
método Java.
El resultado será:
CURSO DE DIRECT WEB REMOTING (DWR)
26 Guía con Ejemplos
AJAX con DWR en NetBeans 6.1
Una de las bibliotecas más fáciles que he visto para
programar en AJAX es el Direct Web Remoting - DWR.
En este capítulo veremos algunas de sus características que
nos ayudará a tener aplicaciones enriquecidas con Ajax. Para
ello usaremos:
1. NetBeans 6.1
2. DWR
Instalando DWR en NetBeans
La biblioteca DWR consta únicamente de un archivo .jar. Este
lo podemos descargar de aquí:
http://getahead.org/dwr/download.
Guardaremos el archivo en una carpeta que será destinada
para las bibliotecas de los proyectos. Yo, en Windows, lo
guardo en d:\proys\lib\DWR, y en Linux lo guardo en
~/proys/lib
Adicionalmente DWR necesita de la biblioteca
commons-logging.
Esta la puedes descargar de aquí:
http://commons.apache.org/downloads/download_logging.cgi
CURSO DE DIRECT WEB REMOTING (DWR)
27 Guía con Ejemplos
Descomprimamos el archivo descargado de commons-logging
en la misma carpeta lib.
Entramos a la opción Tools > Libraries:
Hacemos clic en "New Library" para crear una nueva
biblioteca, y llamaremos DWR.
Clic en OK. Ahora agregamos los archivos .jar
correspondientes.
CURSO DE DIRECT WEB REMOTING (DWR)
28 Guía con Ejemplos
Hacemos clic en Add Jar/Folder y seleccionamos el archivo
commons-logging-1.1.1.jar y dwr.jar
Clic en OK parar cerrar la ventana.
El proyecto Web
Ahora crearemos un aplicación web, que no usará ningún
framework. Será una aplicación totalmente "simple". La
llamaremos DwrSamples.
En las propiedades del proyecto web creado, entramos a sus
propiedades haciendo clic derecho sobre el ícono del proyecto,
y seleccionamos "Properties". En esta ventana seleccionamos
del margen izquierdo la categoría "Libraries". Luego
agregamos la biblioteca DWR haciendo clic en el botón "Add
Library". Después de esto, deberá lucir así:
CURSO DE DIRECT WEB REMOTING (DWR)
29 Guía con Ejemplos
Crearemos una clase a la que llamaremos Calculadora y
estará en el paquete logica. Esta clase, básicamente, tendrá
los métodos que realizarán las operaciones de manera
asíncrona.
package logica; public class Calculadora { public int sumar(int a, int b) { return a + b; } public int restar(int a, int b) { return a - b; } }
CURSO DE DIRECT WEB REMOTING (DWR)
30 Guía con Ejemplos
Ahora, necesitamos que esta clase sea leíble por DWR, por lo
que usaremos anotaciones para "publicar" la clase como
objeto javascript, pero sólo publicaremos el método sumar()
para que sea ajax. Usaremos la anotación de DWR
@RemoteProxy para la clase Calculadora, y @RemoteMethod
para el método sumar(). Deberá lucir así:
package logica; import org.directwebremoting.annotations.RemoteMethod; import org.directwebremoting.annotations.RemoteProxy; @RemoteProxy public class Calculadora { @RemoteMethod public int sumar(int a, int b) { return a + b; } public int restar(int a, int b) { return a - b; } }
Ahora, abrirmos el archivo web.xml (podemos presionar
Shift + Alt + O para abrir el buscador de archivos y escribir
web para que nos seleccione el archivo que estamos
buscando). En la barra superior hacemos clic en el botón
"Servlets" para visualizar los servlets de nuestra aplicación.
Una vez allí, hacemos clic en el botón "Add Servlet".
CURSO DE DIRECT WEB REMOTING (DWR)
31 Guía con Ejemplos
El nuevo servlet que crearemos, le pondremos el nombre
"DWR", la clase del servlet será:
"org.directwebremoting.servlet.DwrServlet", y el patrón URL
será "/dwr/*", es decir, este serlet responderá las peticiones
en la dirección "/dwr/". Deberá lucir esta ventana así:
Hacemos clic en "OK". Luego, agregaremos un parámetro de
inicio. Hacemos clic en el botón "Add.." de la sección
"Initialization Parameter".
El parámetro de inicio lo llamaremos classes, y tendrá una
clase llamada logica.Calculadora.
CURSO DE DIRECT WEB REMOTING (DWR)
32 Guía con Ejemplos
Clic en OK, y deberá lucir así la ventana de los servlets.
CURSO DE DIRECT WEB REMOTING (DWR)
33 Guía con Ejemplos
O si lo prefieres en xml, el archivo web.xml deberá lucir así.
Ahora, crearemos nuestra interfaz. Abrimos el archivo
index.jsp, le pondremos un formulario:
<h2>Calculadora</h2> <form action=""> Valor 1: <input type="text" name="valor1" id="valor1"/><br/> Valor 2: <input type="text" name="valor2" id="valor2"/><br/> <input type="button" value="Sumar" onclick="sumar()"/><br/> Resultado:<div id="suma"></div> </form>
CURSO DE DIRECT WEB REMOTING (DWR)
34 Guía con Ejemplos
Nota que el botón no es un submit, sino un tipo "button".
Tampoco hay que olvidar los atributos id de los tags. Estos
nos ayudarán a identificar un tag en toda la página.
Ahora, necesitamos importar las bibliotecas de DWR. Para
ello, agregamos las siguientes lineas en la cabecera del jsp.
<script type="text/javascript" src="<%=pageContext.getServletContext().getContextPath() %>/dwr/interface/Calculadora.js"></script> <script type="text/javascript" src="<%=pageContext.getServletContext().getContextPath() %>/dwr/engine.js"></script> <script type="text/javascript" src="<%=pageContext.getServletContext().getContextPath() %>/dwr/util.js"></script>
Nota que estos javascript están bajo la carpeta /dwr, que es
el servlet que hemos creado párrafos arriba. Además, hay un
Calculadora.js, que tiene el mismo nombre de nuestra clase
java que hemos creado.
Crearemos la función sumar() que es llamada desde el botón
"sumar" de nuestro formulario:
function sumar(){ var valor1=dwr.util.getValue("valor1"); var valor2=dwr.util.getValue("valor2"); Calculadora.sumar(valor1,valor2,mostrarSuma); }
CURSO DE DIRECT WEB REMOTING (DWR)
35 Guía con Ejemplos
En las dos primeras líneas estamos obteniendo los valores de
los tag "valor1" y "valor2". Este nombre es el nombrado en
los atributos id de los input:text. Por ello es importante que
los ID identifiquen a un único tag en toda la página.
La tercera linea llama al objeto Calculadora. Este objeto es el
que DWR creó como contraparte a nuestra clase java
Calculadora.
Nota que llama al método sumar() y recibe tres parámetros.
Los dos primeros son los mismos parámetros que hemos
declarado en nuestra clase java Calculadora. Pero el tercer
parámetro, que se llama mostrarSuma, es el nombre de una
función en javascript que se encargará de recibir y manejar el
resultado que devuelto por el método sumar() de java. Así es
la convención de DWR. Notar que se le está pasando solo el
nombre, sin paréntesis.
La función javascript mostrarSuma() será la siguiente:
function mostrarSuma(resultado){ dwr.util.setValue("suma",resultado); }
CURSO DE DIRECT WEB REMOTING (DWR)
36 Guía con Ejemplos
Vemos que el resultado devuelto por el método de java
sumar() es el parámetro de esta función javascript. Tomamos
el valor y lo mostramos en el tag que tiene nombre "suma"
(que es un <div>).
El index.jsp completo es el siguiente:
<%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>JSP Page</title> <script type="text/javascript" src="<%=pageContext.getServletContext().getContextPath() %>/dwr/interface/Calculadora.js"></script> <script type="text/javascript" src="<%=pageContext.getServletContext().getContextPath() %>/dwr/engine.js"></script> <script type="text/javascript" src="<%=pageContext.getServletContext().getContextPath() %>/dwr/util.js"></script> <script type="text/javascript"> function sumar(){ var valor1=dwr.util.getValue("valor1"); var valor2=dwr.util.getValue("valor2"); Calculadora.sumar(valor1,valor2,mostrarSuma); } function mostrarSuma(resultado){ dwr.util.setValue("suma",resultado); } </script> </head>
CURSO DE DIRECT WEB REMOTING (DWR)
37 Guía con Ejemplos
<body> <h2>Calculadora</h2> <form action=""> Valor 1: <input type="text" name="valor1" id="valor1"/><br/> Valor 2: <input type="text" name="valor2" id="valor2"/><br/> <input type="button" value="Sumar" onclick="sumar()"/><br/> Resultado:<div id="suma"></div> </form> </body> </html>
Lo corremos y probamos:
¡Magia!
CURSO DE DIRECT WEB REMOTING (DWR)
38 Guía con Ejemplos
Con base de datos
A esta altura verás la simpleza del DWR, y que una aplicación
con base de datos no sería de lo más difícil. Haríamos una
clase que accede la base de datos y lo muestre en la web.
Pero ¿cómo lo mostramos en una tabla?. Aquí mostraremos el
ejemplo:
Crearemos una clase llamada PersonasService y lo
guardaremos en el paquete logica. Esta clase tendrá la
anotación@RemoteProxy pero con un parámetro que
cambiará el nombre del objeto javascript. Es decir, no se
llamaráPersonasService en javascript, sino, se llamará
solamente Personas.
package logica; import org.directwebremoting.annotations.RemoteProxy; @RemoteProxy(name = "Personas") public class PersonasService { }
CURSO DE DIRECT WEB REMOTING (DWR)
39 Guía con Ejemplos
Ahora, crearemos un método llamado getLista() que
devolverá una lista de objetos Persona que tendrá los
registros de la base de datos. Para ello, primero crearemos la
clase beans.Persona.
package beans; import java.util.Date; public class Persona { private int id; private String nombre; private String titulo; private boolean viajeroFrecuente; private Date ultimaActualizacion; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getNombre() { return nombre; } public void setNombre(String nombre) { this.nombre = nombre; }
CURSO DE DIRECT WEB REMOTING (DWR)
40 Guía con Ejemplos
public String getTitulo() { return titulo; } public void setTitulo(String titulo) { this.titulo = titulo; } public Date getUltimaActualizacion() { return ultimaActualizacion; } public void setUltimaActualizacion(Date ultimaActualizacion) { this.ultimaActualizacion = ultimaActualizacion; } public boolean isViajeroFrecuente() { return viajeroFrecuente; } public void setViajeroFrecuente(boolean viajeroFrecuente) { this.viajeroFrecuente = viajeroFrecuente; } }
Por alguna razón, los beans con anotaciones no son
convertidos por DWR a objetos JavaScript. Al menos con esta
versión. He seguido la documentación que indica cómo usar
un bean con @DataTransferObject y nada. Si alguien lo puede
lograr, lo agradeceré un montón.
Pero para poder enviar beans en DWR, crearemos un archivo
llamado dwr.xml y lo guardamos dentro del directorio WEB-
INF (en la misma ubicación del archivo web.xml). En ese
archivo colocaremos lo siguiente:
CURSO DE DIRECT WEB REMOTING (DWR)
41 Guía con Ejemplos
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" "http://directwebremoting.org/schema/dwr20.dtd"> <dwr> <allow> <convert converter="bean" match="beans.Persona"> </convert> </allow> </dwr>
Ahora, volvemos a la clase PersonasService. Hacemos clic
derecho sobre el fondo del código fuente, y seleccionamos
Enterprise Resource > Use Database.
Hacemos clic en el botón "Add"
CURSO DE DIRECT WEB REMOTING (DWR)
42 Guía con Ejemplos
Pondremos como nombre de la referencia, el valor de
travelDS. Además, hacemos clic en el botón "Add" de "Project
Data sources", escribimos el nombre del JNDI jdbc/travel y
seleccionamos de la lista el URL del JDBC referido a la base de
datos travel.
Clic en OK
Clic en OK
CURSO DE DIRECT WEB REMOTING (DWR)
43 Guía con Ejemplos
Clic en OK
Veremos que NetBeans nos ha creado un método llamado
getTravelDS()
private DataSource getTravelDS() throws NamingException { Context c = new InitialContext(); return (DataSource) c.lookup("java:comp/env/travelDS"); }
Pues ya con esto, podemos hacer nuestro manejo a la base
de datos.
Ahora sí, crearemos el método getLista():
CURSO DE DIRECT WEB REMOTING (DWR)
44 Guía con Ejemplos
@RemoteMethod public List<Persona> getLista() { try { DataSource ds = getTravelDS(); Connection conn = ds.getConnection(); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("SELECT * FROM person"); List<Persona> lista = new ArrayList<Persona>(); while (rs.next()) { Persona p = new Persona(); p.setId(rs.getInt("PERSONID")); p.setNombre(rs.getString("NAME")); p.setTitulo(rs.getString("JOBTITLE")); p.setViajeroFrecuente(rs.getBoolean("FREQUENTFLYER")); p.setUltimaActualizacion(rs.getDate("LASTUPDATED")); lista.add(p); } return lista; } catch (SQLException ex) { Logger.getLogger(PersonasService.class.getName()).log(Level.SEVERE, null, ex); } catch (NamingException ex) { Logger.getLogger(PersonasService.class.getName()).log(Level.SEVERE, null, ex); } return null; }
La interfaz web
Ahora, para terminar, lo más importante de una aplicación: la
interfaz web.
Crearemos una tabla donde se colocarán los datos de los
registros obtenidos de la base de datos. Esta tabla será así:
CURSO DE DIRECT WEB REMOTING (DWR)
45 Guía con Ejemplos
<input type="button" onclick="mostrarPersonas()" value="Mostrar personas"/> <input type="button" onclick="limpiarCuadro()" value="Limpiar cuadro"/> <table border="1"> <thead> <tr> <th>ID</th> <th>Nombre</th> <th>Cargo</th> </tr> </thead> <tbody id="personas"> <tr id="pattern" style="display:none"> <td id="id"></td> <td id="nombre"></td> <td id="titulo"></td> </tr> </tbody> </table>
Nota que hay una fila que está invisible
(style="display:none"). Esta será nuestra plantilla llamada
"pattern". Cuando llenemos los datos de la base de datos, lo
que haremos será duplicar esta fila por cada registro.
Vemos también que hay un botón que se llama "Mostrar
Personas" que llama a la función JavaScript
mostrarPersonas(), que es la está aquí:
CURSO DE DIRECT WEB REMOTING (DWR)
46 Guía con Ejemplos
function mostrarPersonas(){ Personas.getLista(listarPersonas); }
Es decir, estamos llamando al método getLista() del objeto
JavaScript Personas que el DWR creó. El método
correspondiente en java no tiene parámetros, pero aquí
estamos pasándole un argumento. Este argumento es el
nombre de la función JavaScript que procesará el resultado
devuelto por el método java. Y la función listarPersonas() está
aquí:
function listarPersonas(data){ limpiarCuadro(); for(var i=0;i<data.length;i++){ fila=data[i]; var $id=fila.id; dwr.util.cloneNode("pattern",{idSuffix:$id}); dwr.util.setValue("id"+$id,fila.id); dwr.util.setValue("nombre"+$id,fila.nombre); dwr.util.setValue("titulo"+$id,fila.titulo); $("pattern"+$id).style.display=""; } }
Lo que primero hace es limpiar el cuadro (luego presento la
función que limpia la tabla). Vemos también que está
recibiendo un parámetro. Como vimos en el ejemplo anterior,
este es el resultado que está devolviendo el objeto java.
Lo que hacemos es recorrer todas filas de la lista, tomamos
una fila y obtenemos el ID de ese objeto.
CURSO DE DIRECT WEB REMOTING (DWR)
47 Guía con Ejemplos
Este ID nos permitirá identificar a esa única fila, porque
sabemos que cada ID de la tabla es única.
Luego clonamos la plantilla:
dwr.util.cloneNode("pattern",{idSuffix:$id});
Al clonarla, hacemos que el ID de la fila creada tenga como
subfijo el ID del objeto java. Es decir, al clonar una fila, toda
la fila queda idéntica al patrón, incluyendo los nombres de los
ID, que según el patrón es "pattern". Si el primero registro de
la tabla tiene el valor "1" en el campo "ID", cuando clone la
fila pondrá como nombre del ID "pattern" y terminará con el
valor "1", o sea, se llamará finalmente "pattern1", y las celdas
"nombre1", "titulo1" . Para la segunda fila será "pattern2" y
las celdas "nombre2","titulo2"... y así sucesivamente.
Ya clonamos la fila pattern, ahora colocaremos los valores a
cada celda. Como ya tenemos el ID unico de cada celda,
simplemente colocaremos el valor en ellas
dwr.util.setValue("id"+$id,fila.id); dwr.util.setValue("nombre"+$id,fila.nombre); dwr.util.setValue("titulo"+$id,fila.titulo);
Pero como también se clonó el estilo - que indica que debe
estar oculto - le indicamos que se muestre.
$("pattern"+$id).style.display="";
...y listo.
A continuación las funciones que borran el contenido de la
tabla:
CURSO DE DIRECT WEB REMOTING (DWR)
48 Guía con Ejemplos
function limpiarCuadro(){ dwr.util.removeAllRows("personas",{filter:filtroBorrado}); } function filtroBorrado(tr){ return (tr.id!="pattern"); }
Existe la función filtroBorrado() para evitar que la fila
"pattern" sea borrada. Si no, ¿cómo hacemos la clonación?
Y el resultado es el ya esperado...
Para terminar...
Revisa la documentación de DWR, ahí encontrarás muchas
cosas muy interesantes.