Единственная цель основного API Ajax (так называемого XMLHttpRequest) — отправлять HTTP-запросы для обмена данными между веб-браузером и сервером. Код JavaScript, выполняемый на веб-странице, может использовать XMLHttpRequest для отправки параметров запроса серверному сценарию, например сервлету или странице JSP. Вызывающий сервлет/JSP отправит обратно ответ, содержащий данные, которые обычно используются для обновления представления пользователя без обновления всей страницы. Этот подход предлагает уникальные преимущества с точки зрения производительности и удобства использования, поскольку сетевой трафик снижается, а веб-интерфейс почти так же удобен, как графический интерфейс настольного компьютера.
Однако разработать такой пользовательский интерфейс непросто, поскольку необходимо реализовать обмен, проверку и обработку данных с использованием JavaScript на стороне клиента и Java (или эквивалентного языка) на стороне сервера. Однако во многих случаях дополнительные усилия по созданию интерфейса на основе Ajax того стоят, учитывая те преимущества, которые будут получены.
В этой статье я представлю один из основных методов передачи данных между клиентами и серверами Ajax и сравню различия между традиционной моделью веб-приложений и моделью Ajax. Кроме того, в статье также будут рассмотрены методы обработки данных на стороне сервера и клиента.
Сначала вы научитесь использовать JavaScript для кодирования параметров объекта запроса на стороне клиента. Вы можете использовать так называемую кодировку URL (кодировка по умолчанию, используемая веб-браузерами) или включить параметры запроса в XML-документ. Сервер обработает запрос и вернет ответ, данные которого также необходимо закодировать. В этой статье рассматриваются нотация объектов JavaScript (JSON) и XML, которые являются основными вариантами формата данных ответа.
Большая часть этой статьи будет посвящена API-интерфейсам, связанным с XML, обычно используемым в приложениях Ajax. На стороне клиента XML API очень ограничен, но достаточен. В большинстве случаев все необходимые операции можно выполнить с помощью XMLHttpRequest. Кроме того, JavaScript можно использовать для анализа XML-документов и сериализации деревьев DOM в веб-браузере. На стороне сервера имеется множество API и платформ для обработки XML-документов. В этой статье описывается, как выполнять базовые задачи с помощью стандартного Java API для XML, который поддерживает XML-схему, XPath, DOM и многие другие стандарты.
Из этой статьи вы сможете узнать о лучших методах и новейших API-интерфейсах для обмена данными в приложениях Ajax. Используемый пример кода находится в трех пакетах: util, model и Feed. Классы в пакете util предоставляют методы для анализа XML, проверки на основе схемы, запросов на основе XPath, сериализации DOM и кодирования JSON. Пакет моделей содержит примеры моделей данных, которые можно инициализировать из документов XML, а затем преобразовать в формат JSON. В каталоге модели также есть пример схемы, который можно использовать для проверки XML. Классы в пакете каналов можно использовать для имитации потока данных, который каждые 5 секунд получает информацию через Ajax для обновления веб-страницы. В этой статье объясняется, как избежать утечек памяти в веб-браузере, прекратив ожидающие запросы Ajax и удалив объект XMLHttpRequest, когда вы закончите его использовать.
Примеры JSP и JavaScript включены в веб-каталог. ajaxUtil.js содержит служебные функции для отправки запросов Ajax, завершения запросов и обработки ошибок HTTP. Этот файл также содержит утилиты JavaScript для кодирования XML и URL-адресов, анализа XML и сериализации DOM. Файл ajaxCtrl.jsp действует как контроллер Ajax, получая каждый запрос Ajax, пересылая параметры в модель данных или обеспечивая обработку, а затем возвращая ответ Ajax. Остальные веб-файлы представляют собой примеры, демонстрирующие использование этого практического метода.
Самый простой способсоздать запрос на стороне клиента
для отправки данных на веб-сервер — закодировать запрос в виде строки запроса, которую можно либо добавить к URL-адресу, либо включить в тело запроса, в зависимости от используемого метода HTTP. Если вам нужно отправить сложные структуры данных, лучшим решением будет закодировать информацию в XML-документе. В этом разделе я расскажу об обоих методах.
Кодировать параметры запроса. При разработке традиционных веб-приложений вам не нужно беспокоиться о кодировании данных формы, поскольку веб-браузер делает это автоматически, когда пользователь отправляет данные. Однако в Ajax-приложении параметры запроса необходимо кодировать самостоятельно. JavaScript предоставляет очень полезную функцию escape(), которая заменяет любые символы, которые не могут быть частью URL-адреса, на %HH (где HH — шестнадцатеричный код). Например, любые пробельные символы заменяются на %20.
Загруженный пример кода предоставляет служебную функцию buildQueryString(), которая объединяет параметры, полученные из массива, разделяя имя и значение каждого параметра знаком = и помещая символ & между каждой парой имя-значение:
function buildQueryString(params) {
вар запрос = "";
for (var я = 0; я
+ escape(params[i].name) + "="
+ escape(params[i].value);
}
обратный запрос;
}
Предположим, вы хотите закодировать следующие параметры:
var someParams = [
{ name: "name", value: "Джон Смит" },
{имя: "электронная почта", значение: " [email protected] " },
{ name:"phone", value: "(123) 456 7890" }
];
Вызов buildQueryString(someParams) приведет к получению результатов, содержащих:
name=John%[email protected]&phone=%28123%29%20456%207890;
Если вы хотите использовать метод GET, вам необходимо добавить запрос к URL-адресу после символа? При использовании POST заголовку Content-Type должно быть присвоено значение application/x-www-form-urlencoded с помощью setRequestHeader(), а строка запроса должна быть передана в метод send() XMLHttpRequest, который отправит HTTP-запрос на сервер.
Создайте XML-документ. Использование строк для создания элементов из их атрибутов и данных — это самый простой способ создания XML-документов с помощью JavaScript. Если вы примете это решение, вам понадобится служебный метод для экранирования символов &, <, >, " и:
function escapeXML(content) {
если (содержимое == не определено)
возвращаться "";
if (!content.length || !content.charAt)
содержимое = новая строка (содержимое);
вар результат = "";
длина вар = content.length;
для (вар я = 0; я <длина; я++) {
вар ch = content.charAt(i);
переключатель (ч) {
случай &:
результат += "&";
перерыв;
случай < :
результат += "< ";
перерыв;
случай >:
результат += ">";
перерыв;
случай ":
результат += """;
перерыв;
случай \:
результат += "'";
перерыв;
по умолчанию:
результат += ч;
}
}
вернуть результат;
}
Чтобы упростить задачу, потребуются некоторые дополнительные служебные методы, такие как:
function атрибут(имя, значение) {
return " " + имя + "="" + escapeXML(значение) + """;
}
В следующем примере XML-документ создается из массива объектов с тремя свойствами: символом, акциями и платной ценой:
function buildPortfolioDoc(stocks) {
var xml = "<портфолио>";
for (var i = 0; i
xml += "< акции ";
xml += атрибут("символ", stock.symbol);
xml += атрибут("акции", stock.shares);
xml += атрибут("paidPrice", stock.paidPrice);
xml += "";
}
xml += "";
вернуть XML;
}
Если вы предпочитаете работать с DOM, вы можете использовать API вашего веб-браузера для анализа XML и сериализации дерева DOM. В IE вы можете создать пустой документ с новым ActiveXObject("Microsoft.XMLDOM"). Затем XML можно проанализировать из строки или URL-адреса с помощью методов loadXML() или load() соответственно. В случае IE каждый узел имеет атрибут xml, который позволяет получить XML-представление узла и всех его дочерних узлов. Таким образом, вы можете проанализировать строку XML, изменить дерево DOM, а затем сериализовать DOM обратно в XML.
Браузеры Firefox и Netscape позволяют создавать пустой документ с помощью document.implementation.createDocument(...). Затем узлы DOM можно создавать с помощью createElement(), createTextNode(), createCDATASection() и т. д. Браузер Mozilla также предоставляет два API: DOMParser и XMLSerializer. API DOMParser содержит методы parseFromStream() и parseFromString(). Класс XMLSerializer имеет соответствующие методы для сериализации дерева DOM: SerializeToStream() и SerializeToString().
Следующая функция анализирует строку XML и возвращает документ DOM:
function parse(xml) {
вар дом;
пытаться{
dom = новый ActiveXObject("Microsoft.XMLDOM");
dom.async = ложь;
dom.loadXML(xml);
} поймать (ошибка) {
пытаться{
вар синтаксический анализатор = новый DOMParser();
dom = parser.parseFromString(xml, "text/xml");
удалить парсер;
} поймать (ошибка2) {
если (отладка)
alert("Разбор XML не поддерживается.");
}
}
вернуть дом;
}
Вторая функция сериализует узел DOM и все его дочерние узлы, возвращая XML в виде строки:
functionserialize(dom) {
вар xml = dom.xml;
если (xml == не определено) {
пытаться{
вар сериализатор = новый XMLSerializer();
xml = сериализатор.serializeToString(dom);
удалить сериализатор;
} поймать (ошибка) {
если (отладка)
alert("Сериализация DOM не поддерживается.");
}
}
вернуть XML;
}
Вы также можете использовать XMLHttpRequest в качестве анализатора или сериализатора. После получения ответа на Ajax-запрос от сервера ответ автоматически анализируется. Доступ к текстовой версии и дереву DOM можно получить через свойства responseText и responseXML XMLHttpRequest соответственно. Кроме того, дерево DOM автоматически сериализуется при передаче методу send().
Отправить запрос. В предыдущей статье я представил API XMLHttpRequest и служебную функцию sendHttpRequest(), которую вы можете найти в файле ajaxUtil.js в образце, предоставленном для загрузки. Эта функция принимает четыре параметра (метод HTTP, URL-адрес, массив параметров и обратный вызов), создает объект XMLHttpRequest, устанавливает его свойства и вызывает метод send(). Если указан параметр обратного вызова, запрос отправляется асинхронно, а функция обратного вызова вызывается после получения ответа. В противном случае запрос отправляется синхронно, и вы можете обработать ответ, как только sendHttpRequest() вернется.
Как видите, при использовании XMLHttpRequest необходимо сделать несколько важных выборов
. Какой метод HTTP следует использовать (GET или POST)?
Формат, используемый для кодирования параметров запроса (кодирование XML и URL-адресов обсуждалось ранее в этой статье).
Следует ли выполнять вызов синхронно (ожидая ответа) или асинхронно (с использованием обратного вызова). Формат ответа, например XML, XHTML, HTML или нотация объектов JavaScript (JSON) (обсуждается далее в этой статье). Допустим, вы хотите получить некоторую информацию о ценах на акции из канала данных и периодически обновлять эту информацию без вмешательства пользователя. В этом случае HTTP-запрос должен отправляться асинхронно, чтобы пользовательский интерфейс не блокировался во время получения информации. Параметр запроса представляет собой массив символов, которые могут быть закодированы в URL-адресе. Поскольку сервер может быть перегружен, не следует отправлять XML-документы при частых запросах. Поскольку вас интересуют только последние цены на акции, все невыполненные предыдущие запросы должны быть прекращены:
var ctrlURL = "ajaxCtrl.jsp";
вар FeedRequest = NULL
функция sendInfoRequest (символы, обратный вызов) {
если (фидреквест)
abortRequest (feedRequest);
вар параметры = новый массив ();
for (var я = 0; я < символы.длина; я++)
параметры [я] = {
имя: «символ»,
значение:символы[я]
};
FeedRequest = sendHttpRequest(
«GET», ctrlURL, параметры, обратный вызов);
}
Перед вызовом метода abort() объекта запроса функция abortRequest() (находится в файле ajaxUtil.js) устанавливает для свойства onreadystatechange обратный вызов, который ничего не делает. Кроме того, очень важно удалить объект запроса, чтобы избежать утечек памяти:
function abortRequest(request) {
функция делатьНичего() {
}
request.onreadystatechange = ничего не делать;
запрос.прервать();
удалить запрос подачи;
}
Давайте рассмотрим другой случай: при передаче всех пользовательских данных для сохранения в базе данных запрос должен отправляться синхронно, поскольку вы, вероятно, не хотите, чтобы пользователь модифицировал его во время сохранения этих данных. В этом случае предпочтительным является формат XML, поскольку зачастую проще закодировать объектную модель в документе, чем использовать множество строковых параметров. Кроме того, запросы на сохранение данных происходят нечасто и сервер без проблем справляется с нагрузкой. XML-документ можно закодировать как параметр, чтобы вы могли получить к нему доступ на странице JSP, используя синтаксис EL (${param.xml}). Вот функция, которая отправляет данные модели, закодированные в XML-документе:
function sendSaveRequest(xml) {
var params = [ { name:"xml", value:xml } ];
var saveRequest = sendHttpRequest("POST", ctrlURL, params);
если (сохранить запрос)
удалить saveRequest;
}
Если вам нужно восстановить объектную модель, вы также можете синхронно отправить запрос на получение данных с сервера. В этом случае сервер должен вернуть ответ JSON, чтобы вы могли легко преобразовать его в дерево объектов JavaScript с помощью eval(loadRequest.responseText):
function sendLoadRequest() {
вар модель = ноль;
var loadRequest = sendHttpRequest("GET", ctrlURL);
если (loadRequest) {
модель = eval(loadRequest.responseText);
удалить запрос загрузки;
}
возвратная модель;
}
В следующих двух разделах описаны операции, которые обычно выполняются с XML-документами на сервере, и способы ответа на запросы Ajax.
Обработка запросов на стороне сервера.
Контейнер Servlet/JSP анализирует каждый HTTP-запрос и создает экземпляр ServletRequest, который позволяет получить параметры запроса через getParameter()/getParameterValues() или тело запроса через getInputStream(). На страницах JSP эти параметры также можно получить с помощью синтаксиса EL (${param...} и ${paramValues...}). Обратите внимание, что передача getParameter возможна только в том случае, если Ajax-клиент использует служебную функцию вроде buildQueryString() для кодирования данных в формате application/x-www-form-urlencoded (описанном в предыдущем разделе этой статьи () или $). {param...} для получения параметров запроса. Если вы передаете XML-документ или дерево DOM методу send() XMLHttpRequest на стороне клиента, вы должны использовать метод getInputStream() ServletRequest на стороне сервера.
Проверка данных. Типичное веб-приложение выполняет множество операций проверки данных. Большинство возможных ошибок довольно простые, например, отсутствие параметров запроса, неправильный формат чисел и т. д. Эти ошибки обычно возникают из-за того, что пользователь забывает ввести значение для элемента формы или указывает недопустимое значение. Веб-фреймворки, такие как JSF и Oracle ADF Faces, очень хорошо справляются с такими ошибками пользователей. В приложениях Ajax эти ошибки можно обнаружить и обработать на стороне клиента с помощью JavaScript. Например, вы можете использовать isNaN(new Number(value)) для проверки недопустимости числового значения.
По соображениям безопасности и надежности данные должны быть повторно проверены на стороне сервера, а XML-запросы не следует считать правильно отформатированными. XML-схемы — полезный инструмент для проверки сложных запросов на стороне сервера. Загруженный пример кода включает класс XMLUtil, который предоставляет методы для загрузки и использования документов схемы. В следующем фрагменте кода показано, как инициализировать SchemaFactory:
import javax.xml.*;
импортировать javax.xml.validation.*;
...
защищенная статическая SchemaFactory SchemaFactory;
статический {
SchemaFactory = SchemaFactory.newInstance(
XMLConstants.W3C_XML_SCHEMA_NS_URI);
SchemaFactory.setErrorHandler(newErrorHandler());
}
Метод newErrorHandler() возвращает обработчик ошибок SAX:
import org.xml.sax.*;
...
общественный статический ErrorHandler newErrorHandler() {
вернуть новый ErrorHandler() {
публичное предупреждение о недействительности (SAXParseException e)
выдает SAXException {
Logger.global.warning(e.getMessage());
}
Ошибка публичной недействительности (SAXParseException e)
выдает SAXException {
бросить е;
}
Public void FatalError (SAXParseException e)
выдает SAXException {
бросить е;
}
};
}
Вы можете использовать getResourceAsStream() для поиска и загрузки файла XSD в каталоге или JAR, указанном в CLASSPATH:
public static InputStream getResourceAsStream(String name)
выдает IOException {
InputStream in = XMLUtil.class.getResourceAsStream(name);
если (в == ноль)
выбросить новое FileNotFoundException (имя);
вернуться;
}
Затем используйте экземпляр SchemaFactory для получения объекта Schema с помощью метода newSchema():
import javax.xml.validation.*;
...
общедоступная статическая схема newSchema (имя строки)
выдает IOException, SAXException {
Схема схемы;
InputStream in = getResourceAsStream (имя);
пытаться{
схема = SchemaFactory.newSchema(новый StreamSource(in));
}окончательно{
в.закрыть();
}
схема возврата;
}
Вы также можете создать объект Oracle XMLSchema, используя:
import oracle.xml.parser.schema.XMLSchema;
импортировать oracle.xml.parser.schema.XSDBuilder;
...
общедоступная статическая XMLSchema newOracleSchema (имя строки)
выдает IOException, SAXException {
схема XMLSchema;
InputStream in = getResourceAsStream (имя);
пытаться{
Конструктор XSDBuilder = новый XSDBuilder();
схема = builder.build(новый InputSource(in));
} catch (Исключение e){
выдать новое исключение SAXException(e);
}окончательно{
в.закрыть();
}
схема возврата;
}
Далее вам нужно создать DocumentBuilderFactory. Если в CLASSPATH обнаружена реализация JAXP 1.1, метод setSchema(), определенный в JAXP 1.2, может вызвать исключение UnsupportedOperationException, и в этом случае реализацию JAXP 1.1 необходимо заменить реализацией JAXP 1.2 Java SE 5.0. В этом случае вы все равно можете создать объект схемы с помощью newOracleSchema() и установить его с помощью метода setAttribute():
import javax.xml.parsers.*;
импортировать oracle.xml.jaxp.JXDocumentBuilderFactory;
...
public static DocumentBuilderFactory newParserFactory(
Строка имя_схемы) выдает IOException, SAXException {
DocumentBuilderFactory parserFactory
= DocumentBuilderFactory.newInstance();
пытаться{
parserFactory.setSchema(newSchema(schemaName));
} catch (UnsupportedOperationException e) {
если (parserFactory экземпляр JXDocumentBuilderFactory) {
parserFactory.setAttribute(
JXDocumentBuilderFactory.SCHEMA_OBJECT,
newOracleSchema(имясхемы));
}
}
вернуть parserFactory;
}
Затем создайте объект DocumentBuilder и используйте его для проверки и анализа XML-документа:
import javax.xml.parsers.*;
...
публичный статический DocumentBuilder newParser(
DocumentBuilderFactory parserFactory)
выдает ParserConfigurationException {
Парсер DocumentBuilder = parserFactory.newDocumentBuilder();
parser.setErrorHandler(newErrorHandler());
возвратный парсер;
};
Предположим, вы хотите проверить XML-документ на соответствие примеру схемы портфолио.xsd:
< xsd:schema xmlns:xsd=" http://www.w3.org/2001/XMLSchema ">
< xsd:element name="portfolio" type ="portfolioType "
< xsd:complexType name="portfolioType">
< xsd:element name="stock"
minOccurs="0" maxOccurs="неограниченный">
< xsd:attribute name="symbol"
type="xsd:string" use="required"/>
< xsd:attribute name="shares"
type="xsd:positiveInteger" use="required"/>
< xsd:attribute name="paidPrice"
type="xsd:decimal" use="required"/>
Метод parsePortfolioDoc() класса DataModel использует XMLUtil для проверки и анализа параметров xml и возврата документа DOM:
частная статическая конечная строка SCHEMA_NAME
= "/ajaxapp/model/portfolio.xsd";
частный статический DocumentBuilderFactory parserFactory;
частный статический документ parsePortfolioDoc (String xml)
выдает IOException, SAXException,
ParserConfigurationException {
синхронизировано (DataModel.class) {
если (parserFactory == ноль)
parserFactory = XMLUtil.newParserFactory(SCHEMA_NAME);
}
Анализатор DocumentBuilder = XMLUtil.newParser(parserFactory);
InputSource in = новый InputSource (новый StringReader (xml));
вернуть parser.parse(in);
}
Теперь, когда у вас есть дерево DOM, вам нужно получить данные, необходимые для формирования узлов DOM.
Извлеките необходимую информацию. Для просмотра дерева DOM можно использовать API DOM или язык запросов (например, XQuery или XPath). Java предоставляет стандартный API для XPath, который будет использоваться позже. Класс XMLUtil создает XPathFactory с помощью метода newXPath():
import javax.xml.xpath.*;
...
защищенная статическая XPathFactory xpathFactory;
статический {
xpathFactory = XPathFactory.newInstance();
}
общественный статический XPath newXPath() {
вернуть xpathFactory.newXPath();
}
Следующие методы оценивают выражение XPath в заданном контексте и возвращают результирующее значение:
import javax.xml.xpath.*;
импортировать org.w3c.dom.*;
...
public static String evalToString (строковое выражение,
Контекст объекта) выдает XPathExpressionException {
return (String) newXPath().evaluate(выражение, контекст,
XPathConstants.STRING);
}
public static boolean evalToBoolean (строковое выражение,
Контекст объекта) выдает XPathExpressionException {
return ((Boolean) newXPath().evaluate(выражение, контекст,
XPathConstants.BOOLEAN)).booleanValue();
}
public static double evalToNumber (строковое выражение,
Контекст объекта) выдает XPathExpressionException {
return ((Double) newXPath().evaluate(выражение, контекст,
XPathConstants.NUMBER)).doubleValue();
}
общедоступный статический узел evalToNode (строковое выражение,
Контекст объекта) выдает XPathExpressionException {
return (Node) newXPath().evaluate(выражение, контекст,
XPathConstants.NODE);
}
public static NodeList evalToNodeList (строковое выражение,
Контекст объекта) выдает исключение XPathExpressionException {
return (NodeList) newXPath().evaluate(выражение, контекст,
XPathConstants.NODESET);
}
Метод setData() DataModel использует метод решателя XPath для извлечения информации из объединенного XML-документа:
publicsynced void setData(String xml)
выдает IOException, SAXException,
Исключение ParserConfigurationException,
XPathExpressionException {
пытаться{
МассивСписок акцийСписок
= новый ArrayList();
Документ документа = parsePortfolioDoc(xml);
NodeList nodeList = XMLUtil.evalToNodeList(
"/портфолио/акции", документ);
for (int i = 0; i < nodeList.getLength(); i++) {
Узел node = nodeList.item(i);
StockBean запас = новый StockBean();
шток.setSymbol(
XMLUtil.evalToString("@symbol", node));
stock.setShares(
(int) XMLUtil.evalToNumber("@shares", node));
stock.setPaidPrice(
XMLUtil.evalToNumber("@paidPrice", node));
StockList.add(акции);
}
this.stockList = StockList;
} catch (Исключение e){
Logger.global.logp(Level.SEVERE, "DataModel", "setData",
е.getMessage(), е);
}
}
Как только данные станут доступны в модели данных на стороне сервера, их можно будет обрабатывать в соответствии с требованиями приложения. Затем вы должны ответить на запрос Ajax.
Генерация ответа на стороне сервера.
Возврат HTML в качестве ответа на запрос Ajax — самое простое решение, поскольку вы можете создать разметку с использованием синтаксиса JSP, а клиент Ajax просто использует элемент
Сгенерируйте XML-ответ. Java EE предоставляет множество возможностей для создания XML-документов: созданных с помощью JSP, созданных из дерева объектов с помощью JAXB или созданных с помощью javax.xml.transform. Преобразователь в следующем примере сериализует дерево DOM:
import javax.xml.transform.*;
импортировать javax.xml.transform.dom.*;
импортировать javax.xml.transform.stream.*;
...
общедоступный статический TransformerFactory сериализаторFctory;
статический {
сериализаторFctory = TransformerFactory.newInstance();
}
public static void сериализовать (узел узла, выход OutputStream)
выдает TransformerException {
Сериализатор трансформатора = сериализаторFctory.newTransformer();
Свойства сериализаторПропс = новые свойства();
seriesizerProps.put(OutputKeys.METHOD, "xml");
сериализатор.setOutputProperties(serializerProps);
Исходный источник = новый DOMSource(узел);
Результат результата = новый StreamResult (выход);
сериализатор.трансформ (источник, результат);
}
Существует так много стандартных опций и сред разработки для генерации XML на стороне сервера, что единственное, что вам нужно сделать, — это выбрать тот, который подходит именно вам. Однако на клиенте ситуация совсем другая, поскольку XML можно анализировать только с использованием DOM. Некоторые браузеры также поддерживают XPath и XSLT.
В предыдущих статьях об Ajax вы узнали, как генерировать XML с помощью JSP, а затем анализировать его на клиенте с помощью JavaScript и DOM. Другое решение — использовать JSON вместо XML в качестве формата данных для ответа на запросы Ajax. Как упоминалось ранее, строку JSON можно преобразовать в дерево объектов JavaScript с помощью функции eval(). Это проще, чем использовать JavaScript для извлечения информации из дерева DOM. Все, что вам нужно, — это хороший служебный класс, который генерирует JSON на стороне сервера.
JSON-кодирование. Класс JSONEncoder предоставляет методы для кодирования литералов, объектов и массивов. Результаты сохраняются в java.lang.StringBuilder:
package ajaxapp.util
public class JSONEncoder {;
частный StringBuilder буф;
общественный JSONEncoder() {
buf = новый StringBuilder();
}
...
}
Методcharacter() кодирует один символ:
public voidcharacter(charch) {
переключатель (ч) {
случай \:
случай \":
случай \ :
buf.append( \ );
buf.append(ч);
перерыв;
случай :
buf.append( \ );
буф.добавление ();
перерыв;
случай
:
buf.append( \ );
buf.append(
);
перерыв;
случай
:
buf.append( \ );
buf.append(
);
перерыв;
по умолчанию:
если (ch >= 32 && ch < 128)
buf.append(ч);
еще{
buf.append( \ );
buf.append(u);
for (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);
}
}
}
}
Метод string() кодирует всю строку:
public void string(String str) {
длина int = str.length();
for (int я = 0; я <длина; я++)
символ(str.charAt(i));
}
Метод literal() кодирует литерал JavaScript:
public void literal(Object value) {
if (значение экземпляра строки) {
buf.append(");
строка ((Строка) значение);
buf.append(");
} else if (значение экземпляра символа) {
buf.append(\);
символ(((Символ) значение).charValue());
buf.append(\);
} еще
buf.append(value.toString());
}
Метод comma() добавляет запятую:
Private void comma() {
buf.append(,);
}
Метод deleteLastComma() удалит последний символ запятой в конце буфера (если таковой имеется):
Private void deleteLastComma() {
если (buf. length() > 0)
if (buf.charAt(buf.length()-1) == ,)
buf.deleteCharAt(buf.length()-1);
}
Метод startObject() добавляет символ { для обозначения начала объекта JavaScript:
public void startObject() {
buf.append({);
}
Метод property() кодирует свойства JavaScript:
public void property(String name, Object value) {
buf.append(имя);
buf.append(:);
литерал (значение);
запятая();
}
Метод endObject() добавляет символ }, обозначающий конец объекта JavaScript:
public void endObject() {
удалитьLastComma();
buf.append(});
запятая();
}
Метод startArray() добавляет символ [, обозначающий начало массива JavaScript:
public void startArray() {
buf.append([);
}
Метод element() кодирует элементы массива JavaScript:
public void element(Object value) {
литерал (значение);
запятая();
}
Метод endArray() добавляет символ ] для обозначения конца массива JavaScript:
public void endArray() {
удалитьLastComma();
buf.append(]);
запятая();
}
Метод toString() возвращает строку JSON:
public String toString() {
удалитьLastComma();
вернуть buf.toString();
}
Методclear() очищает буфер:
public voidclear() {
buf.setLength(0);
}
DataModel использует класс JSONEncoder для кодирования хранимых данных:
publicsynced String getData() {
JSONEncoder json = новый JSONEncoder();
json.startArray();
for (int i = 0; i
json.startObject();
json.property("символ", stock.getSymbol());
json.property("акции", stock.getShares());
json.property("paidPrice", stock.getPaidPrice());
json.endObject();
}
json.endArray();
вернуть json.toString();
}
Если указаны параметры запроса XML, страница ajaxCtrl.jsp установит данные модели. В противном случае страница будет использовать выражение EL ${dataModel.data} для вывода строки JSON, возвращаемой getData():
< %@ taglib prefix="c" uri=" http://java.sun.com/jsp/ jstl /core " %>
...
< jsp:useBean id="dataModel"scope="session"
class="ajaxapp.model.DataModel" />
...
< c:when test="${!empty param.xml}">
< c:set target="${dataModel}"
свойство="данные"
value="${param.xml}" />
<с:иначе>
${dataModel.data}
Это задание не завершено, поскольку клиент Ajax должен обработать данные JSON.
Обработка ответов на стороне клиента
В типичном веб-приложении вы генерируете контент на стороне сервера с помощью JSP, веб-платформ и библиотек тегов. Приложения Ajax идеально подходят для этой ситуации, поскольку такие веб-фреймворки, как JavaServer Faces и Oracle ADF Faces, очень полезны при создании приложений Ajax. Однако между Ajax- и не-Ajax-приложениями все еще существуют существенные различия. При использовании Ajax вы должны обрабатывать данные на стороне клиента и использовать JavaScript для динамического создания контента для предоставления данных пользователю.
Если вы используете формат JSON для преобразования данных, очень легко преобразовать текст в дерево объектов с помощью функции eval(), предоставляемой JavaScript. Если вы предпочитаете использовать XML, вам нужно сделать много других вещей, но у этого формата есть и свои преимущества. Например, XML может использоваться многими типами клиентов, тогда как JSON легко анализируется только в среде JavaScript. Кроме того, при использовании XML ошибки можно найти и исправить быстрее, что сокращает время отладки.
Используйте JavaScript для доступа к дереву DOM. DOM API в JavaScript очень похож на пакет org.w3c.dom в Java. Основное отличие — доступ к свойствам. В JavaScript вы можете получить доступ к свойствам напрямую, тогда как Java рассматривает свойства как частные, и вам необходимо получить к ним доступ с помощью методов get и set. Например, вы можете получить корневой элемент документа через dom.documentElement.
DOM — это низкоуровневый API, который обеспечивает доступ к структуре анализируемого документа. Например, в большинстве случаев вы хотите игнорировать комментарии и не хотите иметь соседние текстовые узлы. Рассмотрим следующий простой пример:
var xml = "< element>da< !--comment-->ta&"
+ "< ![CDATA[cdata< /element>";
Вы можете проанализировать приведенную выше строку XML, используя служебную функцию, представленную ранее:
var dom = parse(xml);
Код функции parse() можно найти в ajaxUtil.js; в этом случае функция возвращает дерево DOM, корневой элемент которого содержит текстовый узел, за которым следует комментарий, еще один текстовый узел и узел символьных данных. Если вы хотите включить текст без комментариев, вам необходимо перебрать дочерние элементы элемента, объединяя значения узлов текстовых и символьных данных (которые имеют типы 3 и 4 соответственно):
var element = dom.documentElement;
вар childNodes = element.childNodes;
вар текст = "";
for (var я = 0; я
тип вар = childNodes[i].nodeType;
если (тип == 3 || тип == 4)
текст += childNodes[i].nodeValue;
}
При работе с DOM вам следует создать небольшой набор служебных функций, чтобы избежать работы с этими низкоуровневыми деталями.
Используйте JavaScript для создания динамического контента. Веб-браузеры позволяют получить доступ к структуре DOM веб-страницы через объекты документа. Например, вы можете использовать document.getElementById(...), чтобы очень легко найти элемент. Вы также можете создавать новые элементы и текстовые узлы, которые можно вставлять в существующие документы. Однако проще создать HTML, объединив строки, как показано ниже:
function updateInfo(request) {
вар акции = eval(request.responseText);
var table = "< граница таблицы=1 cellpadding=5>";
таблица += "
Сгенерированный HTML может быть вставлен
в пустой элемент, установив свойство Innerhtml объекта, возвращаемого getElementbyId (), например:
В примере в этой статье используется функция UpdateInfo () в качестве обратного вызова для обработки ответов на запросы AJAX, отправленные на сервер, через SendInForeQuest в файле jaxlogic.js. Если вы хотите обновлять информацию каждые 5 секунд, вы можете использовать функцию javaScript setInterval ():
var Symbols = [...];
SetInterval ("SendInForeQuest (Symbols, UpdateInfo)", 5000);
Класс называется DataFeed моделирует канал на стороне сервера. На странице ajaxctrl.jsp вызывает метод getData (), возвращая ответ как строку JSON. На стороне клиента функция UpdateInfo () анализирует строку JSON с использованием eval (request.responsetext), как показано в предыдущем примере кода.