Статьи

Ajax и JSF, наконец-то присоединившиеся

В четвертой части этой серии о функциях JavaServer Faces (JSF) 2.0, предоставленных Red Hat или в которых разработчики Red Hat сыграли значительную роль, соавтор Дэн Аллен и я собираемся сосредоточиться на новой функциональности Ajax в JSF 2.0.   Мы рассмотрим примеры и объясним вдохновение.   Как и в остальной части этой серии, мы также дадим вам идеи и объяснения, которые вы можете не найти в других статьях или записях блога. 

Примечание редактора: JSF 2.0 доступен в AS6 M1 и будет поддерживаться Red Hat в JBoss Enterprise Application Platform в ближайшем будущем.

Прочитайте другие части этой серии статей:

Часть 1 —
JSF 2: Другой
путь к стандартизации в Seam
Часть 2 —
JSF 2 GETs Закладочные URL-адреса 

Часть 3 —
Свободная навигация в JSF 2

Часть 4 —
Ajax и JSF, присоединились наконец

Часть 5 —
Введение Поведение клиента JSF 2

 

Вступление

С чего начать с JSF и Ajax? Там, безусловно, есть история, которая читается как любовный роман. Вы находите JSF и думаете, что влюблены. Это добавляет структуру и стабильность к сумасшедшей сцене веб-разработки. Но вам не хватает того, чего вы жаждете: Ajax. Однако, еще не все потеряно, потому что вы найдете богатую библиотеку компонентов на стороне, такую ​​как RichFaces, которая удовлетворит ваш голод.   Конечно, это удобное расположение, но вы чувствуете, что используете его для Ajax.   Затем однажды JSF 2 выпускается, и вы сбиваетесь с ног. Истинное счастье наконец-то. В новый JSF встроен не только Ajax, но и другие библиотеки компонентов. Вы больше не застряли в одиноких отношениях! Фантазия сбылась.

 

Почему Аякс сейчас, а не раньше?

Несмотря на то, что Ajax сегодня повсеместно распространен, и вы не могли бы представить Интернет без него, все это было очень новым и революционным, когда были опубликованы первые две спецификации JSF. До того, как библиотеки компонентов Ajax начали появляться, использование Ajax с JSF, вероятно, означало неправильное использование JSF.

Ранние последователи JSF оказались в реальной ситуации, когда Ajax начал бить. Модель просто не поддерживала это. Эти разработчики пытались понять, как заставить JSF работать с Ajax.

Возможно, вы можете вспомнить создание функций JavaScript, которые будут эмулировать отправку JSF-формы, а затем вручную вставлять обновления страницы в страницу. При обратной передаче JSF будет полностью сбит с толку, потому что визуализированное представление не соответствует дереву компонентов (и появляются новые элементы формы). Это один из тех, «Я покажу вам мой страшный код JSF Ajax, если вы покажете мне свой». сценарии. Вот некоторые примеры:

 

invokeAction : function(targetDoc) {
this.mergeValues(targetDoc);
JSFUtils.invokeActionOnComponent(
targetDoc.getElementById("workspaceForm:addLineItem"));
},


<script type="text/javascript">
new Ajax.Autocompleter(
'workspaceForm:worksheet:#{index}:name',
'nameOptions_#{index}',
#{fn:encodeUrl("/ajax/auto_complete_values.jsf")}',
{paramName: 'q', onHide: function(element, update) {
new Effect.DropOut(update, {duration: 0.3}) }})
</script>

<h:inputText id="updatefields" immediate="true" onblur="updateTextFields(document.userForm, 'quota', this);" title="Update All Quotas" size="4"/>

/**
* Gather up form for sending over AJAX.
* 1. create hidden field with name of submitted button (to make JSF happy)
* 2. find all submit buttons and blank out the names (to prevent
* JSF from being confused)
* 3. use Form.serialize() to gather values and submit the Ajax request
*
* For links, might have to add to form to prevent a regular submit:
* onsubmit = function() { return false; }
* then run onclick(), then run Form.serialize()
*/

 

Очевидно, что нужны были более чистые решения, которые более естественно подходят для JSF, а не хаки, которые работали вокруг модели. Те же самые разработчики вскоре были завалены вариантами смешивания Ajax и JSF (см. Http://www.jsfmatrix.net/ ). Возникли некоторые замечательные идеи, такие как Ajax4jsf / RichFaces, ICEFaces и ADF Faces / Trinidad. В то время как было множество решений, казалось, что все шли по-другому, что привело к появлению дымоходов: выберите одну библиотеку, и вы застряли с ней, поскольку представление, вероятно, связано с этим механизмом Ajax.

Наличие такого количества сред JSF / Ajax является хорошим показателем того, что JSF обеспечивает прочную основу для Ajax. Но такие библиотеки, как Ajax4jsf, должны были обернуть запрос и создать вокруг него оболочку Ajax.   К счастью, разработчики из многих богатых библиотек компонентов работали вместе над группой экспертов JSF 2.0 и основной функциональностью Ajax.   Теперь разработчики могут получить доступ к базовой функциональности Ajax «из коробки» с помощью JSF 2.   То же ядро ​​позволит создавать библиотеки компонентов на основе и создавать библиотеки компонентов, которые могут взаимодействовать на одной странице.

 

Теперь, когда Ajax находится в JSF 2, как мне его использовать?

Достаточно истории и знакомств.   В этом разделе мы расскажем о сути и покажем несколько примеров новых функций.

Поддержка Ajax в JSF 2 предоставляется двумя основными способами.   Первый — это JavaScript API: jsf.ajax.request ().   Этот API-интерфейс обеспечивает стандартный мост для запросов Ajax и обеспечивает большой детальный контроль.   Второй — это новый тег с именем <f: ajax> .   С этим тегом вам вообще не нужно беспокоиться о JavaScript. Вместо этого вы можете использовать этот тег для декларативного добавления поведения Ajax в ваше приложение.

 

JavaScript API

Представьте, что вы можете загрузить библиотеку, подобную Prototype, и она просто поняла, как взаимодействовать с деревом компонентов JSF. Мы, теперь у вас есть один.   С новым JavaScript API в JSF 2 вы напрямую вызываете методы JavaScript, которые запускают запросы Ajax и частичную обработку жизненного цикла.   Это замечательно, когда вам требуется контроль уровня Ajax-запросов на уровне JavaScript или вы хотите выполнить собственный JavaScript-код вокруг запроса.

Вот пример использования JavaScript API для добавления Ajax-запроса к стандартной кнопке команды:

 

<h:form>
<h:outputScript name="jsf.js" library="javax.faces" target="head"/>

<h:panelGrid columns=”1”>

<h:inputText id="myinput" value="Text: #{userBean.name}"/> <h:outputText id="outtext" value="Echo: #{userBean.name}"/>

<h:commandButton id="submit" value="submit"
onclick="jsf.ajax.request(this, event, {execute:'myinput',render:'outtext'}); return false;" />

</panelGrid>
</h:form>

 

В этом примере, когда нажата командная кнопка, будет отправлен Ajax-запрос, инициирующий частичную обработку представления на сервере.   Свойство name для UserBean будет обновлено, и в ответе будет отображаться только часть дерева компонентов.   Когда запрос вернется, компонент outtext будет заменен в DOM клиента, а деревья клиента и сервера будут синхронизированы.

Давайте разберем важные части из примера выше.

Первое, что вы можете заметить, это тег <h: outputScript …> .   Это один из нового набора тегов в JSF 2, которые обрабатывают загрузку ресурсов (JavaScript, CSS, изображения и т. Д.).   Я не буду вдаваться в подробности, за исключением того, что этот тег регистрирует ресурс jsf.js и говорит реализации JSF поместить ссылку на скрипт для него в тег html <head>.   Чтобы использовать библиотеки JavaScript напрямую, вы должны включить эту разметку на своей странице.   В jsf.js файл JavaScript в JSF 2 , который содержит стандартизированную JavaScript API.

Настоящим примером этого примера является реализация события onclick командной кнопки .   Это фактический вызов метода, который будет запускать события Ajax.

 

jsf.ajax.request(this, event, execute:'myinput',render:'outtext'});

 

Этот метод принимает 3 параметра; источник, событие и параметры.   Для полного ознакомления с этим методом обратитесь к онлайн-документации по API JavaScript для пространства имен jsf.ajax .

  
source : элемент DOM, который вызвал запрос Ajax, обычно это .

  
событие (необязательно): событие DOM, которое вызвало этот запрос.   Это может быть использовано для получения дополнительных метаданных о событии, например, была ли нажата клавиша Shift.

  
параметры (необязательно): содержит набор пар имя / значение из следующей таблицы

Двумя наиболее важными параметрами являются исполнение и рендеринг .   Они представляют собой очень важные концепции в поддержке обработки частичного представления в JSF.   Частичная обработка представления — это новый механизм в JSF 2, который позволяет запускать жизненный цикл JSF на одном или нескольких поддеревьях компонентов.   Для целей Ajax эта обработка разбита на два этапа: выполнить (декодировать, проверить, обновить модель) и выполнить рендеринг. 

Когда Ajax-запрос отправляется на сервер, вы редко хотите, чтобы запрос обрабатывал все поля на странице. Выполнить атрибут позволяет указать JSF , какие компоненты должны быть обработаны во время запроса. Только идентифицированные компоненты будут проходить этапы проверки, преобразования и обновления модели. Поэтому важно обрабатывать любые компоненты, которые могут повлиять на ваш запрос. В нашем примере выше мы хотим, чтобы компонент myinput обрабатывался на сервере.       

С другой стороны, атрибут render указывает JSF, какая часть дерева компонентов должна быть визуализирована и заменена на клиенте при возврате ответа.   Для пользователя это та часть браузера, которая волшебным образом обновляется без обновления всей страницы.   Как и выполнить , вы редко хотите, чтобы вся страница отображалась.   В нашем примере мы хотим, чтобы компонент outtext отображался только после завершения запроса.

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

Давайте разместим эту информацию, чтобы использовать и модифицировать предыдущий пример.   Если у вас возникают проблемы с вызовом JavaScript для ваших запросов Ajax, вы можете также заставить Ajax автоматически запускаться при вводе пользователем.   Ниже тот же пример, что и выше, но без кнопки:

<h:form>
<h:outputScript name="jsf.js" library="javax.faces" target="head"/>

<h:panelGrid columns=”1”>
<h:inputText id="myinput" value="#{userBean.name}"
onkeyup="jsf.ajax.request(this, event, {render: 'outtext'}); return false;"/>

<h:outputText id="outtext" value="#{userBean.name}"!/>

</panelGrid>
</h:form>

 

Поэтому теперь каждый раз, когда пользователь вводит символ во входной текст, Ajax-запрос будет отправлен на сервер, а когда запрос вернет, будет обработан компонент outtext .   Обратите внимание, что нам не нужно устанавливать атрибут «execute».   Это потому, что значение по умолчанию для execute является @this .

Этот JavaScript API выполняет двойную функцию. Большую часть времени API будет использоваться библиотеками компонентов. Но пользователи могут использовать его для запуска собственных запросов Ajax, как вы уже видели. Эта гибкость означает, что вам больше не нужно выходить за пределы модели JSF, чтобы создавать собственные Ajax.   Например, библиотека ICEFaces может использовать это для реализации своих функций Direct-to-DOM.   Гибкость и желание взаимодействия библиотек компонентов, предоставляемые этим API, являются ключевыми.

Я знаю, что вы говорите, это здорово и все такое, но я действительно не хочу связываться с JavaScript.   Вы не единственный, кто так чувствует.   Вот почему JSF 2 предлагает декларативное решение «из коробки» в виде <f: ajax> , которое скрывает использование этого API. 

 

<Е: Аякс>

Как я уже упоминал выше, большинство пользователей стандартного JSF 2.0, вероятно, будут использовать тег <f: ajax>, чтобы они не беспокоились о JavaScript и могли по-прежнему иметь точный контроль над поведением своей страницы.   Любой, кто знаком с RichFaces и его тегом <a4j: support> , увидит очевидную корреляцию в поведении.   Фактически, тег поддержки был большим драйвером и источником вдохновения для тега <f: ajax> .   Архитектор RichFaces и член JSF EG Алекс Смирнов сыграли большую роль в определении этого тега и о том, как он должен работать.

Ниже я покажу вам те же примеры, что и выше, но вместо использования JavaScript API мы будем использовать тег <f: ajax> .   Как вы увидите, с помощью этого тега обычно гораздо проще присоединить функциональность Ajax.   Сначала мы рассмотрим пример с командной кнопкой, с поворотом.

 

<h:form>
<h:panelGrid columns=”1”>

<h:inputText id="myinput" value="Text: #{userBean.name}"/> <h:outputText id="outtext" value="Echo: #{userBean.name}"/>

<h:commandButton id="submit" value="submit">
<f:ajax execute=”@form” render=”outtext”/>
</h:commandButton>

</panelGrid>

</h:form>

 

Как вы можете видеть, это стало намного чище, а тег <f: ajax> позаботится обо всем тяжелом JavaScript.   В этом примере я использовал ярлык @form, чтобы каждый компонент родительской формы обрабатывался на сервере.   Как и прежде, мы также указываем, что внешний текст должен быть возвращен клиенту.   При нажатии кнопки запрос будет запущен, и страница обновится, как и раньше.

В следующем примере мы уберем кнопку и дублируем второй пример из раздела JavaScript API. 

 

<h:form>

<h:panelGrid columns=”1”>
<h:inputText id="myinput" value="#{userBean.name}">
<f:ajax event=”keyup” render=”outtext”/>
</h:inputText>

<h:outputText id="outtext" value="#{userBean.name}"!/>

</panelGrid>
</h:form>

 

Так что же здесь отличается?   Во-первых, нам не нужно устанавливать исполнение, потому что по умолчанию это @this .   Мы также устанавливаем атрибут события для тега.   Это клиентское событие родительского компонента, к которому привязывается поведение Ajax и которое инициирует запрос Ajax.   По умолчанию компоненты ввода вызывают <f: ajax>, когда пользователь меняет значение и покидает поле, но я хотел более отзывчивый пользовательский интерфейс, поэтому я решил использовать keyup .   Также обратите внимание , что вам нужно удалить на перед любым случаем вы хотите использовать.

У тега есть больше уловок в рукаве все же.   Вы можете обернуть тег <f: ajax> вокруг нескольких компонентов и дать поведение Ajax всем дочерним элементам одновременно.   Все дети будут использовать свои настройки по умолчанию и события, если вы не переопределите их специально.   Я продемонстрирую   это на примере из спецификации:

<f:ajax>
<h:commandButton id=”button1”>
<h:commandButton id=”button2”>
<f:ajax event=”mouseover”/>
</h:commandButton>
</f:ajax>

 

В этом примере к обеим кнопкам будет применено поведение Ajax по умолчанию.   В случае commandButton это будет при нажатии.   Однако только компонент button2 также будет запускать Ajax при наведении курсора мыши .   Это может быть полезно, когда вы хотите применить такое же поведение к группе компонентов, не вводя <f: ajax> для каждого тега.

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

 

Отлично, это здесь!   Теперь, как это работает?

В JSF 2 в жизненном цикле JSF появилась информация о запросе Ajax.   Большая часть этого понимания — PartialViewContext и функциональность посетителя дерева.   PartialViewContext отвечает за захват состояния, связанного с Ajax-запросом.   Это включает в себя то, что должно быть обработано на сервере, и то, что должно быть отображено на странице.   Функциональность посетителя дерева — это новый метод, visitTree () , в классе UIComponent .   Метод visitTree () позволяет легко перемещаться по подмножеству дерева компонентов в контексте текущего запроса. 

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

У JSF всегда была модель программирования, основанная на событиях, но более ранние версии имели недостаток в том, что предполагалось, что каждое событие должно обрабатываться сервером посредством традиционной операции POST. JSF 2.0 представил обновленный подход, который полностью осознает, что в уравнении есть две стороны, что не все события будут обрабатываться сервером и что может использоваться более эффективный метод связи между клиентом и сервером (Ajax), а не традиционный пост. Так что он умнее, экономнее и даже больше похож на фреймворки с графическим интерфейсом (на самом деле, они вызывают удаленные сервисы).

 

Частичная обработка дерева

Когда вы определяете значение execute в приведенных выше примерах, вы сообщаете JSF, какие сегменты дерева компонентов на стороне сервера должны проходить через жизненный цикл или фазы запроса JSF.   Дерево компонентов JSF предлагает сильную пригодность для обработки Ajax-запроса, подобного этому, потому что компоненты могут быть однозначно идентифицированы.   Это позволяет легко идентифицировать и обрабатывать отдельный компонент или целое поддерево.

Поэтому, когда вы устанавливаете параметр execute следующим образом:

 

<f:ajax execute=”@form” .../>

 

И API JavaScript на стороне клиента, и жизненный цикл на стороне сервера знают, что только компоненты в родительской форме должны пройти проверку, преобразование и   обновить модель.   Когда действия вызваны, значения, выраженные таким образом, будут там в ожидании. 

 

Частичные обновления страницы

Настоящая магия Ajax и заметный эффект, который в конечном итоге видят конечные пользователи, заключается в том, что части их браузера внезапно обновляются без перезагрузки всей страницы.   JSF 2.0 выполняет это очень похоже на то, что RichFaces делал в JSF 1.2 дня.   Как и атрибут execute, атрибут render указывает JSF, какие сегменты дерева компонентов JSF необходимо обработать (обработать) на этапе ответа визуализации.

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

Оказавшись на клиенте, JavaScript вступает во владение и находит соответствующие элементы DOM, которые обычно называются так же, как их близнецы на стороне сервера.   Затем код на стороне клиента отсекает элементы DOM, включая их дочерние элементы, и заменяет их новым содержимым из ответа.

 

Компоненты играют хорошо вместе

В этой статье я говорил о совместимости между наборами компонентов.   В конечном итоге это будет настоящий урожай JSF 2.0.   Общим ядром JavaScript Ajax API является большой аспект этого.   Если все библиотеки компонентов могут договориться и использовать одноядерный API, мы проделаем долгий путь к истинному взаимодействию.

Различные команды библиотек компонентов уже начали обсуждение того, как реализовать, протестировать и продемонстрировать эту возможность.   Мы стремимся к тому, чтобы разные библиотеки работали вместе на примере приложения Возможно, мы извлекаем таблицу данных из RichFaces, дерево из IceFaces, меню из ADF и сворачивающуюся панель из PrimeFaces. Этот тип приложения действительно будет делать несколько вещей. С одной стороны, это послужит доказательством и примером для разработчиков, что библиотеки компонентов JSF 2.0 действительно могут работать вместе. С другой стороны, это поможет всем нам избавиться от проблем и проблем, с которыми разработчики столкнутся при разработке спецификации.

Этот второй момент не следует недооценивать, и вот почему.   Найденные таким образом элементы представляют области реализации, которые могут привести к тому, что библиотеки компонентов не функционируют вместе, или указывают области в спецификации, которые нуждаются в большем определении.   Для разработчика JSF это означает, что библиотеки компонентов будут брать на себя большую часть риска разработки JSF для вас.   Когда эта работа будет завершена, и различные проекты выпустят свои интегрированные наборы компонентов JSF 2.0, разработчики JSF получат одну из крупнейших и наиболее продвинутых библиотек компонентов, доступных в веб-разработке.

 

Заворачивать

Если вы думаете, что все это аккуратно, подождите, пока вы не услышите о структуре поведения, на которой построен тег <f: ajax> .   Здесь работает основная концепция, которая проявляется в JSF 2.0 как новая концепция поведения компонентов.   Интересная вещь в поведении состоит в том, что они обобщают процесс, посредством которого функциональные возможности, как серверные, так и клиентские, могут быть присоединены к компонентам, а не только функциональные возможности, связанные с Ajax. Как только компонент может иметь привязанное к нему поведение, открывается дверь для присоединения всех видов новых поведений.   В следующей статье этой серии будет подробно рассмотрен механизм поведения.   В том числе, как создать свое собственное поведение, и некоторые возможные варианты использования для этого. 

Эта структура поведения является примером одной из точек расширения, которые были включены в спецификацию JSF 2.0.   Его предшественник, JSF 1.2, также позволял таким средам, как Facelets, Seam и RichFaces, расширять и улучшать функциональность.   Возможность поддержки расширений имеет решающее значение для успеха любой технологии.   Он позволяет усовершенствованиям пользователей по мере изменения технологий и требований — как они всегда делают, и JSF 2 имеет все возможности для поддержки этого роста.