Le seul objectif de l'API principale d'Ajax (appelée XMLHttpRequest) est d'envoyer des requêtes HTTP pour échanger des données entre le navigateur Web et le serveur. Le code JavaScript exécuté dans une page Web peut utiliser XMLHttpRequest pour soumettre les paramètres de requête à un script côté serveur, tel qu'un servlet ou une page JSP. Le servlet/JSP appelant renverra une réponse contenant des données généralement utilisées pour mettre à jour la vue de l'utilisateur sans actualiser la page entière. Cette approche offre des avantages uniques en termes de performances et de convivialité, car le trafic réseau est réduit et l'interface utilisateur Web est presque aussi utilisable que l'interface graphique du bureau.
Cependant, développer une telle interface utilisateur n'est pas simple, car vous devez mettre en œuvre l'échange, la validation et le traitement des données en utilisant JavaScript côté client et Java (ou un langage équivalent) côté serveur. Cependant, dans de nombreux cas, l’effort supplémentaire nécessaire pour créer une interface basée sur Ajax en vaut la peine, compte tenu des avantages qui en découleront.
Dans cet article, je présenterai l'une des principales méthodes de transfert de données entre clients et serveurs Ajax et comparerai les différences entre le modèle d'application Web traditionnel et le modèle Ajax. En outre, l'article explorera également les techniques de traitement des données côté serveur et côté client.
Tout d’abord, vous apprendrez à utiliser JavaScript pour encoder les paramètres d’un objet de requête côté client. Vous pouvez utiliser ce que l'on appelle le codage URL (le codage par défaut utilisé par les navigateurs Web) ou vous pouvez inclure les paramètres de requête dans le document XML. Le serveur traitera la requête et renverra une réponse dont les données doivent également être codées. Cet article explore JavaScript Object Notation (JSON) et XML, qui sont les principales options de format de données de réponse.
La majeure partie de cet article se concentrera sur les API liées à XML couramment utilisées dans les applications Ajax. Côté client, l'API XML est très limitée mais suffisante. Dans la plupart des cas, toutes les opérations nécessaires peuvent être effectuées à l'aide de XMLHttpRequest. De plus, JavaScript peut être utilisé pour analyser des documents XML et sérialiser des arborescences DOM dans un navigateur Web. Côté serveur, de nombreuses API et frameworks sont disponibles pour traiter les documents XML. Cet article décrit comment effectuer des tâches de base à l'aide de l'API Java standard pour XML, qui prend en charge XML Schema, XPath, DOM et de nombreuses autres normes.
Grâce à cet article, vous pourrez découvrir les meilleures techniques et les dernières API pour l'échange de données dans les applications Ajax. L'exemple de code impliqué est réparti en trois packages : util, model et feed. Les classes du package util fournissent des méthodes d'analyse XML, de validation basée sur un schéma, d'interrogation basée sur XPath, de sérialisation DOM et d'encodage JSON. Le package de modèles contient des exemples de modèles de données qui peuvent être initialisés à partir de documents XML, puis convertis au format JSON. Il existe également un exemple de schéma dans le répertoire modèle qui peut être utilisé pour la validation XML. Les classes du package de flux peuvent être utilisées pour simuler un flux de données, qui récupère des informations via Ajax toutes les 5 secondes pour actualiser la page Web. Cet article explique comment éviter les fuites de mémoire dans votre navigateur Web en mettant fin aux requêtes Ajax en attente et en supprimant l'objet XMLHttpRequest lorsque vous avez fini de l'utiliser.
Des exemples JSP et JavaScript sont inclus dans le répertoire Web. ajaxUtil.js contient des fonctions utilitaires pour envoyer des requêtes Ajax, terminer les requêtes et gérer les erreurs HTTP. Ce fichier fournit également des utilitaires JavaScript pour le codage XML et URL, l'analyse XML et la sérialisation DOM. Le fichier ajaxCtrl.jsp agit comme un contrôleur Ajax, recevant chaque requête Ajax, transmettant les paramètres au modèle de données ou assurant le traitement, puis renvoyant une réponse Ajax. Le reste des fichiers Web sont des exemples qui montrent comment utiliser cette méthode pratique.
Le moyen le plus simplede créer une requête côté client
pour envoyer des données à un serveur Web consiste à coder la requête sous forme de chaîne de requête, qui peut être ajoutée à l'URL ou incluse dans le corps de la requête, selon la méthode HTTP utilisée. Si vous devez envoyer des structures de données complexes, une meilleure solution consiste à encoder les informations dans un document XML. Je couvrirai les deux méthodes dans cette section.
Encodez les paramètres de la requête. Lorsque vous développez des applications Web traditionnelles, vous n'avez pas à vous soucier du codage des données de formulaire, car le navigateur Web le fait automatiquement lorsque l'utilisateur soumet les données. Cependant, dans une application Ajax, vous devez encoder vous-même les paramètres de la requête. JavaScript fournit une fonction escape() très utile, qui remplace tous les caractères ne pouvant pas faire partie de l'URL par %HH (où HH est le code hexadécimal). Par exemple, tous les caractères d'espacement sont remplacés par %20.
L'exemple de code téléchargé fournit une fonction utilitaire, buildQueryString(), qui concatène les paramètres récupérés d'un tableau, en séparant le nom et la valeur de chaque paramètre par = et en plaçant le caractère & entre chaque paire nom-valeur :
function buildQueryString(params) {
var requête = "";
pour (var i = 0; i < params.length; i++) {
requête += (i > 0 ? "&" : "")
+ échappement(params[i].name) + "="
+ escape(params[i].value);
}
renvoyer une requête ;
}
Supposons que vous souhaitiez encoder les paramètres suivants :
var someParams = [
{ nom : "nom", valeur : "John Smith" },
{ nom : "email", valeur : " [email protected] " },
{ nom : "téléphone", valeur : "(123) 456 7890" }
];
Un appel à buildQueryString(someParams) produira des résultats contenant :
name=John%20Smith&[email protected]&phone=%28123%29%20456%207890.
Si vous souhaitez utiliser la méthode GET, vous devez ajouter la requête à l'URL après le caractère ?. Lors de l'utilisation de POST, l'en-tête Content-Type doit être défini sur application/x-www-form-urlencoded via setRequestHeader(), et la chaîne de requête doit être transmise à la méthode send() de XMLHttpRequest, qui enverra la requête HTTP à serveur.
Créez un document XML. Utiliser des chaînes pour créer des éléments à partir de leurs attributs et données constitue le moyen le plus simple de créer des documents XML avec JavaScript. Si vous adoptez cette solution, vous aurez besoin d'une méthode utilitaire pour échapper les caractères &, <, >, " et :
function escapeXML(content) {
si (contenu == non défini)
retour "";
si (!content.length || !content.charAt)
contenu = nouvelle chaîne (contenu);
var résultat = "";
var longueur = contenu.longueur;
pour (var je = 0; je < longueur; i++) {
var ch = content.charAt(i);
interrupteur (ch) {
cas &:
résultat += "&";
casser;
cas < :
résultat += "< ";
casser;
cas > :
résultat += ">" ;
casser;
cas ":
résultat += """;
casser;
cas \:
résultat += "'";
casser;
défaut:
résultat += ch;
}
}
renvoyer le résultat ;
}
Pour simplifier la tâche, certaines méthodes utilitaires supplémentaires sont requises, telles que :
functionattribut(name,value) {
return " " + nom + "="" + escapeXML(value) + """;
}
L'exemple suivant crée un document XML à partir d'un tableau d'objets avec trois propriétés : symbole, actions et prix payé :
function buildPortfolioDoc(stocks) {
var xml = "<portefeuille>";
pour (var i = 0; i < stocks.length; i++) {
var stock = stocks[i];
xml += "<stock" ;
xml += attribut("symbole", stock.symbol);
xml += attribut("actions", stock.shares);
xml += attribut("paidPrice", stock.paidPrice);
xml += "";
}
xml += "< /portfolio>";
renvoyer XML ;
}
Si vous préférez travailler avec DOM, vous pouvez utiliser l'API de votre navigateur Web pour analyser XML et sérialiser l'arborescence DOM. Avec IE, vous pouvez créer un document vide avec un nouvel ActiveXObject("Microsoft.XMLDOM"). Le XML peut ensuite être analysé à partir d'une chaîne ou d'une URL en utilisant respectivement les méthodes loadXML() ou load(). Dans le cas d'IE, chaque nœud possède un attribut appelé xml qui permet d'obtenir une représentation XML du nœud et de tous ses nœuds enfants. Par conséquent, vous pouvez analyser une chaîne XML, modifier l'arborescence DOM, puis sérialiser le DOM en XML.
Les navigateurs Firefox et Netscape vous permettent de créer un document vide en utilisant document.implementation.createDocument(...). Les nœuds DOM peuvent ensuite être créés en utilisant createElement(), createTextNode(), createCDATASection(), etc. Le navigateur Mozilla fournit également deux API nommées DOMParser et XMLSerializer. L'API DOMParser contient les méthodes parseFromStream() et parseFromString(). La classe XMLSerializer possède des méthodes correspondantes pour sérialiser l'arborescence DOM : SerializeToStream() et SerializeToString().
La fonction suivante analyse une chaîne XML et renvoie un document DOM :
function parse(xml) {
var dom;
essayer{
dom = new ActiveXObject("Microsoft.XMLDOM");
dom.async = false;
dom.loadXML(xml);
} attraper (erreur) {
essayer{
var analyseur = new DOMParser();
dom = parser.parseFromString(xml, "text/xml");
supprimer l'analyseur ;
} attraper (erreur2) {
si (débogage)
alert("L'analyse XML n'est pas prise en charge.");
}
}
retourner dom;
}
La deuxième fonction sérialise un nœud DOM et tous ses nœuds enfants, renvoyant le XML sous forme de chaîne :
function serialize(dom) {
var xml = dom.xml;
si (xml == non défini) {
essayer{
var sérialiseur = new XMLSerializer();
xml = serializer.serializeToString(dom);
supprimer le sérialiseur ;
} attraper (erreur) {
si (débogage)
alert("La sérialisation DOM n'est pas prise en charge.");
}
}
renvoyer XML ;
}
Vous pouvez également utiliser XMLHttpRequest comme analyseur ou sérialiseur. Une fois qu'une réponse à une requête Ajax est reçue du serveur, la réponse est automatiquement analysée. La version texte et l'arborescence DOM sont accessibles respectivement via les propriétés ResponseText et ResponseXML de XMLHttpRequest. De plus, l'arborescence DOM est automatiquement sérialisée lorsqu'elle est transmise à la méthode send().
Envoyez une demande. Dans un article précédent, j'ai présenté l'API XMLHttpRequest et une fonction utilitaire, sendHttpRequest(), que vous pouvez trouver dans le fichier ajaxUtil.js dans l'exemple fourni en téléchargement. Cette fonction prend quatre paramètres (méthode HTTP, URL, un tableau de paramètres et un rappel), crée un objet XMLHttpRequest, définit ses propriétés et appelle la méthode send(). Si un paramètre de rappel est fourni, la demande est envoyée de manière asynchrone et la fonction de rappel est appelée après réception de la réponse. Sinon, la requête est envoyée de manière synchrone et vous pouvez gérer la réponse dès le retour de sendHttpRequest().
Comme vous pouvez le constater, vous devez faire des choix importants lorsque vous utilisez XMLHttpRequest
. Quelle méthode HTTP doit être utilisée (GET ou POST) ?
Le format utilisé pour coder les paramètres de la requête (le codage XML et URL a été abordé plus haut dans cet article)
S'il faut effectuer l'appel de manière synchrone (en attente d'une réponse) ou de manière asynchrone (à l'aide d'un rappel). Le format de la réponse, tel que XML, XHTML, HTML ou JavaScript Object Notation (JSON) (abordé plus loin dans cet article). Supposons que vous souhaitiez obtenir des informations sur le cours des actions à partir d'un flux de données et actualiser les informations périodiquement sans intervention de l'utilisateur. Dans ce cas, la requête HTTP doit être envoyée de manière asynchrone afin que l'interface utilisateur ne soit pas bloquée lors de la récupération des informations. Le paramètre de requête est un tableau de symboles pouvant être codés dans l'URL. Le serveur pouvant être surchargé, vous ne souhaitez pas envoyer de documents XML lorsque des requêtes fréquentes sont effectuées. Puisque vous n'êtes intéressé que par le dernier cours de l'action, toutes les demandes précédentes en attente doivent être interrompues :
var ctrlURL = "ajaxCtrl.jsp";
var feedRequest = null;
function sendInfoRequest (symboles, rappel) {
si (feedRequest)
abortRequest(feedRequest);
var params = nouveau tableau();
pour (var i = 0; i < symboles.length; i++)
paramètres[i] = {
nom:"symbole",
valeur:symboles[i]
} ;
feedRequest = sendHttpRequest(
"GET", ctrlURL, paramètres, rappel);
}
Avant d'appeler la méthode abort() de l'objet de requête, la fonction abortRequest() (trouvée dans le fichier ajaxUtil.js) définit la propriété onreadystatechange sur un rappel qui ne fait rien. De plus, il est essentiel de supprimer l'objet de requête pour éviter les fuites de mémoire :
function abortRequest(request) {
fonction ne rien faire() {
}
request.onreadystatechange = doNothing;
request.abort();
supprimer feedRequest ;
}
Considérons un autre cas : lors du transfert de l'intégralité des données utilisateur à sauvegarder dans la base de données, la requête doit être envoyée de manière synchrone car vous ne souhaitez probablement pas que l'utilisateur la modifie pendant que la sauvegarde de ces données est en cours. Dans ce cas, le format XML est préféré car il est souvent plus simple d'encoder le modèle objet dans le document que d'utiliser de nombreux paramètres de chaîne. De plus, les demandes de sauvegarde de données sont peu fréquentes et le serveur gère la charge sans aucun problème. Un document XML peut être codé en tant que paramètre afin que vous puissiez y accéder dans une page JSP en utilisant la syntaxe EL (${param.xml}). Voici la fonction qui envoie les données du modèle encodées dans un document XML :
function sendSaveRequest(xml) {
var params = [ { nom:"xml", valeur:xml } ];
var saveRequest = sendHttpRequest("POST", ctrlURL, params);
si (saveRequest)
supprimer saveRequest ;
}
Si vous devez restaurer le modèle objet, vous pouvez également envoyer une requête de manière synchrone pour récupérer les données du serveur. Dans ce cas, le serveur doit renvoyer une réponse JSON afin que vous puissiez facilement la convertir en arborescence d'objets JavaScript à l'aide de eval(loadRequest.responseText) :
function sendLoadRequest() {
var modèle = nul ;
var loadRequest = sendHttpRequest("GET", ctrlURL);
si (loadRequest) {
modèle = eval(loadRequest.responseText);
supprimer loadRequest ;
}
modèle de retour ;
}
Les deux sections suivantes décrivent les opérations généralement effectuées sur les documents XML sur le serveur et comment répondre aux requêtes Ajax.
Gestion des requêtes côté serveur
Le conteneur Servlet/JSP analyse chaque requête HTTP et crée une instance ServletRequest, qui vous permet d'obtenir les paramètres de la requête via getParameter() / getParameterValues() ou le corps de la requête via getInputStream(). Dans les pages JSP, ces paramètres peuvent également être obtenus en utilisant la syntaxe EL (${param...} et ${paramValues...}). Notez que transmettre getParameter n'est possible que si le client Ajax utilise une fonction utilitaire telle que buildQueryString() pour encoder les données au format application/x-www-form-urlencoded (décrit dans la section précédente de cet article () ou $). {param...} pour obtenir les paramètres de la requête. Si vous transmettez un document XML ou une arborescence DOM à la méthode send() de XMLHttpRequest côté client, vous devez utiliser la méthode getInputStream() de ServletRequest côté serveur.
Validation des données. Une application Web typique effectue de nombreuses opérations de validation des données. La plupart des erreurs possibles sont assez simples, telles que des paramètres de requête manquants, des formats de nombres incorrects, etc. Ces erreurs sont généralement causées par l'oubli par l'utilisateur de saisir une valeur pour un élément de formulaire ou par la fourniture d'une valeur non valide. Les frameworks Web tels que JSF et Oracle ADF Faces sont très efficaces pour gérer ces erreurs utilisateur. Dans les applications Ajax, ces erreurs peuvent être détectées et gérées côté client à l'aide de JavaScript. Par exemple, vous pouvez utiliser isNaN(new Number(value)) pour vérifier qu'une valeur numérique n'est pas valide.
Pour des raisons de sécurité et de fiabilité, les données doivent être revalidées côté serveur et les requêtes XML ne doivent pas être considérées comme correctement formatées. Les schémas XML sont un outil utile pour valider des requêtes complexes côté serveur. L'exemple de code téléchargé inclut une classe appelée XMLUtil qui fournit des méthodes de chargement et d'utilisation de documents de schéma. L'extrait de code suivant montre comment initialiser SchemaFactory :
import javax.xml.*;
importer javax.xml.validation.* ;
...
SchemaFactory statique protégé schemaFactory ;
statique {
schemaFactory = SchemaFactory.newInstance(
XMLConstants.W3C_XML_SCHEMA_NS_URI);
schemaFactory.setErrorHandler(newErrorHandler());
}
La méthode newErrorHandler() renvoie un gestionnaire d'erreurs SAX :
import org.xml.sax.*;
...
public static ErrorHandler newErrorHandler() {
renvoyer un nouveau ErrorHandler() {
avertissement public void (SAXParseException e)
lance SAXException {
Logger.global.warning(e.getMessage());
}
erreur publique void (SAXParseException e)
lance SAXException {
lancez e;
}
public void fatalError (SAXParseException e)
lance SAXException {
lancez e;
}
} ;
}
Vous pouvez utiliser getResourceAsStream() pour rechercher et charger un fichier XSD dans un répertoire ou un JAR spécifié dans CLASSPATH :
public static InputStream getResourceAsStream(String name)
lance IOException {
InputStream in = XMLUtil.class.getResourceAsStream(nom);
si (dans == nul)
lancer une nouvelle FileNotFoundException (nom);
rentrer;
}
Ensuite, utilisez l'instance SchemaFactory pour obtenir l'objet Schema via la méthode newSchema() :
import javax.xml.validation.*;
...
Schéma statique public newSchema (nom de chaîne)
lance IOException, SAXException {
Schéma de schéma ;
InputStream in = getResourceAsStream(nom);
essayer{
schéma = schemaFactory.newSchema(new StreamSource(in));
}enfin{
joindre();
}
schéma de retour ;
}
Vous pouvez également créer un objet Oracle XMLSchema en utilisant :
import oracle.xml.parser.schema.XMLSchema;
importer oracle.xml.parser.schema.XSDBuilder ;
...
public static XMLSchema newOracleSchema (nom de chaîne)
lance IOException, SAXException {
Schéma XMLSchema ;
InputStream in = getResourceAsStream(nom);
essayer{
Générateur XSDBuilder = new XSDBuilder();
schéma = builder.build(new InputSource(in));
} attraper (Exception e){
lancer une nouvelle SAXException(e);
}enfin{
joindre();
}
schéma de retour ;
}
Ensuite, vous devez créer un DocumentBuilderFactory. Si une implémentation JAXP 1.1 est trouvée dans CLASSPATH, la méthode setSchema() définie par JAXP 1.2 peut lever une UnsupportedOperationException, auquel cas l'implémentation JAXP 1.1 doit être remplacée par l'implémentation JAXP 1.2 de Java SE 5.0. Dans ce cas, vous pouvez toujours créer un objet schéma en utilisant newOracleSchema() et le définir via la méthode setAttribute() :
import javax.xml.parsers.*;
importer oracle.xml.jaxp.JXDocumentBuilderFactory ;
...
public statique DocumentBuilderFactory newParserFactory (
String schemaName) renvoie IOException, SAXException {
DocumentBuilderFactory parserFactory
= DocumentBuilderFactory.newInstance();
essayer{
parserFactory.setSchema(newSchema(schemaName));
} catch (UnsupportedOperationException e) {
if (instance parserFactory de JXDocumentBuilderFactory) {
parserFactory.setAttribute(
JXDocumentBuilderFactory.SCHEMA_OBJECT,
newOracleSchema(schemaName));
}
}
retourner parserFactory ;
}
Créez ensuite un objet DocumentBuilder et utilisez-le pour valider et analyser le document XML :
import javax.xml.parsers.*;
...
public statique DocumentBuilder newParser (
DocumentBuilderFactoryparserFactory)
lance ParserConfigurationException {
Analyseur DocumentBuilder = parserFactory.newDocumentBuilder();
parser.setErrorHandler(newErrorHandler());
analyseur de retour ;
} ;
Supposons que vous souhaitiez valider un document XML par rapport à l'exemple de schéma portfolio.xsd :
< xsd:schema xmlns:xsd=" http://www.w3.org/2001/XMLSchema ">
< xsd:element name="portfolio" type ="portfolioType"
< xsd:complexType name="portfolioType">
<xsd:séquence>
< xsd:nom de l'élément="stock"
minOccurs="0" maxOccurs="unbounded">
<xsd:complexType>
< xsd:nom de l'attribut="symbole"
type="xsd:string" use="required"/>
< xsd:nom de l'attribut="partages"
type="xsd:positiveInteger" use="required"/>
< xsd:nom de l'attribut="paidPrice"
type="xsd:décimal" use="required"/>
< /xsd:complexType>
< /xsd:élément>
< /xsd:séquence>
< /xsd:complexType>
< /xsd:schéma>
La méthode parsePortfolioDoc() de la classe DataModel utilise XMLUtil pour valider et analyser les paramètres xml et renvoyer un document DOM :
private static final String SCHEMA_NAME
= "/ajaxapp/model/portfolio.xsd";
parserFactory DocumentBuilderFactory statique privé ;
Document statique privé parsePortfolioDoc (String xml)
lance IOException, SAXException,
ParserConfigurationException {
synchronisé (DataModel.class) {
si (parserFactory == null)
parserFactory = XMLUtil.newParserFactory(SCHEMA_NAME);
}
Analyseur DocumentBuilder = XMLUtil.newParser(parserFactory);
InputSource in = new InputSource(new StringReader(xml));
return parser.parse(in);
}
Maintenant que vous disposez d’une arborescence DOM, vous devez obtenir les données nécessaires pour former les nœuds DOM.
Extrayez les informations requises. Vous pouvez utiliser l'API DOM ou un langage de requête (tel que XQuery ou XPath) pour parcourir l'arborescence DOM. Java fournit une API standard pour XPath, qui sera utilisée ultérieurement. La classe XMLUtil crée une XPathFactory avec une méthode newXPath() :
import javax.xml.xpath.*;
...
XPathFactory statique protégé xpathFactory ;
statique {
xpathFactory = XPathFactory.newInstance();
}
XPath statique public newXPath() {
return xpathFactory.newXPath();
}
Les méthodes suivantes évaluent une expression XPath dans un contexte donné et renvoient la valeur résultante :
import javax.xml.xpath.*;
importer org.w3c.dom.* ;
...
chaîne statique publique evalToString (expression de chaîne,
Contexte de l'objet) lance XPathExpressionException {
return (String) newXPath().evaluate(expression, contexte,
XPathConstants.STRING);
}
public static boolean evalToBoolean (expression de chaîne,
Contexte de l'objet) lance XPathExpressionException {
return ((Boolean) newXPath().evaluate(expression, contexte,
XPathConstants.BOOLEAN)).booleanValue();
}
public statique double evalToNumber (expression de chaîne,
Contexte de l'objet) lance XPathExpressionException {
return ((Double) newXPath().evaluate(expression, contexte,
XPathConstants.NUMBER)).doubleValue();
}
Nœud statique public evalToNode (expression de chaîne,
Contexte de l'objet) lance XPathExpressionException {
return (Node) newXPath().evaluate(expression, contexte,
XPathConstants.NODE);
}
public static NodeList evalToNodeList (expression de chaîne,
Contexte de l'objet) lance XPathExpressionException {
return (NodeList) newXPath().evaluate(expression, contexte,
XPathConstants.NODESET);
}
La méthode setData() du DataModel utilise la méthode du solveur XPath pour extraire les informations du document XML combiné :
public synchronisé void setData(String xml)
lance IOException, SAXException,
ParserConfigurationException,
XPathExpressionException {
essayer{
Liste de stocks de ArrayList
= new ArrayList();
Document doc = parsePortfolioDoc(xml);
NodeList nodeList = XMLUtil.evalToNodeList(
"/portefeuille/actions", doc);
pour (int i = 0; i < nodeList.getLength(); i++) {
Noeud node = nodeList.item(i);
StockBean = nouveau StockBean();
stock.setSymbol(
XMLUtil.evalToString("@symbol", noeud));
stock.setShares(
(int) XMLUtil.evalToNumber("@shares", noeud));
stock.setPaidPrice(
XMLUtil.evalToNumber("@paidPrice", noeud));
stockList.add(stock);
}
this.stockList = stockList;
} attraper (Exception e){
Logger.global.logp(Niveau.SEVERE, "DataModel", "setData",
e.getMessage(), e);
}
}
Une fois les données disponibles dans le modèle de données côté serveur, elles peuvent être traitées selon les exigences de l'application. Ensuite, vous devez répondre à la requête Ajax.
Générer la réponse côté serveur
Renvoyer du HTML en réponse à une requête Ajax est la solution la plus simple car vous pouvez créer le balisage en utilisant la syntaxe JSP et le client Ajax utilise simplement l'élément <div> ou <span>. La propriété innerHTML insère du HTML. quelque part sur la page. Cependant, il est plus efficace de renvoyer les données au client Ajax sans aucun balisage de présentation. Vous pouvez utiliser le format XML ou JSON.
Générez une réponse XML. Java EE offre de nombreuses options pour créer des documents XML : générés via JSP, créés à partir d'une arborescence d'objets via JAXB ou générés à l'aide de javax.xml.transform. Le transformateur dans l'exemple suivant sérialisera une arborescence DOM :
import javax.xml.transform.*;
importer javax.xml.transform.dom.* ;
importer javax.xml.transform.stream.* ;
...
public statique TransformerFactory serializerFctory ;
statique {
serializerFctory = TransformerFactory.newInstance();
}
public static void sérialiser (nœud de nœud, sortie OutputStream)
lance TransformerException {
Sérialiseur de transformateur = serializerFctory.newTransformer();
Propriétés serializerProps = new Properties();
serializerProps.put(OutputKeys.METHOD, "xml");
serializer.setOutputProperties(serializerProps);
Source source = nouveau DOMSource (nœud);
Résultat résultat = new StreamResult(out);
Serializer.transform (source, résultat);
}
Il existe tellement d'options standard et de frameworks de sources de développement pour générer du XML côté serveur que la seule chose que vous avez à faire est de choisir celui qui vous convient. Cependant, sur le client, la situation est très différente puisque XML ne peut être analysé qu'à l'aide du DOM. Certains navigateurs prennent également en charge XPath et XSLT.
Dans les articles Ajax précédents, vous avez appris à générer du XML via JSP, puis à l'analyser sur le client à l'aide de JavaScript et du DOM. Une autre solution consiste à utiliser JSON au lieu de XML comme format de données pour répondre aux requêtes Ajax. Comme mentionné précédemment, une chaîne JSON peut être convertie en une arborescence d'objets JavaScript à l'aide de la fonction eval(). C'est plus simple que d'utiliser JavaScript pour extraire des informations de l'arborescence DOM. Tout ce dont vous avez besoin est une bonne classe utilitaire qui génère du JSON côté serveur.
Encodage JSON. La classe JSONEncoder fournit des méthodes pour coder des littéraux, des objets et des tableaux. Les résultats sont stockés dans java.lang.StringBuilder :
package ajaxapp.util ;
public class JSONEncoder {
buf privé de StringBuilder ;
public JSONEncoder() {
buf = nouveau StringBuilder();
}
...
}
La méthode caractère() code un seul caractère :
public void caractère(char ch) {
interrupteur (ch) {
cas \:
cas \":
cas \ :
buf.append( \ );
buf.append(ch);
casser;
cas :
buf.append( \ );
buf.append( );
casser;
cas
:
buf.append( \ );
buf.append(
);
casser;
cas
:
buf.append( \ );
buf.append(
);
casser;
défaut:
si (ch >= 32 && ch < 128)
buf.append(ch);
autre{
buf.append( \ );
buf.append(u);
pour (int j = 12; j >= 0; j-=4) {
int k = (((int) ch) >> j) & 0x0f;
int c = k < 10 ? + k :a + k - 10;
buf.append((char) c);
}
}
}
}
La méthode string() encode la chaîne entière :
public void string(String str) {
int longueur = str.length();
pour (int i = 0; i < longueur; i++)
caractère(str.charAt(i));
}
La méthode literal() encode le littéral JavaScript :
public void literal (Valeur de l'objet) {
if (valeur instance de String) {
buf.append(");
chaîne((Chaîne) valeur);
buf.append(");
} else if (valeur instance de caractère) {
buf.append(\);
caractère(((Caractère) valeur).charValue());
buf.append(\);
} autre
buf.append(value.toString());
}
La méthode virgule() ajoute un caractère virgule :
private void virgule() {
buf.append(,);
}
La méthode deleteLastComma() supprimera le dernier caractère virgule à la fin du tampon (le cas échéant) :
private void deleteLastComma() {
si (buf. length() > 0)
si (buf.charAt(buf.length()-1) == ,)
buf.deleteCharAt(buf.length()-1);
}
La méthode startObject() ajoute un caractère { pour indiquer le début d'un objet JavaScript :
public void startObject() {
buf.append({);
}
La méthode property() code les propriétés JavaScript :
public void property(String name, Object value) {
buf.append(nom);
buf.append(:);
littéral(valeur);
virgule();
}
La méthode endObject() ajoute un caractère } pour indiquer la fin d'un objet JavaScript :
public void endObject() {
deleteLastComma();
buf.append(});
virgule();
}
La méthode startArray() ajoute un caractère [ pour indiquer le début d'un tableau JavaScript :
public void startArray() {
buf.append([);
}
La méthode element() encode les éléments d'un tableau JavaScript :
public void element(Object value) {
littéral(valeur);
virgule();
}
La méthode endArray() ajoute un caractère ] pour indiquer la fin d'un tableau JavaScript :
public void endArray() {
deleteLastComma();
buf.append(]);
virgule();
}
La méthode toString() renvoie une chaîne JSON :
public String toString() {
deleteLastComma();
return buf.toString();
}
La méthode clear() efface le tampon :
public void clear() {
buf.setLength(0);
}
DataModel utilise la classe JSONEncoder pour encoder les données qu'il conserve :
public synchronisé String getData() {
JSONEncoder json = new JSONEncoder();
json.startArray();
pour (int i = 0; i < stockList.size(); i++) {
stock StockBean = stockList.get(i);
json.startObject();
json.property("symbole", stock.getSymbol());
json.property("actions", stock.getShares());
json.property("paidPrice", stock.getPaidPrice());
json.endObject();
}
json.endArray();
return json.toString();
}
Si des paramètres de requête XML sont fournis, la page ajaxCtrl.jsp définira les données du modèle. Sinon, la page utilisera l'expression EL ${dataModel.data} pour afficher la chaîne JSON renvoyée par getData() :
< %@ taglib prefix="c" uri=" http://java.sun.com/jsp/ jstl /core " %>
...
< jsp:useBean id="dataModel" scope="session"
class="ajaxapp.model.DataModel" />
< c:choose>
...
< c:when test="${!empty param.xml}">
< c:set target="${dataModel}"
propriété="données"
value="${param.xml}" />
< /c:quand>
<c:sinon>
${dataModel.data}
< /c:sinon>
< /c:choisir>
Ce travail n'est pas terminé car le client Ajax doit traiter les données JSON.
Traitement des réponses côté client
Dans une application Web classique, vous générez du contenu côté serveur à l'aide de JSP, de frameworks Web et de bibliothèques de balises. Les applications Ajax sont idéales pour cette situation car les frameworks Web tels que JavaServer Faces et Oracle ADF Faces sont très utiles pour créer des applications Ajax. Cependant, il existe encore des différences significatives entre les applications Ajax et non-Ajax. Lorsque vous utilisez Ajax, vous devez traiter les données côté client et utiliser JavaScript pour générer dynamiquement du contenu afin de fournir les données à l'utilisateur.
Si vous utilisez le format JSON pour la conversion de données, il est très simple de convertir du texte en une arborescence d'objets à l'aide de la fonction eval() fournie par JavaScript. Si vous préférez utiliser XML, vous devez faire beaucoup d'autres choses, mais ce format a aussi ses propres avantages. Par exemple, XML peut être utilisé par de nombreux types de clients, tandis que JSON n'est facile à analyser que dans un environnement JavaScript. De plus, lors de l'utilisation de XML, les erreurs peuvent être trouvées et corrigées plus rapidement, réduisant ainsi le temps de débogage.
Utilisez JavaScript pour accéder à l'arborescence DOM. L'API DOM de JavaScript est très similaire au package org.w3c.dom de Java. La principale différence réside dans l’accès aux propriétés. En JavaScript, vous pouvez accéder directement aux propriétés, tandis que Java traite les propriétés comme privées et vous devez y accéder via les méthodes get et set. Par exemple, vous pouvez obtenir l'élément racine d'un document via dom.documentElement.
Le DOM est une API de bas niveau qui permet d'accéder à la structure du document analysé. Par exemple, vous souhaitez ignorer les commentaires dans la plupart des cas et ne souhaiterez peut-être pas avoir de nœuds de texte adjacents. Prenons l'exemple simple suivant :
var xml = "< element>da< !--comment-->ta&"
+ "< ![CDATA[cdata< /element>" ;
Vous pouvez analyser la chaîne XML ci-dessus à l'aide de la fonction utilitaire présentée précédemment :
var dom = parse(xml);
Vous pouvez trouver le code de la fonction parse() dans ajaxUtil.js ; dans ce cas, la fonction renvoie une arborescence DOM dont l'élément racine contient un nœud de texte, suivi d'un commentaire, d'un autre nœud de texte et d'un nœud de données de caractères. Si vous souhaitez inclure du texte sans commentaires, vous devez parcourir les éléments enfants de l'élément, en concaténant les valeurs des nœuds de données texte et caractère (qui ont respectivement les types 3 et 4) :
var element = dom.documentElement ;
var childNodes = element.childNodes;
var texte = "";
pour (var i = 0; i < childNodes.length; i++)
si (childNodes[i].nodeValue) {
var type = childNodes[i].nodeType;
si (type == 3 || type == 4)
texte += childNodes[i].nodeValue ;
}
Lorsque vous travaillez avec le DOM, vous devez créer un petit ensemble de fonctions utilitaires pour éviter de gérer ces détails de bas niveau.
Utilisez JavaScript pour générer du contenu dynamique. Les navigateurs Web vous permettent d'accéder à la structure DOM d'une page Web via des objets document. Par exemple, vous pouvez utiliser document.getElementById(...) pour retrouver un élément très facilement. Vous pouvez également créer de nouveaux éléments et nœuds de texte pouvant être insérés dans des documents existants. Cependant, il est plus simple de construire du HTML en concaténant des chaînes comme indiqué ci-dessous :
function updateInfo(request) {
var partages = eval(request.responseText);
var table = "<table border=1 cellpadding=5>";
table += "<tr>" ;
table += "< th>Symbole< /th>" ;
table += "< th>Tendance< /th>" ;
table += "< th>Dernier prix< /th>" ;
tableau += "< /tr>" ;
pour (var i = 0; i < parts.length; i++) {
var partage = partages[i];
symbole var = escapeXML (share.symbol)
var tendance = share.trend > 0 ? "+" : "-";
var lastPrice = nouveau Number(share.lastPrice).toFixed(2);
table += "<tr>" ;
table += "< td>" + symbole + "< /td>" ;
tableau += "< td>" + tendance + "< /td>" ;
table += "< td>" + dernierPrice + "< /td>" ;
tableau += "< /tr>" ;
}
table += "< /table>" ;
document.getElementById("table").innerHTML = table;
}
Le HTML généré peut être inséré
dans un élément vide en définissant la propriété innerHTML de l'objet renvoyé par getElementById (), par exemple:
<div id = "table">
< /div>
L'exemple de cet article utilise la fonction UpdateInfo () comme un rappel pour gérer les réponses aux demandes AJAX envoyées au serveur via SendInforequest dans le fichier ajaxlogic.js. Si vous souhaitez mettre à jour des informations toutes les 5 secondes, vous pouvez utiliser la fonction SetInterval () de JavaScript:
var symboles = [...];
setInterval ("SendInforequest (symboles, updateInfo)", 5000);
Une classe appelée DataFeed simule un flux côté serveur. La page Ajaxctrl.jsp appelle la méthode GetData () du flux, renvoyant la réponse en tant que chaîne JSON. Côté client, la fonction UpdateInfo () analyse la chaîne JSON à l'aide d'EVAL (request.ResponSeText), comme indiqué dans l'exemple de code précédent.