AJAX (Asynchronous XML And JavaScript) -- это способ построения веб-приложений на основе объединения целого ряда технологий:
Аббревиатура AJAX, также как DHTML или LAMP, не является технологией, а обозначает совместное использование группы существующих технологий.
В качестве платформы для выполнения AJAX-приложений может выступать любой популярный браузер последних версий: Mozilla Firefox, Microsoft Internet Explorer, Opera, Apple Safari.
Суть AJAX в том, что приложения, использующие его, становятся более интерактивными и похожими на традиционные приложения, выполняющиеся в операционной системе. Достигается это тем, что для каждого взаимодействия с пользователем можно обновить только часть страницы, а не перезагружать всю страницу целиком, как в традиционных веб-приложениях.
Рис. Модель веб-приложения
Рис. Сравнение традиционной модели
взаимодействия в веб-приложениях и AJAX
На самом деле идея сделать веб-приложения более похожими на обычные приложения в смысле пользовательского интерфейса не нова и такие возможности уже давно могли быть реализованы с помощью различных технологий: Macromedia Flash, Java Applets, Microsoft ActiveX и т.д. Однако, все они не получили очень широкого распространения из-за того, что использовали частные закрытые решения отдельных фирм, требовали установки дополнительного программного обеспечения и не имели достаточной переносимости между платформами. AJAX лишен этого недостатка.
Хотя AJAX не требует установки дополнительного программного обеспечения, для его работы все-таки необходимо, чтобы в браузере был включен JavaScript, поэтому чтобы приложения были по-настоящему переносимыми, это необходимо предусмотреть. В настоящее время для обхода этого недостатка были добавлены средства в ряд библиотек для поддержки AJAX и выработаны определенные техники для поддержки пользователей с выключенным JavaScript-ом.
Другие недостатки AJAX связаны с удобством использования -- нарушается работа кнопки «Назад» браузера и возможность делать закладки на определенное состояние приложения. Для обхода этих недостатков также разработаны и применяются различные техники.
Внедрение AJAX идет полным ходом как на любительских сайтах, так и на крупных сайтах, обслуживающих миллионы запросов ежедневно.
Приведем простой низкоуровневый пример веб-приложения, использующего AJAX, из которого хорошо видно какие технологии и как используются для достижения требуемого эффекта частичного обновления страницы. В примере не будут использованы никакие дополнительные средства, позволяющие упростить разработку AJAX-приложений и повысить уровень абстракции.
Для того, чтобы испытать данный пример необходимо иметь доступ к веб-серверу с поддержкой PHP. Полные исходные коды примера приведены на github-е (в архиве).
Серверная часть примера представляет собой PHP-скрипт, являющийся простейшим веб-сервисом. Понятие веб-сервиса в общем случае не ограничивается SOAP/WSDL-сервисами. Возможно применять и другие XML-протоколы. Один из наиболее популярных из них XML/RPC. В нашем примере для простоты между сервисом и клиентом будут передаваться чистые данные без какой-либо XML-разметки.
Функция разработанного веб-сервиса -- принимать на входе методом POST число и выдавать на выходе это число возведенное в квадрат. Число передается в виде строки и никакой проверки правильности входных данных не производится.
Серверная часть примера test.php
<?php // vim:ts=4 $x = $GLOBALS['HTTP_RAW_POST_DATA']; print($x * $x); ?>
Клиентская часть примера представляет собой HTML-файл с внедренными JavaScript-инструкциями. Клиент посылает веб-сервису число и асинхронно принимает ответ. Асинхронность означает, что веб-браузер не подвисает во время запроса и пользователь может продолжать работать пока запрос выполняется. (рис. 2)
Основой поддержки AJAX в браузере является объект XMLHttpRequest для браузеров Mozilla, Safari и прочих, и объект ActiveX Microsoft.XMLHTTP для браузеров фирмы Microsoft.
Ответ веб-сервиса выдается пользователю с помощью стандартной функции JavaScript alert(), но чаще всего он внедряется непосредственно в страницу с помощью DOM, встроенной в браузер.
Клиентская часть примера test.html
<html> <head> </head> <body> <script type="text/javascript" language="javascript"> // <![CDATA[ var http_request = false; function makeRequest(url) { http_request = false; if (window.XMLHttpRequest) { // Mozilla, Safari,... http_request = new XMLHttpRequest(); if (http_request.overrideMimeType) { http_request.overrideMimeType('text/xml'); } } else if (window.ActiveXObject) { // IE try { http_request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { http_request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {} } } if (!http_request) { alert('Giving up :( Cannot create an XMLHTTP instance'); return false; } http_request.onreadystatechange = alertContents; http_request.open('POST', url, true); http_request.send('5'); } function alertContents() { if (http_request.readyState == 4) { // COMPLETED if (http_request.status == 200) { // HTTP STATUS alert(http_request.responseText); } else { alert('There was a problem with the request.'); } } } // ]]> </script> <span style="cursor: pointer; text-decoration: underline" onclick="makeRequest('http://freedomnet.ru/services/simple/test.php')"> Make a request </span> </body> </html>
Рис. Пользовательский интерфейс
примера
Заголовки пересылаемые при вызове веб-сервиса
POST /services/simple/test.php HTTP/1.1 Host: freedomnet.ru User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.12) Gecko/20050915 Firefox/1.0.7 Accept: text/xml,application/xml,application/xhtml+xml,index.htm;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive Content-Type: text/xml Content-Length: 1 Pragma: no-cache Cache-Control: no-cache 5 HTTP/1.x 200 OK Date: Wed, 09 Nov 2005 11:40:36 GMT Server: Apache/2.0.54 X-Powered-By: PHP/5.0.5 Content-Length: 2 Keep-Alive: timeout=10, max=100 Connection: Keep-Alive Content-Type: index.htm; charset=WINDOWS-1251 Content-Language: ru 25
В последнее время в сообществе веб-разработчиков AJAX является горячей темой. Неудивительно, что уже появилось множество библиотек поддержки AJAX для различных языков программирования. [2,3] Среди них можно выделить некоторую классификацию. Во-первых, по языку программирования:
По функциональности AJAX-библиотеки можно разделить на:
Рассмотрим компонентно-ориентированные библиотеки поддержки AJAX на примере компонентов для JavaServer Faces (JSF).
JavaServer Faces -- это набор серверных компонентов Java для создания HTML-интерфейсов. Для него существуют компоненты, использующие Ajax.
Рассмотрим компонент Progress Bar, который показывает ход выполнения некоторого процесса на сервере в виде заполняющейся полосы и процентов выполнения. (рис. 4)
Данный пример выполняется в любом Java-веб-контейнере, поддерживающем стандарт сервлетов. Я использовал Apache Tomcat 5.5. Полные исходные коды примера приведены на сайте https://bpcatalog.dev.java.net/nonav/ajax/progress-bar-jsf/frames.html.
Рис. Компонент Progress Bar
Текст JSP-страницы с компонентом Progress Bar
<%-- Copyright 2004-2005 Sun Microsystems, Inc. All rights reserved. You may not modify, use, reproduce, or distribute this software except in compliance with the terms of the License at: http://developer.sun.com/berkeley_license.html --%> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@ taglib uri="http://java.sun.com/blueprints/ajax/progress-bar" prefix="d" %> <f:view> <html> <head> <title>AJAX enabled Button and Progress Bar</title> </head> <body> <h:form id="form"> <table> <tr><td><d:progressBar id="progressBar" value="#{process.percentage}" interval="#{process.pollInterval}" action="complete" /> </td> <td> </td></tr> </table> <p>For a detailed description of this component, please see <a href="https://bpcatalog.dev.java.net/ajax/progress-bar-jsf/">the blueprints catalog entry</a>.</p> </h:form> </f:view> </body> </html>
Переменная process соответствуют классу ProcessBean:
Класс ProcessBean
/* Copyright 2005 Sun Microsystems, Inc. All rights reserved. You may not modify, use, reproduce, or distribute this software except in compliance with the terms of the License at: http://developer.sun.com/berkeley_license.html */ /* * $Id: ProcessBean.java,v 1.2 2005/06/11 06:05:10 edburns Exp $ */ package com.sun.j2ee.blueprints.bpcatalog.ajax.progressbar; import java.util.Random; public class ProcessBean { public ProcessBean() { } private int percentage = 0; private int increment = 10; public int getPercentage() { if (100 < percentage) { percentage = 0 - increment; } return percentage += increment; } /** * Getter for property randomPercentage. * @return Value of property randomPercentage. */ public int getRandomPercentage() { return random.nextInt(101); } private Random random = new Random(); /** * Holds value of property pollInterval. */ private int pollInterval = 250; /** * Getter for property pollInterval. * @return Value of property pollInterval. */ public int getPollInterval() { return this.pollInterval; } /** * Setter for property pollInterval. * @param pollInterval New value of property pollInterval. */ public void setPollInterval(int pollInterval) { this.pollInterval = pollInterval; } }
Для написания примера AJAX-приложения на Java я выбрал библиотеку DWR.
Библиотека Direct Web Remoting (DWR) позволяет «экспортировать» код Java в код JavaScript веб-страницы и непосредственно вызывать Java-методы из веб-страницы. На самом деле эта библиотека реализует удаленные вызовы с помощью технологий AJAX. Кроме того она предоставляет удобные JavaScript-функции для манипулирования содержимым страницы через DOM.
Для выполнения данного примера необходим Java-веб-контейнер, поддерживающий стандарты сервлетов. Я использовал Apache Tomcat 5.5. Кроме того необходимо скачать и установить в контейнер библиотеку DWR. Полные исходные коды примера находятся на github-е (в архиве).
Приведенный пример будет аналогичен примеру из раздела 2 -- возведение числа в квадрат. Только на этот раз код примера будет выглядеть гораздо чище и понятнее, входное значение можно будет вводить непосредственно пользователю, а выходное значение будет внедряться в страницу, а не выводиться через функцию alert().
Java-код примера состоит всего из одного простого класса:
Calculator.java
package org.koliamorev.dwr; public class Calculator { public float Square(float num) { return num * num; } }
Этот класс через десриптор dwr.xml экспортируется в JavaScript код:
dwr.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN" "http://www.getahead.ltd.uk/dwr/dwr10.dtd"> <dwr> <allow> <create creator="new" javascript="Calculator"> <param name="class" value="org.koliamorev.dwr.Calculator" /> </create> </allow> </dwr>
В JSP-странице мы включаем сгенерированные заглушки для класса Calculator, а также вспомогательный JavaScript-код библиотеки DWR. Кроме того здесь мы задаем функцию назначенную для кнопки «Отправить» и функцию-callback для получения результатов вычислений.
index.jsp
<%@ page language="java" contentType="index.htm; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="index.htm; charset=UTF-8"> <title>Insert title here</title> </head> <body> <script type='text/javascript' src='dwr/engine.js'></script> <script type='text/javascript' src='dwr/interface/Calculator.js'></script> <script type='text/javascript' src='dwr/util.js'></script> <script type='text/javascript'> // <![CDATA[ function sendNumber() { var number = DWRUtil.getValue("number"); DWRUtil.setValue("result", ""); Calculator.Square(gotResult, number); } function gotResult(number) { DWRUtil.setValue("result", number); } // ]]> </script> <p> Введите число: <input id="number"/> <input type="button" value="Возвести в квадрат" onclick="sendNumber()"/> </p> <p>Ответ: <span id="result"></span></p> </body> </html>
JavaScript-заглушки Java-классов генерируются каждый раз во время вызова страницы. Происходит это через специальный сервлет библиотеки DWR. Поэтому в дексрипторе веб-приложения web.xml мы назначаем переадресацию на этот сервлет всех вызовов адресов вида dwr/*.
web.xml
<?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>dwr</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <servlet> <servlet-name>dwr-invoker</servlet-name> <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>true</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>dwr-invoker</servlet-name> <url-pattern>/dwr/*</url-pattern> </servlet-mapping> </web-app>
Рис. Пользовательский интерфейс примера
Обмен данными с сервером
http://localhost:8080/dwr/dwr/exec/Calculator.Square POST /dwr/dwr/exec/Calculator.Square HTTP/1.1 Host: localhost:8080 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.12) Gecko/20050915 Firefox/1.0.7 Accept: text/xml,application/xml,application/xhtml+xml,index.htm;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive Content-Type: text/xml Content-Length: 119 Cookie: JSESSIONID=E0ACB6407919818A27C1EBA4DD0A6753 Pragma: no-cache Cache-Control: no-cache callCount=1 c0-scriptName=Calculator c0-methodName=Square c0-id=7260_1132038473906 c0-param0=string:3.1415926 xml=true HTTP/1.x 200 OK Server: Apache-Coyote/1.1 Content-Type: text/plain;charset=ISO-8859-1 Transfer-Encoding: chunked Date: Tue, 15 Nov 2005 07:07:53 GMT <script type='text/javascript'> var s0=9.869603; window.parent.DWREngine._handleResponse('520_1132038593390', s0); </script>
Технология AJAX и вопросы связанные с разработкой таких приложений в настоящее время очень популярны в среде веб-разработчиков и дизайнеров и быстро развиваются. Так, например, в следующих версиях браузера Mozilla планируется добавить более продвинутую поддержку XML в движок JavaScript. Это будет способствовать переходу на XML-формат для обмена данными в AJAX-приложениях (в настоящее время более удобными оказываются простые текстовые форматы). Постоянно открываются какие-либо новые аспекты связанные с этой технологией, отмечаются различные достоинства и недостатки. Но уже сейчас можно сказать, что AJAX прочно занял свое место на огромном количестве сайтов.
Отметим важные вопросы, которые не были рассмотрены в данном докладе: обратная совместимость AJAX-приложений с устаревшими браузерами, техники сохраняющие usability традиционных веб-приложений (кнопка «Назад», соответствие URL и состояния веб-приложения и т. д.).
~
area~
components.htm, 10.11.2005)