Direct Web Remoting è una libreria scritta in JAVA che permette di creare applicazioni Web basate su AJAX in modo molto semplice. DWR permette, infatti, di esporre con facilità oggetti Java, in esecuzione su un Web server, come servizi AJAX, quindi richiamabili in modo asincrono.
Per spiegare il funzionamento di questo framework svilupperemo una piccolissima applicazione Web. Utilizzeremo la versione 2.0 di DWR, l'ultima versione stabile attualmente disponibile sul sito ufficiale del progetto.
La nostra applicazione sarà costituita da una semplice pagina contenente un elenco di categorie. Cliccando su una di quest'ultime sarà possibile visualizzare l'elenco dei prodotti appartenenti alla categoria selezionata. In termini pratici, il click sul nome di una categoria, provocherà l'invocazione del framework DWR che chiamerà la classe da noi predisposta per l'acquisizione dei prodotti corrispondenti alla categoria prescelta. La pagina verrà aggiornata senza la necessità che questa venga ricaricata.
Lo sviluppo della classe Java che permette di recuperare i prodotti è molto semplice; abbiamo ipotizzato la presenza di tre categorie: monitor (id 1), portatili (id 2) e stampanti (id 3). Naturalmente è possibile recuperare le informazioni in qualsiasi modo, come ad esempio leggerle dal database o invocare un servizio Web. La classe restituisce una stringa html che contiene l'elenco dei prodotti.
Listato 1. Recupera i prodotti
public class Prodotti {
public String getProdotti(int idMacrocategoria){
StringBuffer htmlCode = new StringBuffer(0);
switch (idMacrocategoria){
case 1:{
htmlCode.append("<div>Prodotto 1 <img src="images/monitor1.jpg"></div>");
htmlCode.append("<div>Prodotto 2 <img src="images/monitor2.jpg"></div>");
htmlCode.append("<div>Prodotto 3 <img src="images/monitor3.jpg"></div>");
break;
}
case 2:{
htmlCode.append("<div>Prodotto 4 <img src="images/portatile1.jpg"></div>");
htmlCode.append("<div>Prodotto 5 <img src="images/portatile2.jpg"></div>");
htmlCode.append("<div>Prodotto 6 <img src="images/portatile3.jpg"></div>");
break;
}
case 3:{
htmlCode.append("<div>Prodotto 7 <img src="images/stampante1.jpg"></div>");
htmlCode.append("<div>Prodotto 8 <img src="images/stampante2.jpg"></div>");
htmlCode.append("<div>Prodotto 9 <img src="images/stampante3.jpg"></div>");
break;
}
}
return htmlCode.toString();
}
}
Per poter utilizzare il framework all'interno della nostra applicazione bisogna seguire i seguenti passi:
- definire la Servlet DWR nel file web.xml;
- creare il file di configurazione dwr.xml;
- importare, nelle librerie dell'applicazione (WEB-INF/lib), il dwr.jar.
Servlet DWR nel file web.xml
Listato 2. definisce la servlet DWR in web.xml
<servlet>
<display-name>DWR Servlet</display-name>
<servlet-name>DWR-Servlet</servlet-name>
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>DWR-Servlet</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
È possibile impostare anche il parametro debug che permette di stabilire il livello di logging del framework. Settando il parametro con il valore true tutte le chiamate al framework vengono stampate sulla console del web server.
File di configurazione dwr.xml
Listato 3. File di configurazione dwr.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC
"-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN"
"http://www.getahead.ltd.uk/dwr/dwr10.dtd">
<dwr>
<allow>
<create creator="new" javascript="Prodotti">
<param name="class" value="luca.santaniello.dwr.Prodotti" />
</create>
</allow>
</dwr>
Nel file dwr.xml, che va inserito nella directory WEB-INF, bisogna elencare le classi che intendiamo esporre. Nel nostro caso abbiamo inserito esclusivamente la classe Prodotti. Così facendo il framework crea un file Prodotti.js che conterrà le funzioni javascript necessarie per l'invocazione del servizio.
Importare il dwr.jar
Dopo aver importato, nelle librerie dell'applicazione (WEB-INF/lib), il file dwr.jar possiamo fare il deploy dell'applicazione sul Web server (ad esempio Tomcat) e caricare la pagina http://localhost:8181/DwrTest/dwr/index.html all'interno della quale possiamo visualizzare l'elenco delle classi che abbiamo esposto e testare le loro funzionalità.
Adesso creiamo la pagina HTML nella quale invocheremo il framework. DWR ci permette di farlo in maniera semplice. Prima di tutto bisogna importare le due librerie javascript: dwr/engine.js che contiene il motore javascript di DWR e dwr/interface/Prodotti.js che permette di richiamare i metodi esposti dalla classe Prodotti. È possibile importare anche la libreria dwr/util.js che contiene funzioni molto utili per gestire l'output della risposta.
Listato 4. Pagina HTML che invocherà il framework
<script type='text/javascript' src='dwr/interface/Prodotti.js'></script>
<script type='text/javascript' src='dwr/engine.js'></script>
<script type='text/javascript' src='dwr/util.js'></script>
<div id="box">
<div id="macrocategorie">
<ul>
<li><a href="#" onclick="Prodotti.getProdotti(1, aggiornaPagina)">Monitor</a></li>
<li><a href="#" onclick="Prodotti.getProdotti(2, aggiornaPagina)">Portatili</a></li>
<li><a href="#" onclick="Prodotti.getProdotti(3, aggiornaPagina)">Stampanti</a></li>
</ul>
</div>
<div id="prodotti"></div>
</div>
Sull'evento onClick
di ciascuna categoria richiamiamo la funzione Prodotti.getProdotti(idCategoria, nomeFunzione)
. Il secondo parametro della funzione è il nome di un'altra funzione javascript che viene richiamata automaticamente dal framework DWR nel momento in cui la richiesta asincrona restituisce il risultato. Tale funzione riceve sotto forma di testo i valori elaborati dalla classe java.
La nostra funzione aggiornaPagina
non fa altro che inserire all'interno del div prodotti la stringa ricevuta in formato HTML.
Listato 5. Inserisce all'interno del div la stringa
function aggiornaPagina(msg){
DWRUtil.setEscapeHtml(false);
DWRUtil.setValue("prodotti", msg);
}
Nell'esempio precedente la classe java ha preso in carica la costruzione di una stringa HTML mentre la funzione aggiornaPagina
ha soltanto inserito tale stringa in un div prestabilito.
Con DWR è possibile anche spostare la costruzione dell'HTML nella funzione javascript. In alcuni casi, infatti, è utile far restituire alla classe java, non una stringa, ma un array di oggetti. In questo caso DWR riesce a trasformare l'array di oggetti java in un array di oggetti javascript facilmente gestibili mediante le classi di utilità di DWR. Per far comprendere meglio il funzionamento, modificheremo l'esempio precedente e faremo in modo che la classe java restituisca un array di oggetti.
Creiamo prima di tutto una classe ProdottoVO che ha soltanto due attributi: nome e immagine.
Listato 6. Setta e restituisce nome e immagine
public class ProdottoVO{
String nome;
String immagine;
public ProdottoVO(){ }
public ProdottoVO(String nome, String immagine){
setImmagine(immagine);
setNome(nome);
}
public String getNome(){
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public String getImmagine() {
return immagine;
}
public void setImmagine(String immagine) {
this.immagine = immagine;
}
}
Un'ulteriore modifica da fare è modificare il file dwr.xml in modo che la classe ProdottoVO venga riconosciuta dal framework e sia ammessa come parametro.
<dwr>
<allow>
<create creator="new" javascript="Prodotti">
<param name="class" value="luca.santaniello.dwr.Prodotti" />
</create>
<convert converter="bean" match="luca.santaniello.dwr.ProdottoVO"/>
</allow>
</dwr>
La funzione javascript aggiornaPagina
riceverà in input un array di oggetti javascript. Mediante un ciclo for
scorriamo i singoli prodotti e costruiamo la stringa HTML. Infine inseriamo nel div tale stringa.
Listato 7. Costruisce la stringa
function aggiornaPagina(messages){
var html = "";
for (var data in messages){
html = "<div>" + messages[data].nome + "<img src="" + messages[data].image + ""></div>" + html;
}
DWRUtil.setEscapeHtml(false);
DWRUtil.setValue("prodotti", html);
}