Статьи

Свободная навигация в JSF 2

В этой статье, третьей из серии, посвященной функциям JavaServer Faces (JSF) 2.0, предоставленной Red Hat, или в которой Red Hat активно участвовал, вы узнаете, что обход в приложении JSF 2 намного проще и требует меньше ввода текста. Благодаря улучшенной поддержке запросов GET и возможности закладок, о которых говорилось в предыдущей статье, JSF 2 стала более гибкой. Но не за счет хорошего дизайна. JSF больше не нужно вторгаться в ваши бизнес-объекты, требуя методы действий для возврата результатов навигации, но вместо этого может отражать состояние системы при выборе варианта навигации. Эта статья должна дать вам оценку того, насколько интеллектуальной стала навигационная система в JSF 2.

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

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

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

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

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

 

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

Неявная навигация особенно полезна для разработки прототипов приложений, где правила навигации просто мешают. Этот стиль навигации интерпретирует результаты навигации как идентификаторы представления. По мере того как вы выходите за рамки прототипирования, условная навигация удаляет связь между сетью и транзакционным уровнем, потому что обработчик навигации извлекает информацию из ваших бизнес-компонентов, чтобы выбрать вариант навигации. Упреждающая навигация, с которой вы познакомились в прошлой статье, может использовать неявную навигацию или декларативные правила навигации для создания закладок URL во время рендеринга. Использование системы навигации для создания закладок URL-адресов позволяет JSF добавлять поддержку GET при сохранении согласованных, централизованных правил навигации.

Даже с этими новыми опциями невозможно сказать, какие требования может предъявлять ваше приложение к навигации. Таким образом, в JSF 2 вы можете, наконец, запрашивать и изменять варианты навигации; В JSF 2 был представлен новый API, который предоставляет набор правил навигации. Прежде чем мы перейдем к настройкам, давайте выясним, как эти новые варианты делают навигационную систему более гибкой и помогают подготовить следующий шаг пользователя. Надеюсь, вам не понадобятся эти настройки в конце концов.

Гибкие возможности навигации

Декларативная навигационная модель в JSF была отходом от явного выбора навигации «вперед» действием в Struts. Навигационные переходы в JSF, которые сопоставляются на основе текущего идентификатора представления, логического результата и / или сигнатуры выражения действия, описываются в дескрипторе JSF (face-config.xml) с использованием правил на основе XML. Соответствующий переход указывает на следующее представление для рендеринга и должен ли перенаправление на стороне клиента продолжать рендеринг. Вот типичный пример:

<navigation-rule>
<from-view-id>/guess.xhtml</from-view-id>
<navigation-case>
<from-action>#{numberGuessGame.guess}</from-action>
<from-outcome>correct</from-outcome>
<to-view-id>/gameover.xhtml</to-view-id>
</navigation-case>
</navigation-rule>

Хотя навигационная модель JSF более четкая и, возможно, более гибкая, чем в Struts, остаются две фундаментальные проблемы. Во-первых, метод действия по-прежнему требуется для возврата навигационной директивы. Директива просто оказывается более «нейтральным» строковым результатом, а не явным типом (т.
Е. ActionForward ), но связь такая же тесная, и вы теряете безопасность типов в процессе, так действительно ли это улучшение? Другая проблема заключается в том, что вы должны определить вариант навигации, соответствующий этому результату, даже в самых простых случаях, которые могут быть очень утомительными. Таким образом, вы не можете утверждать, что навигационная модель менее навязчива или более удобна. Это просто застряло где-то посередине.

Подводя итог, навигационная модель JSF недостаточно гибкая. Он должен лучше соответствовать различным стилям разработки и быть более самодостаточным. С одной стороны, ваш стиль или фаза разработки могут диктовать отказ от декларативной абстракции правила навигации. С другой стороны, вы можете полностью отделить бизнес-объекты от модели навигации, исключив эти произвольные директивы возвращаемого значения. JSF 2 предоставляет вам широкий спектр возможностей, и даже позволяет вам довольствоваться счастливой средой. Первый вариант обеспечивается неявной навигацией, а второй — условной навигацией. С неявной навигацией вы можете даже использовать текущую модель без необходимости сразу определять правило навигации. Давайте распакуем эти две новые альтернативы, начиная с неявной навигации.

Неявная навигация

JSF будет публиковать форму обратно в текущее представление (используя метод POST HTTP) всякий раз, когда пользователь выполняет действие, такое как нажатие кнопки команды (отсюда и термин «обратная передача»). Раньше единственный способ заставить JSF перейти в другое представление после вызова действия (т. Е. После фазы приложения Invoke) — это определить случай навигации в файле face-config.xml. Случаи навигации сопоставляются на основе EL-сигнатуры вызванного метода действия и возвращаемого значения метода, преобразованного в строку (логический результат). Чтобы привести пример, предположим, что пользователь нажимает кнопку, определенную следующим образом:

<h:commandButton action="#{commandHandler.preview}" value="Preview"/>

Метод
preview () в компоненте с именем
commandHandler возвращает значение, указывающее результат обработки:

public String preview() {
// tidy, translate and/or validate comment
return "success";
}

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

<navigation-rule>
<from-view-id>/entry.xhtml</from-view-id>
<navigation-case>
<from-action>#{commentHandler.preview}</from-action>
<from-outcome>success</from-outcome>
<to-view-id>/previewComment.xhtml</to-view-id>
</navigation-case>
</navigation-rule>

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

Быстрый способ, который присутствует в Seam, заключается в том, чтобы метод действия просто возвращал идентификатор целевого представления напрямую. В этом случае вы фактически рассматриваете значение логического результата как идентификатор представления. Этот метод был принят в JSF 2 как неявная навигация. Он улучшен после Seam, потому что вы можете удалить расширение представления (например, .xhtml), и JSF автоматически добавит его обратно для вас при поиске идентификатора представления. Следовательно, он не более инвазивен, чем исходные значения строки, которые вы в настоящее время возвращаете.

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

  1. Обнаружить наличие? персонаж в логическом исходе
    1. Если есть, захватите параметры строки запроса, которые следуют за ним? характер
    2. Специальный параметр строки запроса Face-Redirect = True указывает, что эта навигация должна быть выполнена с использованием перенаправления на стороне клиента
  2. Если логический результат не заканчивается расширением файла, добавьте расширение файла текущего идентификатора представления (например, .xhtml)
  3. Если логический результат не начинается с /, добавьте местоположение текущего идентификатора представления (например, /, / admin / и т. Д.)
  4. Попытка найти шаблон для идентификатора представления

    1. Если шаблон найден, создайте виртуальный случай навигации, который нацелен на идентификатор разрешенного представления.
    2. Если шаблон не найден, пропустите неявную навигацию
  5. Выполнить навигационный кейс

    1. Если случай навигации не является перенаправлением, создайте и визуализируйте целевое представление в том же запросе
    2. Если в качестве случая навигации используется перенаправление, создайте URL-адрес перенаправления, добавив параметры строки запроса, полученные ранее, и перенаправьте на него

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

  • Возвращаемое значение метода действия
  • Атрибут action компонента UICommand (например, <h: commandButton action = «/ records.xhtml» …> )
  • Атрибут исхода UIOutcomeTarget (например, <h: link result = «/ records.xhtml» …> )
  • Метод handleNavigation () API NavigationHandler

Вот пример перехода к представлению предварительного просмотра, переведенному в неявную навигацию. Возвращаемое значение автоматически украшается начальным / и конечным .xhtml.

public String preview() {
// tidy, translate and/or validate comment
return "previewComment";
}

Представление /previewComment.xhtml будет отображено в том же запросе. Если вы хотите перенаправить сначала, добавьте следующий флаг в строку запроса возвращаемого значения:

public String preview() {
// tidy, translate and/or validate comment
return "previewComment?faces-redirect=true";
}

Вы можете выполнить любой сценарий навигации, используя неявную навигацию, которую вы можете сделать сегодня, с формальным случаем навигации, определенным в Face-config.xml Неявная навигация спроектирована как случай сбоя (после ознакомления с правилами явной навигации). Если происходит сбой (т. Е. Шаблон не может быть найден ), и JSF 2
ProjectStage устанавливается на разработку, автоматически генерируется FacesMessage, чтобы предупредить разработчика о возможной ошибке программирования.


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

Условная навигация

Неявная навигация подчеркивает, насколько инвазивным является возложение бремени на ваш бизнес-объект, чтобы вернуть логический результат, просто чтобы сделать навигацию JSF счастливой (и работающей). Такое связывание особенно проблематично, когда вы хотите реагировать на события пользовательского интерфейса, используя компоненты вашего бизнес-уровня — упрощенную архитектуру, поддерживаемую как в Seam, так и в Java EE 6, чтобы уменьшить количество связующего кода без увеличения связывания.

Что было бы более «логичным», так это инвертировать элемент управления и попросить обработчик навигации проверить состояние компонента, чтобы определить, какой вариант навигации подходит. Навигация становится контекстной, а не статичной. Вот что дает вам условная навигация.

Условная навигация вводит условие как новый критерий соответствия в случае навигации. Это’
определены в
Элемент <if> является дочерним элементом для
<navigation-case> и выражается с использованием выражения значения EL. Выражение значения оценивается каждый раз, когда рассматривается случай навигации. Для любого случая навигации, который соответствует, если условие определено, условие должно иметь значение true, чтобы случай навигации считался совпадением.

Вот пример случая условной навигации:

<navigation-case>
<from-action>#{registration.register}</from-action>
<if>#{currentUser.registered}</if>
<to-view-id>/account.xhtml</to-view-id>
<redirect/>
</navigation-case>

Как видите, условие не обязательно должно ссылаться на свойство вызываемого компонента. Это может быть любое состояние, достижимое EL.

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

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

<navigation-case>
<from-action>#{identity.login}</from-action>
<if>#{currentUser.admin}</if>
<to-view-id>/admin/home.xhtml</to-view-id>
<redirect/>
</navigation-case>
<navigation-case>
<from-action>#{identity.login}</from-action>
<if>#{currentUser.vendor}</if>
<to-view-id>/vendor/home.xhtml</to-view-id>
<redirect/>
</navigation-case>
<navigation-case>
<from-action>#{identity.login}</from-action>
<if>#{currentUser.client}</if>
<to-view-id>/client/home.xhtml</to-view-id>
<redirect/>
</navigation-case>

Если вы намереваетесь просто сопоставить нулевой результат в любом случае, вы можете использовать условие, которое является истинно истинным (которое, по общему признанию, могло бы быть улучшено в JSF 2.1):

<navigation-case>
<from-action>#{identity.logout}</from-action>
<if>#{true}</if>
<to-view-id>/home.xhtml</to-view-id>
<redirect/>
</navigation-case>

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

Но подождите, это еще не все! Необходимость перечисления всех возможных маршрутов с использованием отдельных случаев навигации приводит к смерти по XML (довольно болезненная смерть). Что, если вы хотите делегировать решение бину помощника навигации или использовать язык сценариев? Есть хорошие новости. Ты сможешь! Идентификатор целевого представления можно разрешить из выражения значения EL. Вернемся к примеру входа в систему и используем вспомогательный компонент для маршрутизации пользователя с использованием одного случая навигации:

<navigation-case>
<from-action>#{identity.login}</from-action>
<to-view-id>#{navigationHelper.userHomeViewId}</to-view-id>
<redirect/>
</navigation-case>

Боже мой, насколько это лучше? Помощник по навигации может инкапсулировать логику проверки
bean- компонента currentUser и определения правильного идентификатора целевого представления.

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

 

Предвидя следующий ход пользователя


До этого момента обработчик навигации включается только при обратной передаче.
Поскольку события пользовательского интерфейса инициируют «обратную передачу» к текущему представлению, как упоминалось ранее, обработчик навигации запускается после фазы вызова приложения, чтобы направить пользователя к следующему представлению. JSF 2 представляет совершенно новый способ использования обработчика навигации, оценивая правила навигации на этапе ответа на визуализацию. Эта оценка времени рендеринга называется преимущественной (или заранее определенной) навигацией.
 

Упреждающая навигация

Спецификация определяет упреждающую навигацию как механизм определения целевого URL в ответе рендеринга, обычно для компонента гиперссылки. Идентификатор текущего представления и заданный результат используются для определения идентификатора целевого представления, который затем преобразуется в URL-адрес для закладки и используется в качестве цели гиперссылки. Этот процесс, конечно, происходит до того, как пользователь активировал компонент (например, нажмите на гиперссылку). Фактически, пользователь может никогда не активировать компонент. Идея состоит в том, чтобы объединить декларативную (или неявную) навигационную модель с поддержкой создания закладок.

Основываясь на только что описанном, вы должны теперь понять, почему вы объявляете идентификатор целевого представления в атрибуте с именем
resultна новых закладочных компонентных тегах (и почему эти компоненты наследуются от класса компонентов с именем
UIOutcomeTarget ). Вы не нацеливаетесь непосредственно на идентификатор представления, а скорее на результат навигации, который может интерпретироваться как идентификатор представления, если сопоставление проваливается на неявную навигацию.

Давайте рассмотрим пример. Предположим, что вы хотите создать ссылку на домашнюю страницу приложения. Вы можете определить ссылку, используя один новый закладочный компонент ссылки:

<h:link outcome="home" value="Home"/>

Это определение будет соответствовать следующему случаю навигации, если он существует:

<navigation-rule>
<from-view-id>*</from-view-id>
<navigation-case>
<from-outcome>home</from-outcome>
<to-view-id>/home.xhtml</to-view-id>
</navigation-case>
</navigation-rule>

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

<a href="/app/home.jsf">Home</a>

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

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

  

Построение строки запроса

Благодаря новой поддержке GET в JSF 2 теперь существует множество способов привязать значения к строке запроса. Опции могут столкнуться при переходе в навигационную воронку. Что выходит на другую сторону? Есть простой алгоритм разрешения конфликтов, который нужно выяснить. Каждый параметр источника имеет приоритет. Когда возникает конфликт, то есть два источника определяют одно и то же имя параметра, используется параметр из источника с наивысшим приоритетом.

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

  1. Неявный параметр строки запроса (например, /blog.xhtml?id=3)
  2. Параметр представления (определенный в <f: метаданные> идентификатора целевого представления)
  3. Вложенный <f: param> в UIOutcomeTarget (например, <h: link> ) или компонент UICommand (например, <h: commandLink> )
  4. Вложенный <view-param> в элементе навигации <redirect> в Face-config.xml

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

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

<h:link outcome="entry?id=#{blog.entryId}" value="Permalink"/

Это действительно случай прототипирования, потому что инструментам будет трудно найти и визуализировать такие параметры, и это затруднит рефакторинг. Гораздо чище и действительно рекомендуемый подход — использовать вложенный тег параметра:

<h:link outcome="entry" value="Permalink">
<f:param name="id" value="#{blog.entryId}"/>
</h:link>

Вы могли бы даже абстрагировать параметр от представления и определить его в навигационном случае вместо этого, но он снова представляет проблему для инструментов:

<h:link outcome="permalink" value="Permalink"/>

<navigation-case>
<from-outcome>permalink</from-outcome>
<to-view-id>/entry.xhtml?id=#{blog.entryId}</to-view-id>
</navigation-case>

Здесь также будет работать вложенный
<view-param> , особенно если вы хотите централизовать ваши параметры.

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

<navigation-case>
<from-action>#{commentHandler.post}</from-action>
<to-view-id>/entry.xhtml</to-view-id>
<redirect>
<view-param>
<param-name>id</param-name>
<param-value>#{blog.entryId}</param-value>
</view-param>
</redirect>
</navigation-case>

Примечание. Не путайте <view-param> с параметром UIViewParameter. Думайте об этом больше как о параметре перенаправления (тэг, вероятно, должен называться <redirect-param>, а не <view-param> , что-то, что нужно учитывать в JSF 2.1).

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

 

Заглянуть в навигационные чехлы


Вы уже видели несколько способов, которыми сами навигационные примеры стали более динамичными. Независимо от того, насколько они динамичны, факт остается фактом: когда вы отправляете приложение для развертывания, навигационные сценарии, которые вы определили вface-config.xml, становятся каменными. Это больше не относится к JSF 2. Был представлен новый интерфейс обработчика навигации, названный
ConfigurableNavigationhandler , который позволяет запрашивать и вносить живые изменения в зарегистрированные
объекты
NavigationCase .

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

NavigationCase — это модель, представляющая случай навигации в JSF API. Когда JSF запускается, случаи навигации считываются из дескриптора JSF, инкапсулируются в
объекты
NavigationCase и регистрируются в
ConfigurableNavigationHandler . Вы можете получить один из зарегистрированных
NavigationCase объекты подписью выражения действия и логическим результатом, под которым оно зарегистрировано.

NavigationCase case = navigationHandler.getNavigationCase(
facesContext, "#{commandBoard.post}", "success");

Вы также можете получить доступ ко всему набору правил навигации в виде
Map <String, Set <NavigationCase >> , где ключами являются значения
<from-view-id> .

Map<String, Set<NavigationCase>> cases =
navigationHandler.getNavigationCases();

Вы можете использовать эту карту для динамической регистрации собственных вариантов навигации. Например, каркас может считывать альтернативный дескриптор навигации (такой как дескриптор страниц Seam) и вносить дополнительные варианты навигации. Имея отдельный объект NavigationCase в руке, вы можете либо прочитать его свойства, либо использовать его для создания действия или перенаправления URL-адреса, возможно, для подачи в свой собственный обработчик навигации. Здесь много возможностей.

Немного неловко, как вы ссылаетесь на этот новый API (
ConfigurableNavigationHandler ). Реализация NavigationHandler по умолчанию
в стандартной реализации JSF должна реализовывать этот интерфейс. Но вам все равно придется преобразовывать его при извлечении из объекта Application следующим образом:

ConfigurableNavigationHandler nh =
(ConfigurableNavigationHandler) FacesContext.getCurrentInstance()
.getApplication().getNavigationHandler();

Очевидно, что вернуться к JSF 2.1. Как только вы получите ручку, навигационная модель — ваша устрица. Вы можете определить новые способы навигации или использовать его для создания закладок URL-адресов в своем собственном стиле.

Продвигаться вперед

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

Для прототипов приложений вы можете получить навигацию, не касаясь дескриптораface-config.xml с неявной навигацией. Просто используйте идентификатор представления, с расширением или без, в качестве логического результата, и все готово. По мере развития приложения вы можете установить четкое разделение между JSF и вашим транзакционным уровнем, используя условную навигацию для выбора варианта навигации. Вы можете урезать количество случаев навигации, указав идентификатор целевого представления в качестве выражения значения и предложив JSF разрешить идентификатор целевого представления из бина помощника по навигации. Если дизайн вашего приложения требует поддержки закладок, вы можете использовать обработчик навигации в его новой роли для создания закладок URL во время визуализации.

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