РАСШИРЕНИЕ ВОЗМОЖНОСТЕЙ ИНТЕРАКТИВНЫХ ПОЛЬЗОВАТЕЛЬСКИХ ИНТЕРФЕЙСОВ WEB-ПРИЛОЖЕНИЙ С ПОМОЩЬЮ ТЕХНОЛОГИИ AJAX В.В. Власов
Научный руководитель - к. т.н., доцент Б.А. Крылов
Описаны решения и технологии, которые могут помочь разработчику интерфейсов WEB-приложений создавать мощные высокоскоростные инструменты взаимодействия между клиентом (браузером) и сервером. AJAX - одно из самых перспективных направлений развития интернет-технологий, которое дает принципиально новые возможности WEB-интерфейсу, увеличивает скорость работы пользователя и уменьшает время ожидания получения или обработки информации.
Введение
О технологии AJAX впервые заговорили после появления 1B февраля 2GG5 г. статьи Джесси Джеймса Гарретта (Jesse James Garrett) «AJAX - новый подход к разработке веб-приложений» (AJAX: A New Approach to Web Applications) [1]. Автором статьи описывается новая развивающаяся технология, которая является одновременно революционной в подходах к разработке веб-интерфейсов и объединением нескольких самостоятельных технологий, которые могут быть эффективно использованы вместе. AJAX - сокращение от Asynchronous JavaScript + XML (Асинхронный JavaScript и XML) - представляет собой фундаментальный сдвиг в сторону увеличения возможностей веб-приложений. Поэтому принято считать, что AJAX - это не самостоятельная технология, а скорее идея.
В последнее время выходит множество различных статей и книг, где рассказывается о совместном использовании AJAX и популярного скриптового языка программирования PHP. В данной статье мы этого вопроса касаться не будем.
Было бы неправильно сказать, что java-разработчики обделены информацией по использованию технологии AJAX, однако большая часть документации доступна на английском языке. Существуют также книги, полностью посвященные AJAX и шаблонам проектирвоания приложений AJAX на стороне клиента [2]. В данной статье будут описаны общие принципы и подходы к проектированию динамических веб-интерфейсов с использованием AJAX, а также практическое применение AJAX с Java 2 Enterprise Edition (J2EE), основанное на документации, предоставляемой Sun Microsystems [3].
Что такое AJAX
Классические WEB-приложение работает примерно следующим образом: большинство действий пользователя (формы, гиперссылки) вызывает обращение к серверу. В основном используются формы для заполнения и отправки некоторых данных. Пользователь вводит некоторые данные, нажимает Submit. На сервер отправляется эта информация (запрос). Сервер занимается обработкой запроса - принимает данные, выполняет необходимые операции, обращаясь к другим методам, классам и, в конце концов, формирует HTML страничку, которую возвращает пользователю. Подобный подход изначально разрабатывался для того, чтобы использовать WEB как хранилище гипертекстовых документов, однако то, что делает WEB хорошим для хранения гипертекстовых документов, не обязательно делает его хорошим для создания WEB-приложений.
Что делает пользователь, пока сервер выполняет свою работу? Правильно. Он ждет. И, с выполнением каждой следующей операции, он ждет еще и еще. Поэтому разработчики WEB-интерфейсов иногда испытывают зависть к разработчикам оконных
приложений, которые обладают более богатыми возможностями и отзывчивостью при взаимодействии с пользователем, что, как кажется, недостижимо для WEB-приложений. Та же самая простота, которая способствовала быстрому распространению WEB, создает непреодолимое расстояние между тем, что мы можем предложить пользователям WEB-приложений, и тем, что пользователь получает при использовании standalone приложений.
AJAX предназначен для того, чтобы решить эту проблему, расширить возможности интерактивных пользовательских WEB-интерфейсов и приблизить WEB-приложения по функциональности к привычным всем нам GUI-приложениям. Если весь интерфейс уже загрузился, почему взаимодействие пользователя с программой должно прерываться, как только программе понадобились некоторые данные с сервера? Почему пользователь вообще должен видеть, что приложение обращается к серверу? AJAX позволяет сделать взаимодействие приложения с сервером незаметным для пользователя и перезагружать не всю страницу, а только отдельные ее фрагменты.
Идея AJAX довольно проста. Сравним механизмы взаимодействия клиент-сервер (рис. 1). Если в случае обычных WEB-приложений клиент (browser client) отправляет по протоколу HTTP запрос на сервер, на сервере происходит обработка запроса, возвращается ответ, страница у клиента в браузере перезагружается и отображает новую страницу, полученную с сервера.
а б
Рис. 1. Сравнение традиционной модели WEB-приложения (а) с моделью AJAX приложений (б)
AJAX приложения позволяют избавиться от прерывистого процесса взаимодействия с WEB-приложением благодаря промежуточному слою между пользователем и сервером - движку AJAX. Казалось бы, добавление нового слоя замедлит взаимодействие между пользователем и программой, но на самом деле возникает обратный эффект. Вместо того, чтобы загружать страницу в начале работы приложения, браузер загружает AJAX движок (AJAX engine), который написан на JavaScript. Этот движок отвечает за отображение WEB-страницы и за взаимодействие приложения с сервером. AJAX движок позволяет пользователю осуществлять взаимодействие с сервером асинхронно, т.е. независимо от обращения к серверу. Таким образом, пользователю нет необходимости наблюдать чистую страницу в браузере или иконку песочных часов в ожидании, когда сервер что-нибудь сделает.
Теперь рассмотрим, какие технологии имелись в виду, когда мы говорили о том, что AJAX - не самостоятельная технология, а идея.
AJAX подразумевает совместное использование следующих технологий:
• стандартные средства отображения страниц DHTML [4];
• механизмы асинхронной передачи данных с сервера с помощью XMLHttpRequest [5], хотя на данный момент этот объект не специфицирован в JavaScript технологии, однако он поддерживается всеми наиболее используемыми браузерами;
• динамические средства отображения информации и взаимодействия с пользователем - Document Object Model [6];
• обмен данными и их обработка - XML и XSLT [7];
• JavaScript, который объединяет все это вместе.
Динамическое обращение к серверу «на лету», без перезагрузки всей страницы полностью, может быть реализовано также с использованием следующих инструментов:
• через динамическое создание дочерних фреймов [8];
• через динамическое создание тега <script>[9].
Используя JavaScript, WEB-страница может асинхронно обращаться к серверу, получать некоторое требуемое содержимое, представленное в XML-формате, текста, html-содержимого или в формате JavaScript Object Notation (JSON) [10]. Затем JavaScript может обновить или изменить используемую Document Object Model html-страницы в соответствии с новыми полученными данными. Взаимодействие страницы с JavaScript основано на отслеживании таких событий, как загрузка документа, клик мышки, изменение фокуса/позиции курсора (мыши), изменение времени и др. AJAX позволяет четко отделить логику представления от отображаемых данных. Для этого html-страница должна быть «разбита» на составные компоненты: базовые и загружаемые. Для реализации подобного взаимодействия AJAX-у требуются различные серверные технологии (server-side). Обычно серверное WEB-приложение отвечает за создание (генерацию) html-страниц для каждого поступившего от клиента запроса. При следующем запросе (обновлении) страницы опять происходит генерация новой страницы и возвращение ее браузеру клиента. «Толстое», более интеллектуальное WEB-приложение ведет себя по-другому: сначала загружается шаблон (контейнер), т. е. некая базовая часть приложения, которая, в свою очередь, отображает содержимое в зависимости от событий, произошедших на странице (клик мышки, перемещение курсора в другое место), используя XML данные, полученные с серверных компонентов приложения (server-side component), и перезагружает только те фрагменты страницы, которые связаны с данным событием (произведенным пользователем действием). Фактически WEB-приложение ведет себя также как обычное оконное (desktop) приложение. Вот некоторые возможные применения для AJAX: 1. Валидация данных формы в режиме реального времени (Real-time form data validation). Под валидацией обычно понимается не просто корректность / правильность типа данных (возраст может быт только числом, но не может быть строкой, если требуется ввести дату, то она должна быть в правильном формате, и т.д.), но и согласованность с определенными критериями. Например, логин пользователя должен быть уникальным (это свойство системы), формат электронного адреса e-mail должен не просто быть строкой, но отвечать определенным критериям, т.е. содержать определенные элементы. Режим real-time подразумевает, соответственно, возможность проверять данные на ходу, не ожидая, пока пользователь произведет какое-либо действие (подтверждение заполнения формы). К данным, которые не могут быть проверены на стороне клиента, можно отнести ID пользователя, серийный номер, пароль, почтовый код и другие данные, которые проверяются на стороне сервера посредством обращения к базе данных или другим хранилищам данных. Очевидно, что в случае обычного WEB-приложения пользователю необходимо отправить форму, прежде чем получить ответ.
2. Загрузка по запросу (Load on demand). Этот вид взаимодействия основан на некоем событии, произошедшем на стороне клиента. WEB-приложение позволяет получать дополнительные данные только после запроса (если таковой произойдет), а не загружать все и сразу. Это существенно ускоряет загрузку страницы.
3. Усовершенствованный интерфейс пользователя и различные эффекты (Sophisticated user interface controls and effects). Возможность управления такими элементами, как деревья (каталогов), меню, таблицы данных, расширенные текстовые редакторы, календари, загрузки и многое другое без дополнительной перезагрузки страницы делает интерфейс пользователя дружественным и понятным (user-friendly).
4. Обновление и синхронизация данных (Refreshing data and server push). WEB-приложения могут получать актуальные (своевременные) данные, такие, как состояние счета, котировки акций, погода, голосования и другие специфические для вашего приложения данные. Однако не всегда эффективно использовать для этих целей AJAX. Такие технологии, как Comet [11], разработаны для того, чтобы сохранять постоянное соединение между клиентом и сервером для получении актуальных данных, которые могут меняться до нескольких раз в секунду.
5. Частичное подтверждение (Partial submit). WEB-приложение может принять на подтверждение не полностью (частично) заполненные данные формы без полного обновления страницы.
6. Объединение данных (Mashes). WEB-приложение может получать данные, используя прокси со стороны сервера или внешние скрипты, чтобы смешивать данные с внешних (других) источников с данными вашего приложения и служебными данными. Это дает возможность создавать свои собственные сервисы. Например, вы можете смешивать данные сторонних источников (таких как Google Maps) с вашими собственными.
7. Страница как приложение (Page as an application). AJAX технология позволяет создавать вам свои собственные одностраничные приложения, которые имеют интерфейс desktop приложений. Например, совмещение технологий AJAX и портле-тов (portlets) [12], проект Bindows [13].
Этот список можно продолжать дальше, однако и этих примеров достаточно, чтобы показать, что применение AJAX расширяет возможности интерактивных пользовательских WEB-приложений и ограничено только воображением разработчика (архитектора приложений).
Анатомия AJAX приложения на примере взаимодействия с J2EE платформой
Рассмотрим на конкретном примере, как работает WEB-приложение с AJAX на клиентской стороне и Java на стороне сервера. Наше WEB-приложение будет очень простое, правда все равно немного сложнее, чем Hello World! Для его реализации вам понадобится сервер приложений (например, JBoss [14]), JRE 1.5, SDK 1.5, библиотека ANT [15] для сборки (War-архива) и развертывания приложения, а также знания упоминаемых технологий.
Наше приложение содержит статическую HTML-страницу (либо сгенерированную сервером JSP страницу - подробнее о JSP технологии см. [16]). Страница содержит форму, которая заполняется некоторыми данными. Эти данные проверяются без перезагрузки страницы. Серверный компонент - сервлет (servlet) [17] называется ValidateServlet, он обеспечивает проверку формы на стороне сервера (бизнес логика приложения). Рис. 2 детально описывает процесс взаимодействия клиента и сервеВа.сь процесс работы приложения можно разбить на несколько этапов (рис. 2).
1. На стороне клиента происходит некоторое событие, вызывается обработчик событий.
2. Создается и настраивается XMLHttpRequest объект.
3. XMLHttpRequest объект посылает запрос к серверу.
4. Запрос (request) обрабатывается сервером (в нашем случае сервлетом ValidateServlet).
5. ValidateServlet возвращает XML документ (response).
6. XMLHttpRequest вызывает callback() функцию и обрабатывает результат.
7. HTML DOM обновяется.
Рассмотрим каждый шаг взаимодействия с AJAX подробно.
Рис. 2. Взаимодействие клиента и сервера с использованием AJAX на стороне клиента
и Веб-контейнера J2EE платформы
1. Возникновение события. В ответ на некоторое событие (заполнение формы) вызывается функция JavaScript. В нашем случае функция validate() обрабатывает событие onkeyup, относящееся к ссылке или компонента формы.
<input type="text" size="20 id="userid" name="id"
onkeyup="validateO;">
Элемент формы вызывает функцию validate() каждый раз, когда пользователь нажимает кнопку в форме.
2. Конфигурирование XMLHttpRequest объекта. Создается новый экземпляр объекта XMLHttpRequest.
var req;
function validate() { var idField = document.getElementById("userid"); var url = "validate?id=" + encodeURIComponent(idField.value); if (typeof XMLHttpRequest != "undefined") { req = new XMLHttpRequest(); } else if (window.ActiveXObject) {
req = new ActiveXObject("Microsoft.XMLHTTP"); }
req.open("GET", url, true); req.onreadystatechange = callback; req.send(null);
}
Функция validate() создает XMLHttpRequest объект. Метод этого объекта open() требует три параметра: HTTP метод (GET или POST) ; URL серверного компо-
нента, обрабатывающего данное событие - в нашем случае URL содержит имя сервлета с параметрами и переменную типу boolean, обозначающей должно ли взаимодействие быть асинхронным. API будет следующим XMLHttpRequest.open(String method, String URL, boolean asynchronous). Если взаимодействие должно быть асинхронным (true), то должна быть определена функция callback() . Функция callback() определяется выражением req. onreadystatechange = callback;. Более подробно это будет описано в п. 6.
3. XMLHttpRequest объект посылает запрос к серверу. Вызывается req.send(null); Если запрос отправляется методом GET, содержимое может быть пустым или null. Браузер отправляет запрос на сервер, используя URL, который был сконфигурирован для объекта XMLHttpRequest. В нашем случае данные присоединены к запросу в виде значение=параметр.
Используйте GET для «неполноценного» запроса, когда два одинаковых запроса возвращают одинаковые результаты. Учтите, когда используется запрос GET, длина строки URL (включая специальные символы) ограничивается некоторыми браузерами и контейнерами сервлетов. Метод POST используется, когда посылаемые данные необходимо скрыть из строки адреса URL. Метод POST требует Content-Type заголовка, который необходимо установить следующим образом:
req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
req.send("id=" + encodeURIComponent(idTextField.value));
Функция encodeURIComponent() обеспечивает корректную передачу данных в зависимости от локализации и отображает специальные символы, в том числе кириллические, в том виде, в каком они пригодны для HTTP запроса.
4. Обработка запроса на стороне сервера. Сервлет ValidateServlet вызывается контейнером, когда на сервер приходит обращение, содержащее URI «validate» («маппинг» (mapping) настраивается в конфигурационном xml файле вашего веб-приложения, например, web.xml).
Ниже показан код сервлета, извлекающего id параметр из запроса request и выполняющий всю бизнес-логику на стороне сервера.
public class ValidateServlet extends HttpServlet {
private ServletContext context; private HashMap users = new HashMap();
public void init(ServletConfig config) throws
ServletException {
super.init(config);
this.context = config.getServletContext(); users.put("greg","account data");
users.put("duke","account data"); }
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
String targetId = request.getParameter("id");
if ((targetId != null) && !users.containsKey(targetId.trim())) { response.setContentType("text/xml"); response.setHeader("Cache-Control", "no-
cache");
response.getWriter().write("<message> valid </message>"); } else {
response.setContentType("text/xml"); response.setHeader("Cache-Control", "no-cache");
response.getWriter().write("<message> invalid
</message>"); }
}
}
В нашем примере не преследуется цель создания кода, соответствующего «правилам хорошего тона» в программировании, а просто показаны базовые операции. Метод init() инициализирует сервлет. В этом есть необходимость только в данном примере. В этом методе создается HashMap, содержащий пользователей. Теоретически у нас должно быть некое хранилище данных (база данных), в котором хранится ID клиента, требующее проверки. На практике чаще всего используются технологии, позволяющие абстрагироваться от необходимости писать SQL-команды (или запросы к БД) в коде, основанные на бинах (Beans), например, EJB [18]. Эта технология позволяет разработчику не заботиться о типе БД (MySQL, Oracle, MSSQL и др.), самостоятельно управляет транзакциями, обеспечивает масштабируемость приложения и много полезных вещей. Также зарекомендовала себя ORM технология Hibernate [19], которая выполняет те же функции, однако более проста и конфигурируема при разработке.
В методе doGet() выполняется проверка, что параметр targetId существует и его значение (имя пользователя) не содержится в коллекции users.
5. ValidateServlet возвращает ответ клиенту. В зависимости от результата проверки if/else, отправляется ответ в формате XML. Пользователь с ID duke присутствует в нашей коллекции, поэтому возвращается XML документ, содержащий только один элемент (тэг) message со значением invalid.
Разработчик должен учесть следующие детали. Во-первых, Content-Type должен быть установлен text/xml. Во-вторых, Cache-Control должен быть no-cache. XMLHttpRequest объект обрабатывает только те запросы, которые удовлетворяют этим условиям. no-cache означает, что браузер клиента кэширует ответы сервера в том случае, если с одинаковых адресов на один и тот же запрос приходят разные ответы.
6. XMLHttpRequest вызывает callback() и обрабатывает результат.
XMLHttpRequest сконфигурирован так, что после получения ответа с сервера вызывается функция callback(). Проверяется, что запрос выполнен readyState==4 и код ответа 200 (успешно).
function callback() { if (req.readyState == 4) { if (req.status == 200) {
// update the HTML DOM based on whether or not message is valid }
}
}
Браузеры поддерживают объектное представление информации. HTML-страница имеет доступ к DOM модели, и API позволяет JavaScript модифицировать DOM после обновления данных.
Когда клиенту возвращается успешный запрос, можно использовать
XMLHttpRequest.responseXML. DOM API дает возможность JavaScript управлять содержимым страницы. Следующая функция делает «разбор» XML-документа. Вызов функции setMessage() обновляет DOM.
function parseMessage() { var message =
req.responseXML.getElementsByTagName("message")[0]; setMessage(message.childNodes[0].nodeValue);
}
7. HTML DOM обновлен. JavaScript может обратиться к любому элементу на странице, используя идентификаторы. Функция document.getElementById("userIdMessage") возвращает ссылку на элемент, который отмечен идентификатором "userldMessage". Используя эту ссылку, можно изменить атрибуты элемента, свойства стиля, добавить, удалить, изменить дочерние элементы. Содержимое тела элемента может быть изменено вызовом свойства innerHTML, как в следующем примере:
<script type="text/javascript">
function setMessage(message) { var mdiv = document.getElementById("userIdMessage"); if (message == "invalid") {
mdiv.innerHTML = "<div style=\"color:red\">Invalid User Id</ div>"; } else {
mdiv.innerHTML = "<div style=\"color:green\">Valid
User Id</ div>"; }
}
</script>
<body>
<div id="userIdMessage"></div>
</body>
Часть HTML-страницы будет изменена. Если свойство innerHTML содержит такие элементы, как <image> или <iframe>, то содержимое этих элементов загрузит новые данные с сервера и будет обновлено. Такие AJAX приложения, как Google Maps [20], реализуют технологию добавления изображений, используя вызовы AJAX, чтобы динамически строить карту.
Заключение
Самый большой прорыв в использовании AJAX подхода не является техническим. Основные технологии, используемые в AJAX, уже давно используются, стабильны и хорошо осмыслены. Прорыв для разработчиков WEB-приложений заключается в том, чтобы перешагнуть через общепринятые ограничения и быть открытыми для более широких и богатых возможностей. Уже сейчас пользователь Интернета может использовать приложения, построенные на идеологии AJAX: Flickr, GMail, Google Suggest или Google Maps. А что будет завтра? Системы автоматизированного проектирования в Интернет? On-line операционные системы, загружаемые с сервера производителя? Возможности, которые дает идеология AJAX, по истине безграничны.
Литература
1. J. J. Garrett. AJAX: A New Approach to Web Applications (http://www.adaptivepath.com/publications/ essays/archives/000385.php), 2005.
2. Крейн Д., Паскарелло Э. Ajax в действии. М.: Изд. дом «Вильямс», 2006.
3. G. Murray, Asynchronous JavaScript Technology and XML (AJAX) With the Java Platform. (http://java.sun.com/developer/technicalArticles/J2EE/AJAX/), 2006.
4. W3C: Dynamic Accessible Web Content Roadmap (http://www.w3.org/WAI/PF/roadmap/ DHTMLRoadmap040506.html), April 5, 2006.
5. W3C: The XMLHttpRequest Object (http://www.w3.org/TR/XMLHttpRequest/), 27 February 2007.
6. W3C: Document Object Model (www.w3.org/DOM/ ), 2005.
7. W3C: XSL Transformations (XSLT) Version 1.0 (http://www.w3.org/TR/xslt), 16 November 1999.
8. Remote Scripting with IFRAME (http://developer.apple.com/internet/webcontent/iframe.html ).
9. JsHttpRequest: динамическая подкачка данных с поддержкой AJAX (http://dklab.ru/lib/JsHttpRequest/).
10. JavaScript Object Notation data-interchange format (www.json.org/).