Журнал LinuxFormat - перейти на главную

LXF95:Java EE

Материал из Linuxformat
(Различия между версиями)
Перейти к: навигация, поиск
(uncomplete)
Строка 10: Строка 10:
 
позволяет приблизить логику работы интернет-приложений к обычной,
 
позволяет приблизить логику работы интернет-приложений к обычной,
 
«десктопной». С другой стороны – все браузеры таки разные. И это
 
«десктопной». С другой стороны – все браузеры таки разные. И это
последнее «таки» местами убивает наповал. Вы думаете, что браузе-
+
последнее «таки» местами убивает наповал. Вы думаете, что браузеров три? IE/Firefox/Opera? Хех. Для правильного приложения их нужно
ров три? IE/Firefox/Opera? Хех. Для правильного приложения их нужно
+
 
протестировать десяток. IE 5.5/6/7, Firefox 1.5/2, Opera 8/9, Safari 1.3/2/
 
протестировать десяток. IE 5.5/6/7, Firefox 1.5/2, Opera 8/9, Safari 1.3/2/
 
(а теперь и 3). И у каждого свой нрав.
 
(а теперь и 3). И у каждого свой нрав.
Строка 20: Строка 19:
 
едем на заправку, заправляем, уезжаем. Чтобы поменять фару – едем,
 
едем на заправку, заправляем, уезжаем. Чтобы поменять фару – едем,
 
снимаем, ставим, уезжаем. Вот это – AJAX. А если бы Аякса не было,
 
снимаем, ставим, уезжаем. Вот это – AJAX. А если бы Аякса не было,
то для каждой такой операции нужно было бы отдавать машину в сер-
+
то для каждой такой операции нужно было бы отдавать машину в сервис, а из сервиса возвращалась бы другая, хоть и максимально точная
вис, а из сервиса возвращалась бы другая, хоть и максимально точная
+
 
копия вашей, с обновлениями (бак заправлен). Асинхронность – это
 
копия вашей, с обновлениями (бак заправлен). Асинхронность – это
 
вообще что-то вроде дозаправки в воздухе. То есть обновление данных
 
вообще что-то вроде дозаправки в воздухе. То есть обновление данных
Строка 39: Строка 37:
 
только вместо маленького скрытого фрейма используется маленькая
 
только вместо маленького скрытого фрейма используется маленькая
 
«флэшка».
 
«флэшка».
 +
 
Впрочем, обычно оба эти способа используются только в случае,
 
Впрочем, обычно оба эти способа используются только в случае,
 
если не подходит «основной» – XMLHttpRequest. Это название объекта
 
если не подходит «основной» – XMLHttpRequest. Это название объекта
 
в JavaScript, который может выполнять асинхронные (и синхронные)
 
в JavaScript, который может выполнять асинхронные (и синхронные)
 
HTTP-запросы. Например:
 
HTTP-запросы. Например:
var xmlHttpRequestValue = new XMLHttpRequest();
+
<source lang="javascript">var xmlHttpRequestValue = new XMLHttpRequest();
 
xmlHttpRequestValue.open(“POST”, “/ajax.jsp?action=update”, true);
 
xmlHttpRequestValue.open(“POST”, “/ajax.jsp?action=update”, true);
 
xmlHttpRequestValue.onreadystatechange = processXmlHttpResponse;
 
xmlHttpRequestValue.onreadystatechange = processXmlHttpResponse;
xmlHttpRequestValue.send(“Информация для пересылки серверу”);
+
xmlHttpRequestValue.send(“Информация для пересылки серверу”);</source>
Все, запрос ушел. Сразу предупрежу, что это не рабочий код, толь-
+
Все, запрос ушел. Сразу предупрежу, что это не рабочий код, только иллюстрация. Обратите внимание на третью строчку. Выделенное
ко иллюстрация. Обратите внимание на третью строчку. Выделенное
+
 
жирным – это имя функции, которая будет обрабатывать события,
 
жирным – это имя функции, которая будет обрабатывать события,
генерируемые во время передачи запроса, такие, как «начат прием дан-
+
генерируемые во время передачи запроса, такие, как «начат прием данных», «закончен прием заголовка», «закончен прием данных». Если мы
ных», «закончен прием заголовка», «закончен прием данных». Если мы
+
хотим что-либо предпринять по окончании приема данных, эта функция будет выглядеть как-то так:
хотим что-либо предпринять по окончании приема данных, эта функ-
+
<source lang="java">function processXmlHttpResponse() {
ция будет выглядеть как-то так:
+
function processXmlHttpResponse() {
+
 
if (xmlHttpRequestValue.readyState == 4) {
 
if (xmlHttpRequestValue.readyState == 4) {
 
…сделать «что-либо»…
 
…сделать «что-либо»…
 
}
 
}
}
+
}</source>
 
Число «4» как раз обозначает, что обработка завершена. Функция
 
Число «4» как раз обозначает, что обработка завершена. Функция
 
processXmlHttpResponse() может вызываться много раз (даже точно не
 
processXmlHttpResponse() может вызываться много раз (даже точно не
Строка 66: Строка 62:
 
==== J ====
 
==== J ====
 
JavaScript – объектный язык. То есть создать класс, как в Java, в нем
 
JavaScript – объектный язык. То есть создать класс, как в Java, в нем
нельзя. А вот новый объект – запросто. И сформировать структуру объ-
+
нельзя. А вот новый объект – запросто. И сформировать структуру объекта (прописать методы, поля) «на лету» тоже можно.
екта (прописать методы, поля) «на лету» тоже можно.
+
 
Чаще всего JavaScript используется как простой способ динами-
+
Чаще всего JavaScript используется как простой способ динамически изменять структуру документа. Например, чтобы поменять цвет
чески изменять структуру документа. Например, чтобы поменять цвет
+
 
параграфа, можно выполнить такой код:
 
параграфа, можно выполнить такой код:
document.getElementById(“paragraph”).style.color = “red”;
+
<source lang="java">document.getElementById(“paragraph”).style.color = “red”;</source>
 
Параграф после этого покраснеет. Чтобы понимать, как добраться до
 
Параграф после этого покраснеет. Чтобы понимать, как добраться до
 
отдельных параграфов, нужно изучить DOM (Document Object Model).
 
отдельных параграфов, нужно изучить DOM (Document Object Model).
Строка 77: Строка 72:
 
==== X ====
 
==== X ====
 
XML, который попал в AJAX последней буквой, используется (как уже
 
XML, который попал в AJAX последней буквой, используется (как уже
упоминалось) далеко не всегда, но часто. Благо, в JavaScript есть воз-
+
упоминалось) далеко не всегда, но часто. Благо, в JavaScript есть возможности по достаточно простому преобразованию чего угодно в XML,
можности по достаточно простому преобразованию чего угодно в XML,
+
 
да и в других языках (не только в Java) библиотеки по работе с этим
 
да и в других языках (не только в Java) библиотеки по работе с этим
 
форматом достаточно хорошо развиты.
 
форматом достаточно хорошо развиты.
  
 
=== Помощники ===
 
=== Помощники ===
Из-за того, что реализации XMLHttpRequest различаются (в паре круп-
+
Из-за того, что реализации XMLHttpRequest различаются (в паре крупных деталей и, что хуже, в паре десятков мелочей), самому писать
ных деталей и, что хуже, в паре десятков мелочей), самому писать
+
 
кросс-браузерную обработку достаточно тяжело и долго. Поэтому
 
кросс-браузерную обработку достаточно тяжело и долго. Поэтому
давайте посмотрим на библиотеки, в состав которых входит «AJAX-
+
давайте посмотрим на библиотеки, в состав которых входит «AJAX-подсистема» и которые сделаны либо специально для Java-северной
подсистема» и которые сделаны либо специально для Java-северной
+
 
составляющей, либо поддерживают ее.
 
составляющей, либо поддерживают ее.
DOJO Огромная библиотека, которая много чего умеет. Если смот-
+
*; DOJO: Огромная библиотека, которая много чего умеет. Если смотреть только на коммуникативные возможности, то тут тоже все в порядке: можно использовать XMLXttpRequest, фрейм, Flash. Первый вариант предлагается по умолчанию. Чуть ниже будет пример работы с DOJO, а сейчас просто отметим, что с учетом достаточно приличной документации, логичной организации и большого количества модулей (в том числе и для использования разных методов коммуникации), библиотеку можно назвать хорошей.
реть только на коммуникативные возможности, то тут тоже все в
+
*; DWR – Direct Web Remoting: Сделана специально для Java. Достоинство состоит в том, что DWR умеет «публиковать» классы Java в JavaScript. То есть вы пишете класс в Java, настраиваете DWR (при помощи XML-дескриптора), и после запуска сервлета (обработкой запросов от DWR занимается отдельный сервлет) в JavaScript «появляются» методы этого класса, которые можно вызывать, так же, как если бы это были обычные функции JavaScript. Способ удобен, но навязывает определенный способ коммуникации. Подходит, когда не нужно контролировать каждый байт передаваемых данных и если с JavaScript вы знакомы не очень хорошо (хотя все равно его нужно знать, так как кроме коммуникации есть много чего еще).
порядке: можно использовать XMLXttpRequest, фрейм, Flash. Первый
+
*; GWT – Google Web Toolkit: В свое время эта библиотека наделала много шуму. Все дело в принципе ее работы. В общем и целом, если на DWR мы пишем на Java коммуникацию, то на GWT – все приложение. Затем GWT компилирует его в клиентскую часть (HTML + JavaScript) и серверную часть (Java). То есть клиент получается автоматически (не целиком, но близко к тому). GWT берет на себя все заботы и по взаимодействию клиента с сервером, и по созданию интерфейса (этот процесс несколько напоминает Swing), и многое другое. В принципе, достаточно хорошее решение, естественно со своими нюансами. Мы еще посмотрим на него поближе... к концу статьи.
вариант предлагается по умолчанию. Чуть ниже будет пример работы
+
с DOJO, а сейчас просто отметим, что с учетом достаточно приличной
+
документации, логичной организации и большого количества модулей
+
(в том числе и для использования разных методов коммуникации),
+
библиотеку можно назвать хорошей.
+
DWR – Direct Web Remoting. Сделана специально для Java.
+
Достоинство состоит в том, что DWR умеет «публиковать» классы Java
+
в JavaScript. То есть вы пишете класс в Java, настраиваете DWR (при
+
помощи XML-дескриптора), и после запуска сервлета (обработкой
+
запросов от DWR занимается отдельный сервлет) в JavaScript «появля-
+
ются» методы этого класса, которые можно вызывать, так же, как если
+
бы это были обычные функции JavaScript. Способ удобен, но навязы-
+
вает определенный способ коммуникации. Подходит, когда не нужно
+
контролировать каждый байт передаваемых данных и если с JavaScript
+
вы знакомы не очень хорошо (хотя все равно его нужно знать, так как
+
кроме коммуникации есть много чего еще).
+
GWT – Google Web Toolkit. В свое время эта библиотека наделала
+
много шуму. Все дело в принципе ее работы. В общем и целом, если на
+
DWR мы пишем на Java коммуникацию, то на GWT – все приложение.
+
Затем GWT компилирует его в клиентскую часть (HTML + JavaScript) и
+
серверную часть (Java). То есть клиент получается автоматически (не
+
целиком, но близко к тому). GWT берет на себя все заботы и по вза-
+
имодействию клиента с сервером, и по созданию интерфейса (этот
+
процесс несколько напоминает Swing), и многое другое. В принципе,
+
достаточно хорошее решение, естественно со своими нюансами. Мы
+
еще посмотрим на него поближе... к концу статьи.
+
  
 
=== Адресная книга с AJAX ===
 
=== Адресная книга с AJAX ===
 
Настало время потренироваться. Давайте возьмем нашу адресную
 
Настало время потренироваться. Давайте возьмем нашу адресную
книгу и сделаем так, чтобы показывалась страничка с табличкой (спис-
+
книгу и сделаем так, чтобы показывалась страничка с табличкой (списком телефонов), а по нажатии на ссылки вместо перехода на новые
ком телефонов), а по нажатии на ссылки вместо перехода на новые
+
 
странички менялся сам список: удалялись и добавлялись строки и так
 
странички менялся сам список: удалялись и добавлялись строки и так
 
далее. Использовать будем DOJO. Идеология от этого не пострадает, но
 
далее. Использовать будем DOJO. Идеология от этого не пострадает, но
Строка 130: Строка 95:
 
Вот строка HTML-таблицы, из которой видно, как будет выводиться
 
Вот строка HTML-таблицы, из которой видно, как будет выводиться
 
список телефонов.
 
список телефонов.
<tr id=”1232323” >
+
<source lang="html4strict"><tr id=”1232323” >
 
<td>1232323</td><td>Vasya Beanov</td><td><td>…</td><td><a
 
<td>1232323</td><td>Vasya Beanov</td><td><td>…</td><td><a
 
href=”#” on click=”remove(‘1232323’); return false;”>Remove</a> / <a
 
href=”#” on click=”remove(‘1232323’); return false;”>Remove</a> / <a
 
href=”#” on click=”startEdit(‘1232323’); return false;”>Edit</a></td>
 
href=”#” on click=”startEdit(‘1232323’); return false;”>Edit</a></td>
</tr>
+
</tr></source>
 
Обратите внимание на id=”…”. Это своеобразные метки, которые
 
Обратите внимание на id=”…”. Это своеобразные метки, которые
позволят при необходимости найти нужную строку. Теперь рассмот-
+
позволят при необходимости найти нужную строку. Теперь рассмотрим JavaScript-код, который выполняется при нажатии на «кнопку» Edit
рим JavaScript-код, который выполняется при нажатии на «кнопку» Edit
+
 
(как самую сложную).
 
(как самую сложную).
function startEdit(aPhone) {
+
<source lang="javascript">function startEdit(aPhone) {
 
getCell(aPhone, 0).innerHTML = ‘<input type=”text” value =”’ +
 
getCell(aPhone, 0).innerHTML = ‘<input type=”text” value =”’ +
 
getCell(aPhone, 0).innerHTML + ‘” id =”phone_’ + aPhone + ‘”/>’;
 
getCell(aPhone, 0).innerHTML + ‘” id =”phone_’ + aPhone + ‘”/>’;
Строка 148: Строка 112:
 
getCell(aPhone, 3).innerHTML = ‘<a href = “#” onclick = “submitEdit(\’’
 
getCell(aPhone, 3).innerHTML = ‘<a href = “#” onclick = “submitEdit(\’’
 
+ aPhone + ‘\’); return false;”>Save changes</a>’;
 
+ aPhone + ‘\’); return false;”>Save changes</a>’;
}
+
}</source>
Простым русским языком этом можно выразить так: ячейки с текс-
+
Простым русским языком этом можно выразить так: ячейки с текстом заменяются на ячейки с полями ввода.
том заменяются на ячейки с полями ввода.
+
 
 
После редактирования и нажатия на кнопку Save changes данные
 
После редактирования и нажатия на кнопку Save changes данные
 
отсылаются на сервер, и в ячейках снова прописывается текст.
 
отсылаются на сервер, и в ячейках снова прописывается текст.
function submitEdit(aPhone) {
+
<source lang="javascript">function submitEdit(aPhone) {
 
getCell(aPhone, 0).innerHTML = document.getElementById(‘phone_’ +
 
getCell(aPhone, 0).innerHTML = document.getElementById(‘phone_’ +
 
aPhone).value;
 
aPhone).value;
Строка 168: Строка 132:
 
“&name=” + getCell(aPhone, 1).innerHTML +
 
“&name=” + getCell(aPhone, 1).innerHTML +
 
“&comment=” + getCell(aPhone, 2).innerHTML);
 
“&comment=” + getCell(aPhone, 2).innerHTML);
}
+
}</source>
 
Теперь посмотрим, как отсылаются и принимаются данные. Для
 
Теперь посмотрим, как отсылаются и принимаются данные. Для
этого у нас есть показательная функция loadTable(), которая загру-
+
этого у нас есть показательная функция loadTable(), которая загружает табличку с сервера. Остальные функции только отправляют
жает табличку с сервера. Остальные функции только отправляют
+
 
данные.
 
данные.
function loadTable() {
+
<source lang="javascript">function loadTable() {
 
dojo.io.queueBind({
 
dojo.io.queueBind({
 
url : “/ajax?action=loadTable”,
 
url : “/ajax?action=loadTable”,
Строка 182: Строка 145:
 
preventCache : true
 
preventCache : true
 
});
 
});
}
+
}</source>
 
Обратите внимание на две вещи. Первая – использование dojo.
 
Обратите внимание на две вещи. Первая – использование dojo.
 
queueBind – это местная реализация AJAX. Нам не нужно беспокоиться,
 
queueBind – это местная реализация AJAX. Нам не нужно беспокоиться,
 
что будет использоваться «внутри» (хотя контролировать внутренности
 
что будет использоваться «внутри» (хотя контролировать внутренности
тоже можно). Вторая – параметр load. Это функция, которая вызывает-
+
тоже можно). Вторая – параметр load. Это функция, которая вызывается после загрузки данных с сервера (сами данные передаются в параметре aData). sendAJAXRequest выглядит абсолютно так же, только без
ся после загрузки данных с сервера (сами данные передаются в пара-
+
метре aData). sendAJAXRequest выглядит абсолютно так же, только без
+
 
параметра load.
 
параметра load.
Кстати, в queueBind’е сами параметры обрамлены фигурными скоб-
+
 
ками. Это как раз и есть объектность JavaScript. Тут создается объект с
+
Кстати, в queueBind’е сами параметры обрамлены фигурными скобками. Это как раз и есть объектность JavaScript. Тут создается объект с
 
полями url, method, load и preventCache, и уже этот объект передается
 
полями url, method, load и preventCache, и уже этот объект передается
 
в качестве параметра функции.
 
в качестве параметра функции.
Строка 199: Строка 160:
 
его работы осталась той же: опять действия. Только вместо выдачи
 
его работы осталась той же: опять действия. Только вместо выдачи
 
большого количества HTML-кода (через шаблоны или напрямую), в
 
большого количества HTML-кода (через шаблоны или напрямую), в
большинстве случаев не выдается ничего. Вот, например, код дейс-
+
большинстве случаев не выдается ничего. Вот, например, код действия удаления:
твия удаления:
+
<source lang="java">String phone = aRequest.getParameter(“phone”);
String phone = aRequest.getParameter(“phone”);
+
_recordsBook.removeRecord(phone);</source>
_recordsBook.removeRecord(phone);
+
 
Только действие создания таблицы телефонов выдает код таблицы
 
Только действие создания таблицы телефонов выдает код таблицы
(но только ее, а не всю страничку). Остальные методы только получа-
+
(но только ее, а не всю страничку). Остальные методы только получают данные и сохраняют их. Изменение таблицы происходит на клиенте при помощи JavaScript (как – можно посмотреть на код submitEdit
ют данные и сохраняют их. Изменение таблицы происходит на клиен-
+
те при помощи JavaScript (как – можно посмотреть на код submitEdit
+
 
выше или в полных исходных текстах на LXFDVD).
 
выше или в полных исходных текстах на LXFDVD).
  
Строка 215: Строка 173:
 
Definitive Guide» тоже не вдохновляет, ведь правда? К тому же архив
 
Definitive Guide» тоже не вдохновляет, ведь правда? К тому же архив
 
можно найти и на нашем DVD), установить. А дальше?
 
можно найти и на нашем DVD), установить. А дальше?
 +
 
Дальше процедура очень похожа на то, что позволяет делать,
 
Дальше процедура очень похожа на то, что позволяет делать,
 
например, Ruby on Rails (или аналогичные каркасы – см. стр. XX):
 
например, Ruby on Rails (или аналогичные каркасы – см. стр. XX):
Вы создаете некий код. Клиентский, серверный, шаблон странички.
+
* Вы создаете некий код. Клиентский, серверный, шаблон странички. При необходимости также можно применять свои CSS-стили.
При необходимости также можно применять свои CSS-стили.
+
* Затем создаете специальный XML-дескриптор. Это файл, который описывает, что нужно запускать, что будет сервером.
Затем создаете специальный XML-дескриптор. Это файл, который
+
* Запускаете компилятор GWT. Он читает клиентский код, создает HTML-странички (испoльзуя ваши шаблоны) и JavaScript-код, который будет связываться с сервером и выполнять запросы, которые были описаны ранее.
описывает, что нужно запускать, что будет сервером.
+
* Запускаете сервер GWT-приложений.
Запускаете компилятор GWT. Он читает клиентский код, создает
+
HTML-странички (испoльзуя ваши шаблоны) и JavaScript-код, который
+
будет связываться с сервером и выполнять запросы, которые были
+
описаны ранее.
+
Запускаете сервер GWT-приложений.
+
 
При этом вы не пишете ни строчки на JavaScript. HTML и CSS – да,
 
При этом вы не пишете ни строчки на JavaScript. HTML и CSS – да,
 
приходится, но опять же достаточно немного. Посмотрим подробнее?
 
приходится, но опять же достаточно немного. Посмотрим подробнее?
Строка 232: Строка 186:
 
Для начала стоит создать HTML-файл, который будет «заготовкой»
 
Для начала стоит создать HTML-файл, который будет «заготовкой»
 
для странички. Вот его код:
 
для странички. Вот его код:
<html>
+
<source lang="html4strict"><html>
 
<head><meta name=’gwt:module’ content=’phoneBook.PhoneBook’></
 
<head><meta name=’gwt:module’ content=’phoneBook.PhoneBook’></
 
head>
 
head>
Строка 247: Строка 201:
 
<div id=”main”></div>
 
<div id=”main”></div>
 
</body>
 
</body>
</html>
+
</html></source>
 
Обратите внимание, что ни одной кнопки нет. И таблицы нет. Зато
 
Обратите внимание, что ни одной кнопки нет. И таблицы нет. Зато
есть элементы, которые помечены id, в них-то и будут вставляться ком-
+
есть элементы, которые помечены id, в них-то и будут вставляться компоненты GWT, которые здесь называются виджетами.
поненты GWT, которые здесь называются виджетами.
+
 
Виджеты
+
==== Виджеты ====
 
Сами виджеты будут вставляться уже из «Java-кода». Почему в
 
Сами виджеты будут вставляться уже из «Java-кода». Почему в
кавычках? Просто это код только пишется на Java, но потом компи-
+
кавычках? Просто это код только пишется на Java, но потом компилируется в JavaScript и выполняется в браузере. Из-за этого есть множество ограничений. Например, нельзя использовать конструкции
лируется в JavaScript и выполняется в браузере. Из-за этого есть мно-
+
Java 5, такие как новые циклы foreach, аннотации, обобщенное программирование (generics) и другие. Нельзя использовать все классы
жество ограничений. Например, нельзя использовать конструкции
+
Java 5, такие как новые циклы foreach, аннотации, обобщенное про-
+
граммирование (generics) и другие. Нельзя использовать все классы
+
 
подряд – только те, для которых в GWT есть «реализация» (для java.
 
подряд – только те, для которых в GWT есть «реализация» (для java.
 
lang.* и java.util.* – есть, и это сильно упрощает дело).
 
lang.* и java.util.* – есть, и это сильно упрощает дело).
 
Код вставки виджетов выглядит примерно следующим образом:
 
Код вставки виджетов выглядит примерно следующим образом:
Button button = new Button(“Add new record”);
+
<source lang="java">Button button = new Button(“Add new record”);
RootPanel.get(“buttonCell”).add(button);
+
RootPanel.get(“buttonCell”).add(button);</source>
 
Первая строчка создает кнопку, вторая вставляет ее в элемент с id
 
Первая строчка создает кнопку, вторая вставляет ее в элемент с id
 
«buttonCell».
 
«buttonCell».
 +
 
Список виджетов достаточно велик, и можно также создавать свои
 
Список виджетов достаточно велик, и можно также создавать свои
собственные. Например, для вывода таблицы контактов можно исполь-
+
собственные. Например, для вывода таблицы контактов можно использовать FlexTable.
зовать FlexTable.
+
<source lang="java">FlexTable table = new FlexTable();</source>
FlexTable table = new FlexTable();
+
 
Этот виджет умеет динамически изменяться, например, вот этак:
 
Этот виджет умеет динамически изменяться, например, вот этак:
aTable.setText(aRow, aColumn, “Текст в ячейку”);
+
<source lang="java">aTable.setText(aRow, aColumn, “Текст в ячейку”);</source>
 
Этот код вставляет в ячейку таблицы текст. Можно также вставить
 
Этот код вставляет в ячейку таблицы текст. Можно также вставить
 
туда и другой виджет, например, так:
 
туда и другой виджет, например, так:
aTable.setWidget(aRow, aColumn, new Button(“Edit”));
+
<source lang="java">aTable.setWidget(aRow, aColumn, new Button(“Edit”));</source>
Для работы нужны не только виджеты, но и обработчики собы-
+
Для работы нужны не только виджеты, но и обработчики событий. Это тоже реализовано достаточно просто: через слушателей (см.
тий. Это тоже реализовано достаточно просто: через слушателей (см.
+
[[LXF92:Java EE|LXF92]]), как в Swing. Вот как, например, добавляется обработчик
LXF92), как в Swing. Вот как, например, добавляется обработчик
+
 
нажатия на кнопку:
 
нажатия на кнопку:
editButton.addClickListener(new ClickListener() {
+
<source lang="java">editButton.addClickListener(new ClickListener() {
 
public void onClick(Widget aWidget) {
 
public void onClick(Widget aWidget) {
 
код обработчика…
 
код обработчика…
 
}
 
}
}
+
}</source>
 
Есть, правда, и кардинальное отличие – в асинхронности. Для этого
 
Есть, правда, и кардинальное отличие – в асинхронности. Для этого
 
перейдем к сервисам.
 
перейдем к сервисам.
  
 
==== Сервисы ====
 
==== Сервисы ====
Для обработки клиентских запросов пишутся так называемые серви-
+
Для обработки клиентских запросов пишутся так называемые сервисы. Чтобы собрать сервис, создается два интерфейса (phoneBook.client.PhoneBookService и phoneBook.client.PhoneBookServiceAsync) и реализация (phoneBook.server.PhoneBookServiceImpl). В сервис выносятся методы, которые сервер выполняет по запросу клиента (у нас это добавление,
сы. Чтобы собрать сервис, создается два интерфейса (phoneBook.client.
+
PhoneBookService и phoneBook.client.PhoneBookServiceAsync) и реализа-
+
ция (phoneBook.server.PhoneBookServiceImpl). В сервис выносятся мето-
+
ды, которые сервер выполняет по запросу клиента (у нас это добавление,
+
 
удаление, редактирование записей и выдача списка записей).
 
удаление, редактирование записей и выдача списка записей).
 +
 
В «асинхронном» интерфейсе прописываются те же методы, что и
 
В «асинхронном» интерфейсе прописываются те же методы, что и
 
в «обычном», но с одним дополнительным параметром AsyncCallback
 
в «обычном», но с одним дополнительным параметром AsyncCallback
Строка 298: Строка 245:
 
вызов, выполнение кода (работа с пользователем) продолжается. А
 
вызов, выполнение кода (работа с пользователем) продолжается. А
 
когда работа асинхронного запроса завершается, вызывается этот
 
когда работа асинхронного запроса завершается, вызывается этот
обратный вызов, который сообщает клиенту: «Товарищ, задание пар-
+
обратный вызов, который сообщает клиенту: «Товарищ, задание партии выполнено, список пользователей доставлен».
тии выполнено, список пользователей доставлен».
+
 
Поэтому обработчики событий (например, кнопки удаления запи-
+
Поэтому обработчики событий (например, кнопки удаления записи) выглядят примерно следующим образом (показан только метод
си) выглядят примерно следующим образом (показан только метод
+
 
onClick соответствующего обработчика):
 
onClick соответствующего обработчика):
// вызов сервиса, второй параметр – это и есть обратный вызов,
+
<source lang="java">// вызов сервиса, второй параметр – это и есть обратный вызов,
 
// то есть то, что вызывается после выполнения запроса
 
// то есть то, что вызывается после выполнения запроса
 
PhoneBookService.App.getInstance().
 
PhoneBookService.App.getInstance().
Строка 319: Строка 265:
 
}
 
}
 
}
 
}
});
+
});</source>
  
 
==== Компиляция и запуск ====
 
==== Компиляция и запуск ====
Ранее я говорил про дескриптор. Он очень прост и выглядит пример-
+
[[Изображение:Img 95 85 1.png|thumb|Итог терзаний — все та же адресная книга и консоль на заднем плане.]]
но так:
+
Ранее я говорил про дескриптор. Он очень прост и выглядит примерно так:
<module>
+
<source lang="xml"><module>
 
<inherits name=’com.google.gwt.user.User’/>
 
<inherits name=’com.google.gwt.user.User’/>
 
<entry-point class=’phoneBook.client.PhoneBook’/>
 
<entry-point class=’phoneBook.client.PhoneBook’/>
<servlet path=’/PhoneBookService’ class=’phoneBook.server.
+
<servlet path=’/PhoneBookService’ class=’phoneBook.server.PhoneBookServiceImpl’/>
PhoneBookServiceImpl’/>
+
</module></source>
</module>
+
 
Чтобы скомпилировать GWT-код, нужно запустить класс com.
 
Чтобы скомпилировать GWT-код, нужно запустить класс com.
google.gwt.dev.GWTCompiler с параметром «полное имя класса, кото-
+
google.gwt.dev.GWTCompiler с параметром «полное имя класса, который нужно скомпилировать». Также можно указать параметр -out
рый нужно скомпилировать». Также можно указать параметр -out
+
 
«каталог, куда складывать результат».
 
«каталог, куда складывать результат».
 +
 
Запуск специальной оболочки для отладки осуществляется при
 
Запуск специальной оболочки для отладки осуществляется при
 
помощи класса com.google.gwt.dev.GWTShell, которому в качестве
 
помощи класса com.google.gwt.dev.GWTShell, которому в качестве
Строка 341: Строка 286:
 
Development Shell, можно узнать из рисунка – «вон он, змей, в окне
 
Development Shell, можно узнать из рисунка – «вон он, змей, в окне
 
маячит...»
 
маячит...»
Итог терзаний — все та же адресная книга и консоль
 
на заднем плане.
 
  
 
=== Ну, а все-таки, если делать самому? ===
 
=== Ну, а все-таки, если делать самому? ===
Строка 348: Строка 291:
 
технологии, связанных и с Java и с XMLHttpRequest’ом и с остальными
 
технологии, связанных и с Java и с XMLHttpRequest’ом и с остальными
 
ее компонентами.
 
ее компонентами.
 +
 
Во-первых, Java (точнее, серверная сторона). Тут проблема одна,
 
Во-первых, Java (точнее, серверная сторона). Тут проблема одна,
 
UTF-8. Почему-то некоторые браузеры не понимают UTF-8 в ответах.
 
UTF-8. Почему-то некоторые браузеры не понимают UTF-8 в ответах.
 
Safari, например. Есть достаточно простой обходной путь – выставлять
 
Safari, например. Есть достаточно простой обходной путь – выставлять
 
не совсем правильный, но работающий тип (Content-Type) содержимого ответа (response), «text/plain; charset=utf-8».
 
не совсем правильный, но работающий тип (Content-Type) содержимого ответа (response), «text/plain; charset=utf-8».
Далее – клиентская часть. Тут подводных камней больше. Во-пер-
+
 
вых, количество соединений: на сайт браузер разрешает обычно не
+
Далее – клиентская часть. Тут подводных камней больше. Во-первых, количество соединений: на сайт браузер разрешает обычно не
 
более двух. Поэтому «сделаем сразу 239 AJAX-запросов» не получится.
 
более двух. Поэтому «сделаем сразу 239 AJAX-запросов» не получится.
 
Один-два в параллели, и все.
 
Один-два в параллели, и все.
 +
 
Во-вторых, выше упоминалось про callback, вызываемый, когда
 
Во-вторых, выше упоминалось про callback, вызываемый, когда
идет процесс загрузки ответа с сервера. Как и сколько раз он вызыва-
+
идет процесс загрузки ответа с сервера. Как и сколько раз он вызывается – четко не определено. То есть нельзя надеяться, что он вызовется
ется – четко не определено. То есть нельзя надеяться, что он вызовется
+
 
с кодом события 4 ровно один раз.
 
с кодом события 4 ровно один раз.
В-третьих, на XMLHttpRequest не существует утвержденного стан-
+
 
дарта или рекомендации, а есть только черновой вариант W3C.
+
В-третьих, на XMLHttpRequest не существует утвержденного стандарта или рекомендации, а есть только черновой вариант W3C.
 
Поэтому реализации в разных браузерах различаются. Радует, правда,
 
Поэтому реализации в разных браузерах различаются. Радует, правда,
 
что не катастрофично.
 
что не катастрофично.
 +
 
Именно поэтому примеры приводятся с использованием сторонних
 
Именно поэтому примеры приводятся с использованием сторонних
библиотек. А если уж и нужно сделать «самому», то стоит восполь-
+
библиотек. А если уж и нужно сделать «самому», то стоит воспользоваться опытом и посмотреть их исходные тексты. В этом-то и сила
зоваться опытом и посмотреть их исходные тексты. В этом-то и сила
+
 
Open Source.
 
Open Source.
  

Версия 12:45, 16 декабря 2008

Содержание

А я? (кс)

ЧАСТЬ 6 Заинтригованы ребусом в заголовке? То ли еще будет, когда прочитаете статью – Александр Бабаев большой мастер загадывать загадки, особенно если речь заходит о Web 2.0.

Когда я начинал писать эту статью в первый раз, я думал, что все достаточно просто. Сел-написал-отдал. Но сразу после этого пришлось переделывать одно приложение, которое изменило понимание и сложности, и самого Аякса. Полностью. В чем же сложность? В несоответствии. С одной стороны, Аякс позволяет приблизить логику работы интернет-приложений к обычной, «десктопной». С другой стороны – все браузеры таки разные. И это последнее «таки» местами убивает наповал. Вы думаете, что браузеров три? IE/Firefox/Opera? Хех. Для правильного приложения их нужно протестировать десяток. IE 5.5/6/7, Firefox 1.5/2, Opera 8/9, Safari 1.3/2/ (а теперь и 3). И у каждого свой нрав.

Ладно, что же такое Аякс?

AJAX – технология асинхронного доступа к серверу с использованием JavaScript и XML. Представим себе автомобиль. Чтобы заправить его – едем на заправку, заправляем, уезжаем. Чтобы поменять фару – едем, снимаем, ставим, уезжаем. Вот это – AJAX. А если бы Аякса не было, то для каждой такой операции нужно было бы отдавать машину в сервис, а из сервиса возвращалась бы другая, хоть и максимально точная копия вашей, с обновлениями (бак заправлен). Асинхронность – это вообще что-то вроде дозаправки в воздухе. То есть обновление данных без «отрыва от просмотра страницы». Давайте подробнее рассмотрим компоненты этой технологии:

A

Асинхронность реализуется разными способами. XMLHttpRequest, фреймы, Flash. Есть и другие (те же апплеты), но они распространены меньше. Второй способ – самый «простой» для человека, знакомого с HTML. Создается ма-а-аленький iframe (одна точка) и помещается куда-нибудь далеко, чтобы не было видно. Потом при необходимости подгрузить что-либо, запрос выполняется как обычно, но с целевым фреймом – тем самым, маленьким. Во фрейм загружается страничка, на которой обычно есть скрипт, который выполняется и делает свое дело (обновляет основной фрейм). Flash – это примерно то же самое, только вместо маленького скрытого фрейма используется маленькая «флэшка».

Впрочем, обычно оба эти способа используются только в случае, если не подходит «основной» – XMLHttpRequest. Это название объекта в JavaScript, который может выполнять асинхронные (и синхронные) HTTP-запросы. Например:

var xmlHttpRequestValue = new XMLHttpRequest();
xmlHttpRequestValue.open(“POST”,/ajax.jsp?action=update”, true);
xmlHttpRequestValue.onreadystatechange = processXmlHttpResponse;
xmlHttpRequestValue.send(“Информация для пересылки серверу”);

Все, запрос ушел. Сразу предупрежу, что это не рабочий код, только иллюстрация. Обратите внимание на третью строчку. Выделенное жирным – это имя функции, которая будет обрабатывать события, генерируемые во время передачи запроса, такие, как «начат прием данных», «закончен прием заголовка», «закончен прием данных». Если мы хотим что-либо предпринять по окончании приема данных, эта функция будет выглядеть как-то так:

function processXmlHttpResponse() {
if (xmlHttpRequestValue.readyState == 4) {
…сделать «что-либо»…
}
}

Число «4» как раз обозначает, что обработка завершена. Функция processXmlHttpResponse() может вызываться много раз (даже точно не определено, сколько), но как только readyState станет равным 4, мы это «поймаем» и обработаем результат.

J

JavaScript – объектный язык. То есть создать класс, как в Java, в нем нельзя. А вот новый объект – запросто. И сформировать структуру объекта (прописать методы, поля) «на лету» тоже можно.

Чаще всего JavaScript используется как простой способ динамически изменять структуру документа. Например, чтобы поменять цвет параграфа, можно выполнить такой код:

document.getElementById(“paragraph”).style.color = “red”;

Параграф после этого покраснеет. Чтобы понимать, как добраться до отдельных параграфов, нужно изучить DOM (Document Object Model).

X

XML, который попал в AJAX последней буквой, используется (как уже упоминалось) далеко не всегда, но часто. Благо, в JavaScript есть возможности по достаточно простому преобразованию чего угодно в XML, да и в других языках (не только в Java) библиотеки по работе с этим форматом достаточно хорошо развиты.

Помощники

Из-за того, что реализации XMLHttpRequest различаются (в паре крупных деталей и, что хуже, в паре десятков мелочей), самому писать кросс-браузерную обработку достаточно тяжело и долго. Поэтому давайте посмотрим на библиотеки, в состав которых входит «AJAX-подсистема» и которые сделаны либо специально для Java-северной составляющей, либо поддерживают ее.

  • DOJO
    Огромная библиотека, которая много чего умеет. Если смотреть только на коммуникативные возможности, то тут тоже все в порядке: можно использовать XMLXttpRequest, фрейм, Flash. Первый вариант предлагается по умолчанию. Чуть ниже будет пример работы с DOJO, а сейчас просто отметим, что с учетом достаточно приличной документации, логичной организации и большого количества модулей (в том числе и для использования разных методов коммуникации), библиотеку можно назвать хорошей.
    DWR – Direct Web Remoting
    Сделана специально для Java. Достоинство состоит в том, что DWR умеет «публиковать» классы Java в JavaScript. То есть вы пишете класс в Java, настраиваете DWR (при помощи XML-дескриптора), и после запуска сервлета (обработкой запросов от DWR занимается отдельный сервлет) в JavaScript «появляются» методы этого класса, которые можно вызывать, так же, как если бы это были обычные функции JavaScript. Способ удобен, но навязывает определенный способ коммуникации. Подходит, когда не нужно контролировать каждый байт передаваемых данных и если с JavaScript вы знакомы не очень хорошо (хотя все равно его нужно знать, так как кроме коммуникации есть много чего еще).
    GWT – Google Web Toolkit
    В свое время эта библиотека наделала много шуму. Все дело в принципе ее работы. В общем и целом, если на DWR мы пишем на Java коммуникацию, то на GWT – все приложение. Затем GWT компилирует его в клиентскую часть (HTML + JavaScript) и серверную часть (Java). То есть клиент получается автоматически (не целиком, но близко к тому). GWT берет на себя все заботы и по взаимодействию клиента с сервером, и по созданию интерфейса (этот процесс несколько напоминает Swing), и многое другое. В принципе, достаточно хорошее решение, естественно со своими нюансами. Мы еще посмотрим на него поближе... к концу статьи.

Адресная книга с AJAX

Настало время потренироваться. Давайте возьмем нашу адресную книгу и сделаем так, чтобы показывалась страничка с табличкой (списком телефонов), а по нажатии на ссылки вместо перехода на новые странички менялся сам список: удалялись и добавлялись строки и так далее. Использовать будем DOJO. Идеология от этого не пострадает, но станет немного проще, короче и понятнее.

HTML/JavaScript

Вот строка HTML-таблицы, из которой видно, как будет выводиться список телефонов.

<tr id=1232323” >
<td>1232323</td><td>Vasya Beanov</td><td><td></td><td><a
href=”#” on click=”remove(‘1232323’); return false;”>Remove</a> / <a
href=”#” on click=”startEdit(‘1232323’); return false;”>Edit</a></td>
</tr>

Обратите внимание на id=”…”. Это своеобразные метки, которые позволят при необходимости найти нужную строку. Теперь рассмотрим JavaScript-код, который выполняется при нажатии на «кнопку» Edit (как самую сложную).

function startEdit(aPhone) {
getCell(aPhone, 0).innerHTML =<input type=”text” value =”’ +
getCell(aPhone, 0).innerHTML + ‘” id =”phone_’ + aPhone + ‘”/>;
getCell(aPhone, 1).innerHTML =<input type=”text” value = “’ +
getCell(aPhone, 1).innerHTML + ‘” id = “name_’ + aPhone + ‘”/>;
getCell(aPhone, 2).innerHTML =<input type = “text” value =”’ +
getCell(aPhone, 2).innerHTML + ‘” id =”comment_’ + aPhone + ‘”/>;
getCell(aPhone, 3).innerHTML =<a href = “#” onclick = “submitEdit(\’’
+ aPhone + ‘\’); return false;>Save changes</a>;
}

Простым русским языком этом можно выразить так: ячейки с текстом заменяются на ячейки с полями ввода.

После редактирования и нажатия на кнопку Save changes данные отсылаются на сервер, и в ячейках снова прописывается текст.

function submitEdit(aPhone) {
getCell(aPhone, 0).innerHTML = document.getElementById(‘phone_’ +
aPhone).value;
getCell(aPhone, 1).innerHTML = document.getElementById(‘name_’ +
aPhone).value;
getCell(aPhone, 2).innerHTML = document.getElementById(‘comment_’
+ aPhone).value;
getCell(aPhone, 3).innerHTML =<a href = “#” onclick = “startEdit(\’’ +
aPhone + ‘\’); return false;>Edit</a> <a href = “#” onclick = “remove(\’’
+ aPhone + ‘\’); return false;>Remove</a>;
sendAJAXRequest(“action=edit” +&old=+ aPhone +&phone=+ getCell(aPhone, 0).innerHTML +&name=+ getCell(aPhone, 1).innerHTML +&comment=+ getCell(aPhone, 2).innerHTML);
}

Теперь посмотрим, как отсылаются и принимаются данные. Для этого у нас есть показательная функция loadTable(), которая загружает табличку с сервера. Остальные функции только отправляют данные.

function loadTable() {
dojo.io.queueBind({
url :/ajax?action=loadTable”,
method : “get”,
load : function (aType, aData, aEvent) {
document.getElementById(“table”).innerHTML = aData;
},
preventCache : true
});
}

Обратите внимание на две вещи. Первая – использование dojo. queueBind – это местная реализация AJAX. Нам не нужно беспокоиться, что будет использоваться «внутри» (хотя контролировать внутренности тоже можно). Вторая – параметр load. Это функция, которая вызывается после загрузки данных с сервера (сами данные передаются в параметре aData). sendAJAXRequest выглядит абсолютно так же, только без параметра load.

Кстати, в queueBind’е сами параметры обрамлены фигурными скобками. Это как раз и есть объектность JavaScript. Тут создается объект с полями url, method, load и preventCache, и уже этот объект передается в качестве параметра функции.

Серверная часть

А теперь посмотрим, как это все обрабатывать на сервере. Логика его работы осталась той же: опять действия. Только вместо выдачи большого количества HTML-кода (через шаблоны или напрямую), в большинстве случаев не выдается ничего. Вот, например, код действия удаления:

String phone = aRequest.getParameter(“phone”);
_recordsBook.removeRecord(phone);

Только действие создания таблицы телефонов выдает код таблицы (но только ее, а не всю страничку). Остальные методы только получают данные и сохраняют их. Изменение таблицы происходит на клиенте при помощи JavaScript (как – можно посмотреть на код submitEdit выше или в полных исходных текстах на LXFDVD).

GWT

А что делать, если вы вообще ничего не понимаете в JavaScript? Не расстраиваться, скачать GWT (он немаленький, но и перспектива читать 1000 с лишним страниц талмуда под названием «JavaScript: The Definitive Guide» тоже не вдохновляет, ведь правда? К тому же архив можно найти и на нашем DVD), установить. А дальше?

Дальше процедура очень похожа на то, что позволяет делать, например, Ruby on Rails (или аналогичные каркасы – см. стр. XX):

  • Вы создаете некий код. Клиентский, серверный, шаблон странички. При необходимости также можно применять свои CSS-стили.
  • Затем создаете специальный XML-дескриптор. Это файл, который описывает, что нужно запускать, что будет сервером.
  • Запускаете компилятор GWT. Он читает клиентский код, создает HTML-странички (испoльзуя ваши шаблоны) и JavaScript-код, который будет связываться с сервером и выполнять запросы, которые были описаны ранее.
  • Запускаете сервер GWT-приложений.

При этом вы не пишете ни строчки на JavaScript. HTML и CSS – да, приходится, но опять же достаточно немного. Посмотрим подробнее?

Структура приложения GWT

Для начала стоит создать HTML-файл, который будет «заготовкой» для странички. Вот его код:

<html>
<head><meta name=’gwt:module’ content=’phoneBook.PhoneBook’></
head>
<body>
<script language=”javascript” type=text/javascript” src=”gwt.js”></
script>
<table>
<tr><td>Phone: </td><td id=”phoneCell”></td>
<td>Name: </td><td id=”nameCell”></td>
<td>Comment: </td><td id=”commentCell”></td>
</tr>
<tr><td colspan=”6” id=”buttonCell”></td></tr>
</table>
<div id=”main”></div>
</body>
</html>

Обратите внимание, что ни одной кнопки нет. И таблицы нет. Зато есть элементы, которые помечены id, в них-то и будут вставляться компоненты GWT, которые здесь называются виджетами.

Виджеты

Сами виджеты будут вставляться уже из «Java-кода». Почему в кавычках? Просто это код только пишется на Java, но потом компилируется в JavaScript и выполняется в браузере. Из-за этого есть множество ограничений. Например, нельзя использовать конструкции Java 5, такие как новые циклы foreach, аннотации, обобщенное программирование (generics) и другие. Нельзя использовать все классы подряд – только те, для которых в GWT есть «реализация» (для java. lang.* и java.util.* – есть, и это сильно упрощает дело). Код вставки виджетов выглядит примерно следующим образом:

Button button = new Button(“Add new record”);
RootPanel.get(“buttonCell”).add(button);

Первая строчка создает кнопку, вторая вставляет ее в элемент с id «buttonCell».

Список виджетов достаточно велик, и можно также создавать свои собственные. Например, для вывода таблицы контактов можно использовать FlexTable.

FlexTable table = new FlexTable();

Этот виджет умеет динамически изменяться, например, вот этак:

aTable.setText(aRow, aColumn, “Текст в ячейку”);

Этот код вставляет в ячейку таблицы текст. Можно также вставить туда и другой виджет, например, так:

aTable.setWidget(aRow, aColumn, new Button(“Edit”));

Для работы нужны не только виджеты, но и обработчики событий. Это тоже реализовано достаточно просто: через слушателей (см. LXF92), как в Swing. Вот как, например, добавляется обработчик нажатия на кнопку:

editButton.addClickListener(new ClickListener() {
public void onClick(Widget aWidget) {
код обработчика…
}
}

Есть, правда, и кардинальное отличие – в асинхронности. Для этого перейдем к сервисам.

Сервисы

Для обработки клиентских запросов пишутся так называемые сервисы. Чтобы собрать сервис, создается два интерфейса (phoneBook.client.PhoneBookService и phoneBook.client.PhoneBookServiceAsync) и реализация (phoneBook.server.PhoneBookServiceImpl). В сервис выносятся методы, которые сервер выполняет по запросу клиента (у нас это добавление, удаление, редактирование записей и выдача списка записей).

В «асинхронном» интерфейсе прописываются те же методы, что и в «обычном», но с одним дополнительным параметром AsyncCallback async. Это «Callback», обратный вызов. Когда делается асинхронный вызов, выполнение кода (работа с пользователем) продолжается. А когда работа асинхронного запроса завершается, вызывается этот обратный вызов, который сообщает клиенту: «Товарищ, задание партии выполнено, список пользователей доставлен».

Поэтому обработчики событий (например, кнопки удаления записи) выглядят примерно следующим образом (показан только метод onClick соответствующего обработчика):

// вызов сервиса, второй параметр – это и есть обратный вызов,
// то есть то, что вызывается после выполнения запроса
PhoneBookService.App.getInstance().
removeRecord(_phone, new AsyncCallback() {
public void onFailure(Throwable aThrowable) {
// ничего тут не будем делать
}
public void onSuccess(Object o) {
// удаляем строку из таблицы, соответствующую телефону
for (int i = 0; i < _table.getRowCount(); i++) {
if (_table.getText(i, 0).equals(_phone)) {
_table.removeRow(i);
break;
}
}
}
});

Компиляция и запуск

(thumbnail)
Итог терзаний — все та же адресная книга и консоль на заднем плане.

Ранее я говорил про дескриптор. Он очень прост и выглядит примерно так:

<module>
<inherits name=’com.google.gwt.user.User’/>
<entry-point class=’phoneBook.client.PhoneBook’/>
<servlet path=’/PhoneBookService’ class=’phoneBook.server.PhoneBookServiceImpl’/>
</module>

Чтобы скомпилировать GWT-код, нужно запустить класс com. google.gwt.dev.GWTCompiler с параметром «полное имя класса, который нужно скомпилировать». Также можно указать параметр -out «каталог, куда складывать результат».

Запуск специальной оболочки для отладки осуществляется при помощи класса com.google.gwt.dev.GWTShell, которому в качестве параметра передается путь к HTML-файлу запуска. Более подробные строки компиляции и запуска лучше посмотреть в примерах, которые поставляются вместе с самим GWT. А как выглядит Google Web Toolkit Development Shell, можно узнать из рисунка – «вон он, змей, в окне маячит...»

Ну, а все-таки, если делать самому?

Давайте поподробнее остановимся на некоторых подводных камнях технологии, связанных и с Java и с XMLHttpRequest’ом и с остальными ее компонентами.

Во-первых, Java (точнее, серверная сторона). Тут проблема одна, UTF-8. Почему-то некоторые браузеры не понимают UTF-8 в ответах. Safari, например. Есть достаточно простой обходной путь – выставлять не совсем правильный, но работающий тип (Content-Type) содержимого ответа (response), «text/plain; charset=utf-8».

Далее – клиентская часть. Тут подводных камней больше. Во-первых, количество соединений: на сайт браузер разрешает обычно не более двух. Поэтому «сделаем сразу 239 AJAX-запросов» не получится. Один-два в параллели, и все.

Во-вторых, выше упоминалось про callback, вызываемый, когда идет процесс загрузки ответа с сервера. Как и сколько раз он вызывается – четко не определено. То есть нельзя надеяться, что он вызовется с кодом события 4 ровно один раз.

В-третьих, на XMLHttpRequest не существует утвержденного стандарта или рекомендации, а есть только черновой вариант W3C. Поэтому реализации в разных браузерах различаются. Радует, правда, что не катастрофично.

Именно поэтому примеры приводятся с использованием сторонних библиотек. А если уж и нужно сделать «самому», то стоит воспользоваться опытом и посмотреть их исходные тексты. В этом-то и сила Open Source.

Вот и весь AJAX

В статье рассмотрен AJAX «по верхам». Тема безграничная, так как кроме технологии, использование AJAX меняет стиль и принципы работы web-приложений. Все то, как они работали до этого, должно быть переосмыслено на совершенно другом уровне. Дерзайте, и все получится. Клиенты будут довольны, а, следовательно, разработчики будут получать больше денег.

Персональные инструменты
купить
подписаться
Яндекс.Метрика