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

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

Пример billpayment: использование событий и Interceptor-ов

В примере billpayment показано, как использовать события и Interceptor-ы.

Исходные файлы находятся в каталоге tut-install/examples/cdi/billpayment/src/main/java/javaeetutorial/billpayment/.

Здесь рассматриваются следующие темы:

Обзор примера billpayment

Пример имитирует оплату счёта с помощью дебетовой или кредитной карты. Когда пользователь выбирает способ оплаты, Managed-бин создаёт соответствующее событие, заполняет его данными и выбрасывает (fires) его. Простой слушатель события обрабатывает его, используя методы-наблюдатели.

В примере также определяется Interceptor, установленный в одном случае целиком на класс и в другом случае на два метода в другом классе.

Класс события PaymentEvent

Класс события, event.PaymentEvent, является простым классом компонента, который содержит конструктор без аргументов. Он также имеет метод toString и get- и set- методы для данных: String для типа платежа, BigDecimal для суммы платежа и Date для отметки времени.

public class PaymentEvent implements Serializable {

    ...
    public String paymentType;
    public BigDecimal value;
    public Date datetime;

    public PaymentEvent() {
    }

    @Override
    public String toString() {
        return this.paymentType
                + " = $" + this.value.toString()
                + " at " + this.datetime.toString();
    }
    ...

Класс события — это простой компонент, объект которого инстанцируется Managed-бином с помощью new, а затем заполняется. По этой причине контейнер CDI не может перехватить создание компонента, и, следовательно, он не может разрешить перехват его get- и set-методов.

Слушатель событий PaymentHandler

Слушатель событий listener.PaymentHandler содержит два метода-наблюдателя, по одному для каждого из двух типов событий:

@Logged
@SessionScoped
public class PaymentHandler implements Serializable {

    ...
    public void creditPayment(@Observes @Credit PaymentEvent event) {
        logger.log(Level.INFO, "PaymentHandler - Credit Handler: {0}",
                event.toString());

        // вызов определённого класса обработчика кредита...
    }

    public void debitPayment(@Observes @Debit PaymentEvent event) {
        logger.log(Level.INFO, "PaymentHandler - Debit Handler: {0}",
                event.toString());

        // вызов определённого класса обработчика дебета...
    }
}

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

Квалификаторы определены в пакете payment, описанном в Страницы Facelets и Managed-бин для billpayment.

Компонент PaymentHandler аннотирован @Logged, так что все его методы могут быть перехвачены.

Страницы Facelets и Managed-бин для billpayment

Пример billpayment содержит две страницы Facelets, index.xhtml и response.xhtml. Тело index.xhtml выглядит так:

    <h:body>
        <h3>Bill Payment Options</h3>
        <p>Enter an amount, select Debit Card or Credit Card,
            then click Pay.</p>
        <h:form>
            <p>
            <h:outputLabel value="Amount: $" for="amt"/>
            <h:inputText id="amt" value="#{paymentBean.value}"
                         required="true"
                         requiredMessage="An amount is required."
                         maxlength="15" />
            </p>
            <h:outputLabel value="Options:" for="opt"/>
            <h:selectOneRadio id="opt" value="#{paymentBean.paymentOption}">
                <f:selectItem id="debit" itemLabel="Debit Card"
                              itemValue="1"/>
                <f:selectItem id="credit" itemLabel="Credit Card"
                              itemValue="2" />
            </h:selectOneRadio>
            <p><h:commandButton id="submit" value="Pay"
                                action="#{paymentBean.pay}" /></p>
            <p><h:commandButton value="Reset"
                                action="#{paymentBean.reset}" /></p>
        </h:form>
        ...
    </h:body>

Поле ввода принимает сумму платежа, переданную в paymentBean.value. Из представленных двух вариантов пользователь может выбрать платёж дебетовой или кредитной картой, передав целочисленное значение в paymentBean.paymentOption. Наконец, действием кнопки «Pay» назначен метод paymentBean.pay, а кнопки «Reset» — метод paymentBean.reset.

Managed-бин payment.PaymentBean использует квалификаторы чтобы различать два вида событий оплаты:

@Named
@SessionScoped
public class PaymentBean implements Serializable {

   ...
    @Inject
    @Credit
    Event<PaymentEvent> creditEvent;

    @Inject
    @Debit
    Event<PaymentEvent> debitEvent;

Квалификаторы @Credit и @Debit определяются в пакете payment вместе с PaymentBean.

Затем PaymentBean определяет свойства, которые он получает со страницы Facelets, и передаёт событие:

    public static final int DEBIT = 1;
    public static final int CREDIT = 2;
    private int paymentOption = DEBIT;

    @Digits(integer = 10, fraction = 2, message = "Invalid value")
    private BigDecimal value;

    private Date datetime;

Значение paymentOption является целым числом, переданным из компонента option. Значение по умолчанию — DEBIT. value — это BigDecimal с ограничением Bean Validation, которое проверяет максимальное количество цифр для значения валюты. Отметка времени для события datetime является объектом Date, инициализированным при вызове метода pay.

Метод pay компонента сначала устанавливает метку времени для события оплаты. Затем он создаёт и заполняет данные события, используя конструктор для PaymentEvent и вызывая методы установки события, используя свойства бина в качестве аргументов. Затем он запускает событие.

    @Logged
    public String pay() {
        this.setDatetime(Calendar.getInstance().getTime());
        switch (paymentOption) {
            case DEBIT:
                PaymentEvent debitPayload = new PaymentEvent();
                debitPayload.setPaymentType("Debit");
                debitPayload.setValue(value);
                debitPayload.setDatetime(datetime);
                debitEvent.fire(debitPayload);
                break;
            case CREDIT:
                PaymentEvent creditPayload = new PaymentEvent();
                creditPayload.setPaymentType("Credit");
                creditPayload.setValue(value);
                creditPayload.setDatetime(datetime);
                creditEvent.fire(creditPayload);
                break;
            default:
                logger.severe("Invalid payment option!");
        }
        return "response";
    }

Метод pay возвращает страницу response.xhtml, на которую перенаправлено действие.

Класс PaymentBean также содержит метод reset, который очищает поле значения на странице index.xhtml и устанавливает для параметра оплаты значение по умолчанию:

    @Logged
    public void reset() {
        setPaymentOption(DEBIT);
        setValue(BigDecimal.ZERO);
    }

В этом компоненте перехватываются только методы pay и reset.

На странице response.xhtml отображается уплаченная сумма. Для отображения способа оплаты используется выражение render:

    <h:body>
        <h:form>
            <h2>Bill Payment: Result</h2>
            <h3>Amount Paid with
                <h:outputText id="debit" value="Debit Card: "
                              rendered="#{paymentBean.paymentOption eq 1}" />
                <h:outputText id="credit" value="Credit Card: "
                              rendered="#{paymentBean.paymentOption eq 2}" />
                <h:outputText id="result" value="#{paymentBean.value}">
                    <f:convertNumber type="currency"/>
                </h:outputText>
            </h3>
            <p><h:commandButton id="back" value="Back" action="index" /></p>
        </h:form>
    </h:body>

Класс Interceptor-а LoggedInterceptor

Класс Interceptor-а LoggedInterceptor и его привязка Interceptor-а Logged определены в пакете interceptor. Привязка Interceptor-а Logged определяется следующим образом:

@Inherited
@InterceptorBinding
@Retention(RUNTIME)
@Target({METHOD, TYPE})
public @interface Logged {
}

Класс LoggedInterceptor выглядит следующим образом:

@Logged
@Interceptor
public class LoggedInterceptor implements Serializable {

    ...

    public LoggedInterceptor() {
    }

    @AroundInvoke
    public Object logMethodEntry(InvocationContext invocationContext)
            throws Exception {
        System.out.println("Entering method: "
                + invocationContext.getMethod().getName() + " in class "
                + invocationContext.getMethod().getDeclaringClass().getName());

        return invocationContext.proceed();
    }
}

Класс аннотируется @Logged и @Interceptor. Метод @AroundInvoke, logMethodEntry, принимает обязательный аргумент InvocationContext и вызывает требуемый метод continue. Когда метод перехватывается, logMethodEntry отображает имя вызываемого метода, а также его класс.

Чтобы включить Interceptor, файл beans.xml определяет его следующим образом:

<interceptors>
    <class>javaeetutorial.billpayment.interceptor.LoggedInterceptor</class>
</interceptors>

В этом приложении классы PaymentEvent и PaymentHandler аннотируются @Logged, поэтому все их методы перехватываются. В PaymentBean только методы pay и reset аннотируются @Logged, поэтому только эти методы перехватываются.

Запуск billpayment

Вы можете использовать IDE NetBeans или Maven для создания, упаковки, развёртывания и запуска приложения billpayment.

Здесь рассматриваются следующие темы:

Сборка, упаковка и развёртывание billpayment с IDE NetBeans

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

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

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

    tut-install/examples/cdi
  4. Выберите каталог billpayment.

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

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

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

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

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

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

    tut-install/examples/cdi/billpayment/
  3. Введите следующую команду для развёртывания приложения:

    mvn install

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

Запуск billpayment

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

    http://localhost:8080/billpayment
  2. На странице Варианты оплаты счетов введите значение в поле Сумма.

    Сумма может содержать до 10 цифр и включать до двух десятичных знаков. Например:

    9876.54
  3. Выберите «Дебетовая карта» или «Кредитная карта» и нажмите «Оплатить».

    Откроется страница «Оплата счёта: результат», отображающая уплаченную сумму и способ оплаты:

    Amount Paid with Credit Card: $9,876.34
  4. Нажмите «Назад», чтобы вернуться на страницу «Оплата счетов».

    Вы также можете нажать Сброс, чтобы вернуться к начальным значениям страницы.

  5. Проверьте вывод журнала сервера.

    В IDE NetBeans выходные данные отображаются на вкладке «Вывод сервера GlassFish». В противном случае просмотрите domain-dir`/logs/server.log`.

    Выходные данные каждого Interceptor-а появляются в журнале, за которым следуют дополнительные выходные данные регистратора, определённые конструктором и методами:

    INFO: Entering method: pay in class billpayment.payment.PaymentBean
    INFO: PaymentHandler created.
    INFO: Entering method: debitPayment in class billpayment.listener.PaymentHandler
    INFO: PaymentHandler - Debit Handler: Debit = $1234.56 at Tue Dec 14 14:50:28 EST 2010

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