LXF95:Java EE
Maximax (обсуждение | вклад) (Новая: {{Цикл/Java EE}}) |
Yaleks (обсуждение | вклад) (uncomplete) |
||
Строка 1: | Строка 1: | ||
{{Цикл/Java EE}} | {{Цикл/Java EE}} | ||
+ | == А я? (кс) == | ||
+ | ''ЧАСТЬ 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; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | ==== Компиляция и запуск ==== | ||
+ | Ранее я говорил про дескриптор. Он очень прост и выглядит пример- | ||
+ | но так: | ||
+ | <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 === | ||
+ | {{Врезка | ||
+ | |Заголовок=Ссылки и интересные статьи | ||
+ | |Содержание= | ||
+ | * DOJO: http://dojotoolkit.org, | ||
+ | * DWR: http://getahead.org/dwr, | ||
+ | * GWT: http://code.google.com/webtoolkit/, | ||
+ | * Статья про GWT от IBM developerWorks: http://www.ibm.com/developerworks/ru/library/j-AJAX4/index.html. | ||
+ | |Ширина=200px}} | ||
+ | В статье рассмотрен AJAX «по верхам». Тема безграничная, так как | ||
+ | кроме технологии, использование AJAX меняет стиль и принципы | ||
+ | работы web-приложений. Все то, как они работали до этого, должно | ||
+ | быть переосмыслено на совершенно другом уровне. Дерзайте, и все | ||
+ | получится. Клиенты будут довольны, а, следовательно, разработчики | ||
+ | будут получать больше денег. |
Версия 23:47, 15 декабря 2008
|
|
|
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
Содержание |
А я? (кс)
ЧАСТЬ 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>
Phone: | Name: | Comment: | |||
</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; } } } });
Компиляция и запуск
Ранее я говорил про дескриптор. Он очень прост и выглядит пример- но так: <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
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
В статье рассмотрен AJAX «по верхам». Тема безграничная, так как кроме технологии, использование AJAX меняет стиль и принципы работы web-приложений. Все то, как они работали до этого, должно быть переосмыслено на совершенно другом уровне. Дерзайте, и все получится. Клиенты будут довольны, а, следовательно, разработчики будут получать больше денег.