Blog2j
 
Cerca con Google
Ricerca personalizzata
 
Chiamate ajax verso bean di Spring con Dwr

Dopo aver visto come gestire gli oggetti di business di una applicazione con spring vediamo adesso come richiamare da codice javascript un metodo di uno di questi oggetti. Per ottenere questo risultato usiamo dwr, un framework java che crea dinamicamente oggetti javascript che permettono di interagire con oggetti java tramite chiamate ajax.

I sorgenti dell'esempio sono disponibili qui, lo zip contiene un dynamic web project di eclipse in cui devono essere aggiunti i jar di spring, dwr e commons-logging.

Iniziamo un esempio pratico con una semplice classe java:

public class Calcolatrice {

	public double piu(double a, double b) {
		return a + b;
	}

	public double meno(double a, double b) {
		return a - b;
	}

	public double per(double a, double b) {
		return a * b;
	}

	public double diviso(double a, double b) {
		return a / b;
	}
}

Creiamo un bean di spring usando questa classe:

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.directwebremoting.org/schema/spring-dwr
           http://www.directwebremoting.org/schema/spring-dwr-2.0.xsd">
           
	<bean id="calcolatrice" class="it.blog2j.spring.Calcolatrice">
		<dwr:remote javascript="calcolatrice" />
	</bean>
	
</beans>

Il file xml contiene nell'header la dichiarazione necessaria per usare il namespace dwr. All'interno del tag della dichiarazione del bean è presente il tag dwr:remote che indica come mappare il bean in javascript. Grazie a questo tag dwr crea un oggetto javascript calcolatrice utilizzabile all'interno di una pagina. Questo oggetto contiene i metodi corrispondenti a quelli disponibili nella classe java, quando vengono richiamati viene eseguita la chiamata ajax verso il server eseguendo in automatico la conversione dei parametri da javascript a java e del valore di ritorno da java a javascript.

Vediamo meglio con una pagina html di esempio come si può utilizzare l'oggetto javascript creato da dwr:

<html>
<head>
<title>Prova dwr</title>

<script type='text/javascript' src='/SpringDwr/dwr/interface/calcolatrice.js'></script>
<script type='text/javascript' src='/SpringDwr/dwr/engine.js'></script>
<script type='text/javascript' src='/SpringDwr/dwr/util.js'></script>

<script type="text/javascript">
function chiamaServer(metodo) {
	var v1 = DWRUtil.getValue('input1');
	var v2 = DWRUtil.getValue('input2');
	calcolatrice[metodo](v1, v2, function(res) {
		alert(res);
	})
}
</script>

</head>
<body>
<center>
	<input type="text" id="input1"><br>
	<input type="text" id="input2"><br>
	<input type="button" onclick="chiamaServer('piu')" value="+">
	<input type="button" onclick="chiamaServer('meno')" value="-">
	<input type="button" onclick="chiamaServer('per')" value="*">
	<input type="button" onclick="chiamaServer('diviso')" value="/">
</center>
</body>
</html>

Nell'header della pagina sono presenti gli include di 3 file javascript:

  • calcolatrice.js: contiene l'oggetto javascript che permette di effettuare le chiamate ajax verso il server
  • engine.js: codice javascript di base di dwr
  • util.js: metodi di utilità per manipolare il dom della pagina web

L'oggetto creato da dwr è usato nel metodo chiamaServer, invoca tramite una chiamata ajax il metodo passato come parametro e stampa un alert con il risultato dell'operazione. Da notare che la chiamata ajax è asincrona, una volta effettuata la chiamata il metodo non aspetta la risposta dal server. Per elaborare la risposta tutti i metodi generati con dwr prendono un parametro in più rispetto ai corrispondenti metodi java: la function di callback da eseguire. Questa function viene invocata quando il browser ottiene la risposta dal server ed ha come parametro il valore di ritorno del metodo java. Nel nostro caso la function di callback manda semplicemente un alert all'utente con il risultato dell'operazione eseguita sul server.

Le configurazioni di spring e dwr devono essere aggiunte nel file web.xml di definizione della web application. In particolare deve essere impostato un parametro con il nome del file di configurazione di spring, un listener che carica l'application context di spring e una servlet di dwr che crea i file javascript:

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
	xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
	<display-name>SpringDwr</display-name>
	
	<!-- file di spring contenente i bean da usare -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:it/blog2j/spring/factoryConfig.xml
        </param-value>
    </context-param>

	<!-- listener che carica l'application context di spring -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    	
    <!-- servlet di dwr che crea gli oggetti javascript -->
	<servlet>
		<servlet-name>dwr</servlet-name>
		<servlet-class>org.directwebremoting.spring.DwrSpringServlet</servlet-class>
		<init-param>
			<param-name>debug</param-name>
			<param-value>true</param-value>
		</init-param>
	</servlet>
	<servlet-mapping>
		<servlet-name>dwr</servlet-name>
		<url-pattern>/dwr/*</url-pattern>
	</servlet-mapping>
	
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
	</welcome-file-list>
</web-app>

Vediamo adesso un esempio più complesso in cui il metodo java da eseguire sul server prende in ingresso una lista di oggetti:

public class PersonaDAO {

	public void salva(List<Persona> l) throws EtaException {
		for (Persona persona : l) {
			if (persona.getNome() == null || persona.getNome().trim().length() == 0) {
				throw new RuntimeException("Specificare il nome");
			}
			if (persona.getEta() == null) {
				throw new RuntimeException("Specificare l'età");
			}
			if (persona.getEta() < 18) {
				throw new EtaException("Tutte le persone devono avere almeno 18 anni");
			}
		}
	}
}

In questo caso deve essere specificato nel file di configurazione di spring non solo il bean ma anche i converter da utilizzare per trasformare oggetti javascript in java (e viceversa):

<bean id="personaDAO" class="it.blog2j.spring.PersonaDAO">
	<dwr:remote javascript="personaDAO" />
</bean>

<dwr:configuration>
	<dwr:convert class="it.blog2j.spring.Persona" type="bean" />
	<dwr:convert class="java.lang.Exception" type="exception" />
</dwr:configuration>

Dwr mette a disposizione vari converter ed offre la possibilità di implementare converter custom in caso di necessità. In questo esempio abbiamo usato un bean converter per gestire la classe Persona (in pratica vengono convertite tutte le proprietà dell'oggetto ottenute tramite reflection) e un exception converter per gestire le varie eccezioni.

Una pagina html che usa questa classe java con dwr è la seguente:

<html>
<head>
<title>Prova dwr</title>

<script type='text/javascript' src='/SpringDwr/dwr/interface/personaDAO.js'></script>
<script type='text/javascript' src='/SpringDwr/dwr/engine.js'></script>
<script type='text/javascript' src='/SpringDwr/dwr/util.js'></script>

<script type="text/javascript">
dwr.engine.setErrorHandler(function(message, exception) {
	alert("Errore: " + message + " (" + exception.javaClassName + ")");
});

function salva() {
	var l = [];
	var e = DWRUtil.getValue('eta1');
	l.push({
		nome: DWRUtil.getValue('nome1'),
		eta: e != '' ? parseInt(e) : null
	});
	e = DWRUtil.getValue('eta2');
	l.push({
		nome: DWRUtil.getValue('nome2'),
		eta: e != '' ? parseInt(e) : null
	});
	
	personaDAO.salva(l, function() {
		alert('Salvataggio eseguito');
	});
}
</script>

</head>
<body>
<center>
	Nome Persona 1:<input type="text" id="nome1"><br>
	Età Persona 1:<input type="text" id="eta1"><br>
	Nome Persona 2:<input type="text" id="nome2"><br>
	Età Persona 2:<input type="text" id="eta2"><br>
	<input type="button" onclick="salva()" value="Salva">
</center>
</body>
</html>

Il parametro passato al metodo salva è un semplice array javascript contenente due oggetti javascript con gli stessi campi contenuti nell'oggetto java Persona. Le conversioni di questo array e di una eventuale eccezione vengono effettutate automaticamente da dwr.

La function di callback viene invocata solamente se il metodo non lancia una eccezione, in questo esempio abbiamo impostato anche l'errorHandler, ovvero un callback javascript da invocare nel caso di eccezioni.

Dwr si integra facilmente con i vari framework javascript che permettono di creare pagine web interattive "serie" (non come quelle viste in questo esempio). Nel prossimo tutorial vedremo come integrarlo con extjs.

 
News