Java Platform, Enterprise Edition (Java EE) 8
Учебник по Java EE

Назад Вперёд Содержание

Использование Faces Flows

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

Faces Flow в некоторой степени аналогичны процедурам процедурного программирования.

  • Как и процедура, Flow имеет чётко определённую точку входа, список параметров и возвращаемое значение. Однако, в отличие от процедуры, Flow может возвращать несколько значений.

  • Как и процедура, Flow имеет область видимости, позволяющую получать информацию только во время вызова Flow. Такая информация недоступна вне области видимости Flow и не потребляет никаких ресурсов после возврата из Flow.

  • Как и процедура, Flow может вызвать другие Flow перед возвратом. Вызов Flow поддерживается в стеке вызовов: новый Flow помещается в стек вызова, а после возврата извлекается из него.

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

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

Flow могут быть вложенными, так что если вы вызываете один Flow из другого и затем выходите из второго Flow, вы возвращаетесь к вызывающему Flow, а не к возвратному узлу второго Flow.

Вы можете настроить Flow программно, создав аннотированный класс @FlowDefinition, или вы можете настроить Flow с помощью файла конфигурации. Файл конфигурации может содержать один Flow, или вы можете использовать файл faces-config.xml, чтобы поместить все Flow в одно место, если в вашем приложении много Flow. Программная конфигурация размещает код ближе к остальной части кода Flow и позволяет вам организовывать Flow в модули.

На рисунке 16-1 показаны два Flow и показано, как они взаимодействуют

Рис. 16-1. Два Faces Flow и их взаимодействие

На этом рисунке показаны два Faces Flow, Flow A и Flow B. Каждый имеет начальный узел и две дополнительные страницы. Каждый связан с Managed-бином. Каждый определяет возвращаемый узел, и каждый определяет два параметра, которые должны быть переданы другому Flow.

На этом рисунке Flow A имеет начальный узел с именем flow-a и две дополнительные страницы, next_a1 и next_a2. Из next_a2 пользователь может либо выйти из Flow, используя узел возврата taskFlowReturn1, либо вызвать Flow B, передав два параметра. Flow A также определяет два входящих параметра, которые он может принимать из Flow B. Flow B идентичен Flow A во всём, за исключением имён и файлов. Каждый Flow также имеет связанный Managed-бин. Бинами являются Flow_a_Bean и Flow_b_Bean.

Упаковка Flows в приложение

Как правило, Flow упаковывается в веб-приложении с использованием структуры каталогов, когда Flow отделены друг от друга. Например, в каталоге src/main/webapp проекта Maven вы поместите файлы Facelets, которые находятся вне Flow, на верхний уровень, как обычно. Тогда файлы webapp каждого Flow будут находиться в отдельных каталах, а файлы Java будут находиться в src/main/java. Например, файлы для приложения, показанные на Рис. 16-1, могут выглядеть следующим образом:

src/main/webapp/
    index.xhtml
    return.xhtml
    WEB_INF/
        beans.xml
        web.xml
    flow-a/
        flow-a.xhtml
        next_a1.xhtml
        next_a2.xhtml
    flow-b/
        flow-b-flow.xml
        next_b1.xhtml
        next_b2.xhtml
src/main/java/javaeetutorial/flowexample
            FlowA.java
            Flow_a_Bean.java
            Flow_b_Bean.java

В этом примере flow-a определяется программно в FlowA.java, а flow-b определяется файлом конфигурации flow-b-flow.xml.

Простейший Flow: пример simple-flow

Приложение simple-flow демонстрирует самые базовые строительные блоки приложения Faces Flows и иллюстрирует некоторые соглашения, облегчающие начало работы с итеративной разработкой с использованием Flow. Вы можете начать с простого примера, подобного этому, и продолжить его.

В этом примере приводится неявное определение Flow путём включения пустого файла конфигурации. Файл конфигурации с содержимым или аннотированный класс @FlowDefinition предоставляет явное определение Flow.

Исходный код для этого приложения находится в каталоге tut-install/examples/web/jsf/simple-flow/.

Расположение файла в примере simple-flow выглядит следующим образом:

src/main/webapp
    index.xhtml
    simple-flow-return.xhtml
    WEB_INF/
        web.xml
    simple-flow
        simple-flow-flow.xml
        simple-flow.xhtml
        simple-flow-page2.xhtml

В примере simple-flow есть пустой файл конфигурации, который по соглашению называется flow-name-flow.xml. Flow не требует какой-либо настройки по следующим причинам.

  • Flow не вызывает другой Flow и не передаёт параметры другому Flow.

  • Flow использует имена по умолчанию для первой страницы Flow, flow-name`.xhtml`, и страницу возврата, flow-name`-return.xhtml`.

В этом примере всего четыре страницы Facelets.

  • index.xhtml — стартовая страница, которая почти ничего не содержит, кроме кнопки, перемещающей на первую страницу Flow:

    <p><h:commandButton value="Enter Flow" action="simple-flow"/></p>
  • simple-flow.xhtml и simple-flow-page2.xhtml — две страницы самого Flow. При отсутствии явного определения Flow страница, имя которой совпадает с именем Flow, считается начальным узлом Flow. В этом случае Flow называется simple-flow, поэтому предполагается, что начальным узлом Flow является страница simple-flow.xhtml. Начальный узел — это узел, к которому переходят при входе в Flow. Его можно рассматривать как домашнюю страницу Flow.

    Страница simple-flow.xhtml попросит вас ввести значение в области Flow и предоставит кнопку для перехода на следующую страницу Flow:

    <p>Value: <h:inputText id="input" value="#{flowScope.value}" /></p>
    
    <p><h:commandButton value="Next" action="simple-flow-page2" /></p>

    Вторая страница, которая может иметь любое имя, отображает значение в области видимости Flow и предоставляет кнопку для перехода на страницу возврата:

    <p>Value: #{flowScope.value}</p>
    
    <p><h:commandButton value="Return" action="simple-flow-return" /></p>
  • simple-flow-return.xhtml — страница возврата. Страница возврата, которая по соглашению называется flow-name`-return.xhtml`, должна находиться за пределами Flow. На этой странице отображается значение области видимости Flow, показывающее, что оно не имеет значения вне Flow, и предоставляется ссылка, которая ведет на страницу index.xhtml:

    <p>Value (should be empty):
        "<h:outputText id="output" value="#{flowScope.value}" />"</p>
    
    <p><h:link outcome="index" value="Back to Start" /></p>

Страницы Facelets используют только данные области видимости Flow, поэтому в примере не требуется Managed-бин.

Сборка, упаковка и развёртывание simple-flow в IDE NetBeans

  1. Удостоверьтесь, чтобы GlassFish Server был запущен (см. Запуск и остановка сервера GlassFish).

  2. В меню «Файл» выберите «Открыть проект».

  3. В диалоговом окне «Открыть проект» перейдите к:

    tut-install/examples/web/jsf
  4. Выберите каталог simple-flow.

  5. Нажмите Открыть проект.

  6. На вкладке «Проекты» кликните правой кнопкой мыши проект simple-flow и выберите «Сборка».

    Эта команда собирает и упаковывает приложение в WAR-файл, simple-flow.war, который находится в каталоге target. Затем приложение развёртывается на сервере.

Сборка, упаковка и развёртывание simple-flow с использованием Maven

  1. Удостоверьтесь, чтобы GlassFish Server был запущен (см. Запуск и остановка сервера GlassFish).

  2. В окне терминала перейдите в:

    tut-install/examples/web/jsf/simple-flow/
  3. Введите следующую команду:

    mvn install

    Эта команда собирает и упаковывает приложение в WAR-файл, simple-flow.war, который находится в каталоге target. Затем приложение развёртывается на сервере.

Запуск simple-flow

  1. Введите следующий URL в браузере:

    http://localhost:8080/simple-flow
  2. На странице index.xhtml нажмите Enter Flow.

  3. На первой странице Flow введите любую строку в поле «Значение», затем нажмите «Далее».

  4. На второй странице Flow вы можете увидеть введённое вами значение. Нажмите Return.

  5. На странице возврата пустая пара кавычек заключает в себе недоступное значение. Нажмите кнопку «Назад в начало», чтобы вернуться на страницу index.xhtml.

Приложение checkout-module

Приложение checkout-module значительно сложнее, чем simple-flow. Он показывает, как вы можете использовать функцию Faces Flows для реализации модуля оформления заказа для интернет-магазина.

Как и гипотетический пример на рис. 16-1, пример приложения содержит два Flow, каждый из которых может вызывать другой. Оба Flow имеют явные определения. Один Flow, checkoutFlow, определяется программно. Другой Flow, joinFlow, указан в файле конфигурации.

Исходный код для этого приложения находится в каталоге tut-install/examples/web/jsf/checkout-module/.

Для приложения checkout-module структура каталогов следующая (есть также каталог src/main/webapp/resources с таблицей стилей и изображением):

src/main/webapp/
    index.xhtml
    exithome.xhtml
    WEB_INF/
        beans.xml
        web.xml
    checkoutFlow/
        checkoutFlow.xhtml
        checkoutFlow2.xhtml
        checkoutFlow3.xhtml
        checkoutFlow4.xhtml
    joinFlow/
        joinFlow-flow.xml
        joinFlow.xhtml
        joinFlow2.xhtml
src/main/java/javaeetutorial/checkoutmodule
            CheckoutBean.java
            CheckoutFlow.java
            CheckoutFlowBean.java
            JoinFlowBean.java

Например, index.xhtml является начальной страницей для приложения, а также узлом возврата для Flow оформления заказа. Страница exithome.xhtml является узлом возврата для Flow объединения.

Файл конфигурации joinFlow-flow.xml определяет Flow объединения, а исходный файл CheckoutFlow.java определяет Flow оформления.

Flow оформления содержит четыре страницы Facelets, а Flow объединения — две.

Managed-бины, охватываемые каждым Flow: CheckoutFlowBean.java и JoinFlowBean.java, тогда как CheckoutBean.java является вспомогательным бином для страницы index.html.

Страницы Facelets для checkout-module

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

<p><h:commandButton value="Check Out" action="checkoutFlow"/></p>
...
<p><h:commandButton value="Join" action="joinFlow"/></p>

Эта страница также является возвратным узлом для Flow оформления заказа.

Страница Facelets exithome.xhtml является узлом возврата для Flow объединения. На этой странице есть кнопка, позволяющая вернуться на страницу index.xhtml.

Четыре страницы Facelets во Flow оформления заказа, начиная с checkoutFlow.xhtml и заканчивая checkoutFlow4.xhtml, позволяют перейти на следующую страницу или, в некоторых случаях, вернуться из Flow. Страница checkoutFlow.xhtml позволяет получить доступ к параметрам, переданным из Flow объединения через область видимости Flow. Они отображаются в виде пустых кавычек, если вы не вызвали Flow оформления из Flow объединения.

<p>If you called this flow from the Join flow, you can see these parameters:
    "<h:outputText value="#{flowScope.param1Value}"/>" and
    "<h:outputText value="#{flowScope.param2Value}"/>"
</p>

Только checkoutFlow2.xhtml имеет кнопку для возврата на предыдущую страницу, но перемещение между страницами обычно разрешено во Flow. Вот кнопки для checkoutFlow2.xhtml:

<p><h:commandButton value="Continue" action="checkoutFlow3"/></p>
<p><h:commandButton value="Go Back" action="checkoutFlow"/></p>
<p><h:commandButton value="Exit Flow" action="returnFromCheckoutFlow"/></p>

Действие returnFromCheckoutFlow определено в файле исходного кода CheckoutFlow.java.

Последняя страница Flow оформления checkoutFlow4.xhtml содержит кнопку, которая вызывает Flow объединения:

<p><h:commandButton value="Join" action="calljoin"/></p>
<p><h:commandButton value="Exit Flow" action="returnFromCheckoutFlow"/></p>

Действие calljoin также определено в файле исходного кода конфигурации, CheckoutFlow.java. Это действие входит во Flow объединения, получая два параметра из Flow оформления.

Две страницы во Flow объединения, joinFlow.xhtml и joinFlow2.xhtml, аналогичны тем, которые находятся во Flow оформления. На второй странице есть кнопка для вызова Flow оформления заказа и кнопка для возврата из Flow объединения:

<p><h:commandButton value="Check Out" action="callcheckoutFlow"/></p>
<p><h:commandButton value="Exit Flow" action="returnFromJoinFlow"/></p>

Для этого Flow действия callcheckoutFlow и returnFromJoinFlow определены в файле конфигурации joinFlow-flow.xml.

Использование файла конфигурации для настройки Flow

Если вы используете файл конфигурации приложения для настройки Flow, он должен называться flowName`-flow.xml`. В этом примере Flow объединения использует файл конфигурации с именем joinFlow-flow.xml. Этот файл является файлом faces-config, в котором указан элемент flow-definition. Этот элемент должен определять имя Flow, используя атрибут id. Под элементом flow-definition должен быть элемент flow-return, который указывает точку возврата для Flow. Все входные параметры указываются с помощью элементов inbound-parameter. Если Flow вызывает другой Flow, элемент call-flow должен использовать элемент flow-reference для именования вызываемого Flow и может использовать элемент outbound-parameter для указания любого исходящего параметры.

Файл конфигурации для Flow объединения выглядит следующим образом:

<faces-config version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee \
              http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd">

    <flow-definition id="joinFlow">
        <flow-return id="returnFromJoinFlow">
            <from-outcome>#{joinFlowBean.returnValue}</from-outcome>
        </flow-return>

        <inbound-parameter>
            <name>param1FromCheckoutFlow</name>
            <value>#{flowScope.param1Value}</value>
        </inbound-parameter>
        <inbound-parameter>
            <name>param2FromCheckoutFlow</name>
            <value>#{flowScope.param2Value}</value>
        </inbound-parameter>

        <flow-call id="callcheckoutFlow">
            <flow-reference>
                <flow-id>checkoutFlow</flow-id>
            </flow-reference>
            <outbound-parameter>
                <name>param1FromJoinFlow</name>
                <value>param1 joinFlow value</value>
            </outbound-parameter>
            <outbound-parameter>
                <name>param2FromJoinFlow</name>
                <value>param2 joinFlow value</value>
            </outbound-parameter>
        </flow-call>
    </flow-definition>
</faces-config>

Атрибут id элемента flow-definition определяет имя Flow как joinFlow. Значение атрибута id элемента flow-return идентифицирует имя возвращаемого узла, а его значение определяется в from-outcome элемент как свойство returnValue Managed-бина области видимости Flow для Flow объединения JoinFlowBean.

Имена и значения входных параметров извлекаются из области видимости Flow в следующем порядке (flowScope.param1Value, flowScope.param2Value), согласно тому, как это было определено в и конфигурации Flow оформления.

Элемент flow-call определяет, как Flow объединения вызывает Flow оформления. Атрибут id элемента callcheckoutFlow определяет действие вызова Flow. В элементе flow-call элемент flow-reference определяет фактическое имя вызываемого Flow, checkoutFlow. Элементы outbound-parameter определяют параметры, которые будут переданы при вызове checkoutFlow. Здесь это просто произвольные строки.

Использование Java-класса для настройки Flow

Если вы используете класс Java для настройки Flow, он должен совпадать с Flow по имени. Класс для Flow оформления называется CheckoutFlow.java.

import java.io.Serializable;
import javax.enterprise.inject.Produces;
import javax.faces.flow.Flow;
import javax.faces.flow.builder.FlowBuilder;
import javax.faces.flow.builder.FlowBuilderParameter;
import javax.faces.flow.builder.FlowDefinition;

class CheckoutFlow implements Serializable {

    private static final long serialVersionUID = 1L;

    @Produces
    @FlowDefinition
    public Flow defineFlow(@FlowBuilderParameter FlowBuilder flowBuilder) {

        String flowId = "checkoutFlow";
        flowBuilder.id("", flowId);
        flowBuilder.viewNode(flowId,
                "/" + flowId + "/" + flowId + ".xhtml").
                markAsStartNode();

        flowBuilder.returnNode("returnFromCheckoutFlow").
                fromOutcome("#{checkoutFlowBean.returnValue}");

        flowBuilder.inboundParameter("param1FromJoinFlow",
                "#{flowScope.param1Value}");
        flowBuilder.inboundParameter("param2FromJoinFlow",
                "#{flowScope.param2Value}");

        flowBuilder.flowCallNode("calljoin").flowReference("", "joinFlow").
                outboundParameter("param1FromCheckoutFlow",
                    "#{checkoutFlowBean.name}").
                outboundParameter("param2FromCheckoutFlow",
                    "#{checkoutFlowBean.city}");
        return flowBuilder.getFlow();
    }
}

Класс выполняет действия, практически идентичные тем, которые выполняются файлом конфигурации joinFlow-flow.xml. Он содержит единственный метод defineFlow в качестве метода-производителя с квалификатором @FlowDefinition, который возвращает класс javax.faces.flow.Flow. Метод defineFlow принимает один параметр — FlowBuilder с квалификатором @FlowBuilderParameter, который передаётся из JavaServer Faces. Затем метод вызывает методы класса javax.faces.flow.Builder.FlowBuilder для настройки Flow.

Во-первых, метод определяет id Flow как checkoutFlow. Затем он явно определяет начальный узел для Flow. По умолчанию это имя Flow с суффиксом .xhtml.

Затем метод определяет возвратный узел аналогично тому, как это делает файл конфигурации. Метод returnNode устанавливает имя возвращаемого узла как returnFromCheckoutFlow, а метод fromOutcome указывает его значение как свойство returnValue Managed-бина во Flow оформления, CheckoutFlowBean.

Метод inboundParameter устанавливает имена и значения входных параметров из Flow объединения, которые извлекаются из области видимости Flow в следующем порядке (flowScope.param1Value, flowScope. param2Value), согласно тому, как определено в в файле конфигурации Flow объединения.

Метод flowCallNode определяет, как Flow оформления вызывает Flow объединения. Аргумент calljoin определяет действие вызова Flow. Связанный метод flowReference определяет фактическое имя вызываемого Flow, joinFlow, а затем вызывает методы outboundParameter для определения параметров, передаваемых при вызове joinFlow. Здесь это значения из Managed-бина CheckoutFlowBean.

Наконец, метод defineFlow вызывает метод getFlow и возвращает результат.

Область видимости Flow для Managed-бина

Каждый из двух Flow имеет Managed-бин, который определяет свойства страниц в Flow. Например, CheckoutFlowBean определяет свойства, значения которых вводятся пользователем как на странице checkoutFlow.xhtml, так и на странице checkoutFlow3.xhtml.

Каждый Managed-бин имеет метод getReturnValue, который устанавливает значение возвращаемого узла. Для CheckoutFlowBean возвратным узлом является страница index.xhtml, указанная с помощью неявной навигации:

public String getReturnValue() {
    return "index";
}

Для JoinFlowBean возвратным узлом является страница exithome.xhtml.

Сборка, упаковка и развёртывание checkout-module в IDE NetBeans

  1. Удостоверьтесь, чтобы GlassFish Server был запущен (см. Запуск и остановка сервера GlassFish).

  2. В меню «Файл» выберите «Открыть проект».

  3. В диалоговом окне «Открыть проект» перейдите к:

    tut-install/examples/web/jsf
  4. Выберите каталог checkout-module.

  5. Нажмите Открыть проект.

  6. На вкладке «Проекты» кликните правой кнопкой мыши проект checkout-module и выберите «Сборка».

    Эта команда собирает и упаковывает приложение в WAR-файл, checkout-module.war, который находится в каталоге target. Затем приложение развёртывается на сервере.

Сборка, упаковка и развёртывание checkout-module с помощью Maven

  1. Удостоверьтесь, чтобы GlassFish Server был запущен (см. Запуск и остановка сервера GlassFish).

  2. В окне терминала перейдите в:

    tut-install/examples/web/jsf/checkout-module/
  3. Введите следующую команду:

    mvn install

    Эта команда собирает и упаковывает приложение в WAR-файл, checkout-module.war, который находится в каталоге target. Затем приложение развёртывается на сервере.

Запуск checkout-module

  1. Введите следующий URL в браузере:

    http://localhost:8080/checkout-module
  2. На странице index.xhtml представлены гипотетические результаты похода за покупками. Нажмите «Check Out» или «Join», чтобы войти в один из двух Flow.

  3. Следуйте за Flow, предоставляя входные данные по мере необходимости и выбирая, продолжить, вернуться назад или выйти из Flow.

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

  4. На последней странице Flow выберите опцию для ввода другого Flow. Это позволяет просматривать входные параметры из предыдущего Flow.

  5. Поскольку Flow являются вложенными, если вы нажмёте Exit Flow из вызываемого Flow, вы вернётесь к первой странице вызывающего Flow. (Возможно появится предупреждение, которое можно игнорировать.) Нажмите «Выход из Flow» на этой странице, чтобы перейти к указанному возвратному узлу.


Назад Вперёд Содержание
Логотип Oracle  Copyright © 2017, Oracle и/или её дочерних компаний. Все права защищены. Версия перевода 1.0.5 (Java EE Tutorial — русскоязычная версия)