Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ajax_v_deystvii.pdf
Скачиваний:
34
Добавлен:
05.03.2016
Размер:
5.83 Mб
Скачать

468 Часть IV. Ajax в примерах

Итак, мы сформировали все базовые функциональные возможности для рабочей системы портала, в том числе несколько элементов, которые классические Web-приложения просто не могли бы дать. Имеется еще несколько элементов, которые можно отнести к категории полезных, например, возможности добавления, удаления и переименования окон. Из-за ограниченного размера книги мы не будем их рассматривать. Впрочем, вы можете загрузить полный код приложения-портала, в котором можно добавлять, удалять, переименовывать и настраивать свойства окон, не покидая единственной страницы портала. Если у вас возникнут какие-либо вопросы, касающиеся приведенного кода, или вам потребуется более подробное его объяснение, вы всегда можете связаться с авторами через www.manning.com.

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

11.6. Реструктуризация

Как вы видели, концепция основанного на Ajax клиента портала, взаимо ] действующего с серверной частью портала, является довольно убедительной. ', В разделе, посвященном реструктуризации клиентской части кода мы рас- ] смотрим наш компонент как объект, выступающий в роли арбитра команд портала, отправляемых менеджеру портала на сервере. В процессе реструк- ] туризации мы постараемся выделить те части кода, которые могут со временем меняться, и максимально облегчить эти изменения. Поскольку портал ] представляет собой крулномодульный компонент, а мы в какой-то степени можем распоряжаться содержимым страницы, нас не ограничивает требо- ] вание не вмешиваться в HTML-разметку страницы (как в двух предыду- • щих проектах).

Однако, прежде чем рассматривать семантику клиентской части сценария, остановимся на контракте с сервером. Наша предыдущая реализация серверного кода была написана на Java, поэтому возможности аутентификации обеспечивал сервлетный фильтр(один сервлет возвращал конфигураЦИИ окна, второй — записывал конфигурации окна). Подобным образом, для добавления новых окон и удаления текущих мы создадим дополнительные автономные сервлеты. В Web-приложениях Java сервлеты можно достаточно гибко отобразить в URL; данная возможность определена в файле web.xml, содержащемся в загружаемом Web-архиве (.war). Например, функция Se- I lectServlet, возвращающая сценарий, определяющий исходные окна, была отображена в URL portalLogin.servlet.

Одним из достоинств инфраструктуры Ajax является слабая связь между клиентом и сервером. В нашем примере портала в качестве внутреннего интерфейса используется Java, но нам совсем не обязательно привязываться к таким особенностям Java, как сервлетные фильтры и гибкая перезапись URL. Альтернативная внутренняя архитектура может ис-

Глава 11. Улучшенный Web-портал Ajax

469

пользовать диспетчер запросов, при которой единственный сервлет (страница РНР или ресурс ASP.NET) принимает все входящие запросы, а затем считывает параметр, задающий тип выполняемого действия (специфика передачи параметра определяется методом: GET или POST). Например, строка параметров для входа на портал может выглядеть как асtion=login&userid=userspassword=password. Используя Java, мы можем реализовать подход с помощью диспетчера запросов, присваивая определенный префикс URL, например .portal, сервлету диспетчера, что позволит записывать такие URL, как login.portal.

В реструктуризированном компоненте мы обобщим предположения относительно внутренней архитектуры, разрешив либо архитектуру диспетчера запросов, либо вариант с множественными адресами, использованный в реализации Java. Тем не менее от нас не требуется полная гибкость, поэтому мы предопределим набор команд, предположительно понятных для внутренней архитектуры портала и охватывающих регистрацию, отображение для пользователя окон портала, а также добавление и удаление окон из портала. Учитывая указанные изменения серверной части приложения, вернемся к реализации клиентской части.

Обсуждение реструктуризации портала начнем с переопределения контракта использования с точки зрения HTML-кода страницы, а затем приступим к реализации. Напомним, что введение HTML-страницы в сценарий портала происходит посредством регистрации, а точнее — с помощью кнопки входа в систему.

<input type="button" name="btnSub" value="login" onclick="LoginRequest(tquotelogintquote)">

Мы изменили обработчик события onclick, теперь это вызов функции, которая будет использовать наш компонент-портал. Предположим, что этот компонент обрабатывается с помощью сценария, выполняемого после загрузки. Характерный пример того, как это должно выглядеть, приведен в листинге 11.13.

Листинг 11.13. Создание портала и вход в систему

function createPortal() { myPortal = new Portal(

/ / О Основной URL портала tquoteportalManagertquote,

{

// © Необязательные параметры

messageSpanld: tquotespanprocessingtquote, urlSuffix: tquote.portaltquote }) ;

//© Вызвать для загрузки окон myPortal.loadPage(Portal-LOAD_SETTINGS_ACTION);

document.getElementById(tquoteusernametquote).focus{) ;

}

function login() { myPortal.login(document.getElementByld(tquoteusernametquote).value,

document.getElementById(tquotepasswordtquote).value);

470Часть IV. Ajax в примерах

Втакой семантике использования функция createportal (), которая должна вызываться сразу после загрузки страницы, создает экземпляр компонента портала. Первый ее аргумент — это основной URL серверного приложения портала О, второй предоставляет необязательные параметры, используемые для ее настройки под конкретный контекст 0. В данном случае мы сообщаем функции идентификатор элемента DOM, в который следует записывать сообщения о состоянии, и имя параметра запроса, который определит совершаемое действие. После создания на портале вызывается API loadPage, загружающий окна портала, если в сеансе сервера присутствует регистрационное имя пользователя ©. Если в систему никто не входил, сервер возвращает пустой сценарий, оставляя на экране только форму регистрации.

Функция login () представляет собой вспомогательную функцию, вызывающую метод login {) компонента портала, передающую в качестве аргументов имя пользователя и пароль. Согласно данному контракту обработчик событий onclick кнопки регистрации вызывает метод login () страницы.

<input type="button" name="btnSub" value="login" onclick="login()">

11.6.1. Определение конструктора

Разобравшись с использованием компонента с точки зрения страницы, займемся реализацией логики. Начнем с конструктора.

function Portal( baseUrl, options ) { this.basellrl = baseUrl;

this.options - options; this.initDocumentMouseHandler();

В качестве первого аргумента приведенный конструктор принимает URL средства управления порталом Ajax на сервере, а в качестве второго — объект опций, используемый при определении конфигураций. Напомним, что в первом варианте данного сценария использовался сервлетный фильтр и два сервлета, выполняющих внутреннюю обработку. Далее мы будем предполагать, что все запросы к внутренней части портала будет перехватывать один сервлет, или ресурс portalManager (см. листинг 11.13). Если нам требуется сконфигурировать портал с учетом внутренней архитектуры, не использующей единственный диспетчер запросов, мы можем передать конструктору различные аргументы, например:

myPortal = new Portal( tguotedatatquote,

{ messageSpanld: tquotespanProcessingtquote, urlSuffix: tquote.phptquote }

);

Таким образом, мы передадим основной URL "данных" и, поскольку в массиве опций определен параметр actionParam, добавим к пути URL команду с суффиксом .php, получая в результате URL, подобный data/login, php. Следовательно, мы получаем всю необходимую на данный момент гибкость. Вопрос превращения опций в URL будет рассмотрен в разделе 11.6.3. Сейчас же мы перейдем к следующему заданию. Итак, из по-

Гпава 11. Улучшенный Web-портал Ajax 471

следней строки конструктора следует необходимость адаптации библиотеки AjaxWindows.js.

11.6.2. Адаптация библиотеки AjaxWindows.js

Напомним, что реализация данного портала использует внешнюю библиотеку AjaxWindows.js для создания отдельных окон портала и управления их размером и положением на экране. В связи с этим нам, в частности, требуется адаптировать библиотеку для отправки запросов Ajax менеджеру портала, чтобы записать настройки после события mouseup. Мы отслеживаем данное действие потому, что теоретически им заканчиваются все операции перемещения и изменения размеров. Первое, что мы сделали для выполнения данной адаптации, — скопировали код библиотеки AjaxWindows.js и изменили в нем фрагмент, помещающий в документ обработчик событий mouseup. Если рассматривать библиотеку AjaxWindow.js как продукт стороннего производителя, то недостатки данного подхода очевидны. Мы отошли от кода чужой библиотеки, т.е. модифицировали исходный код и поведение библиотеки так, что они перестали быть совместимыми с версиями, поддерживаемыми авторами библиотеки. Если библиотека изменится, нам придется согласовывать его со своими изменениями при выходе каждой следующей версии. Мы ничего не сделали, чтобы изолировать место изменения и сделать его как можно более "безболезненным". Поэтому рассмотрим менее радикальный подход к адаптации и выясним, можно ли как-то исправить данную ситуацию. Напомним, что последняя строка конструктора выглядела следующим образом:

this . initDocumentMouseHandler();

Метод initDocumentMouseHandler () представляет оперативную адаптацию библиотеки AjaxWindows.js. Он, как и ранее, просто перезаписывает обработчик document.onmouseup, но делает это уже в нашем собственном коде. Теперь логика, требуемая для адаптации внутри метода портала handleMouseUp(), реализована в нашем методе (листинг 11.14).

Листинг 11.14. Адаптация обработчика AjaxWindows.js

initDocumentMouseHandler: function() { var oThis = this;

document.onmouseup = function() { oThis.handleMouseUp(); };

Ь

handleMouseUp: function() { bDrag = false;

bResize = false; intLastX = -1;

document.body.style.cursor = "default"; if { elemWin && bHasMoved )

this.saveWindowProperties(elemWin.id); bHasMoved = false;

Ь

.

__Л

 

 

 

 

Это решение уже гораздо лучше, но это еще не все. Если библиотека AjaxWindows.js определяет обработчик mouseup в именованной, а не в ано-

472 Часть IV. Ajax в примерах

нимиой функции, то этот обработчик можно сохранить под другим именем и вызывать из нашего собственного обработчика. Таким образом, мы не будем дублировать логику, уже определенную в библиотеке AjaxWindows.js. Данный подход иллюстрируется в приведенном ниже коде.

function ajaxWindowsMouseUpHandler() { // logic here ...

}

document.onmouseup = ajaxWindowsMouseUpHandler;

Функция ajaxWindowsMouseUpHandler () представляет собой обратный вызов, определенный внешней библиотекой AjaxWindows.js. Как показано ниже, ее применение позволит сохранить определение метода и использовать его позже.

initDocumentMouseHandler: function() {

this.ajaxWindowsMouseUpHandler = aj axWindowsMouseUpHandler;

// О Сохранить

нашу собственную ссылку

v a r oThis =

t h i s ;

document.onmouseup = f u n c t i o n ( ) { oThis . handleMouseUp(); };

Ь

//© Вызвать библиотечную функцию handleMouseUp: function() {

this.aj axWindowsMouseUpHandler() ;

//© Добавить функциональные возможности Ajax if { elemWin && bHasMoved )

this.saveWindowProperties(eleraWin.id) ;

>,

Теперь наш метод handleMouseUp () не должен дублировать функциональные возможности библиотеки AjaxWindows.js. Необходимые возможности мы вызываем © посредством записанной ссылки О, а затем добавляем функциональные возможности Ajax ©. Если же обработчик mouseup библиотеки Ajax Windows в будущем изменится, то эти изменения не потребуют модификации нашего кода. Это уже более приятная ситуация с точки зрения управления изменениями. Разумеется, она предполагает, что подразумеваемый контракт с библиотекой не изменится — имеются в виду две глобальные переменные, elemWin и HasMoved. Поскольку в текущий момент библиотека определяет обработчик mouseup как анонимную функцию, мы по-прежнему можем записать ссылку на существующую функцию обработки события mouseup, используя следующую строку кода:

this.ajaxWindowsMouseUpHandler - this.document.onmouseup;

Таким образом, мы добиваемся того же результата, что и ранее, но теперь решение гораздо изящнее, поскольку в данной ситуации контракт гораздо слабее. Приведенное решение основывается на том, что мы включили наши эиблиотеки сценария в правильном порядке, т.е. библиотека AjaxWindows.js уже выполнила код, помещающий в документ обработчик mouseup. Кроме то- ^о, предполагается, что никакая другая библиотека не поместила в документ зругой обработчик событий mouseup или реализовала другой интерфейсный подход, подобный нашему.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]