Главная » Spring » Определение   основной последовательности Spring

0

Руководство новой сети пиццерий Spizza2 приняло решение, что- бы уменьшить нагрузку на отдел заказа пиццы по телефону, предо- ставить своим клиентам возможность заказать пиццу через Интер- нет. Когда клиент приходит на веб-сайт Spizza, он идентифициру- ет себя, выбирает одну или несколько пицц, добавляет их в заказ, предоставляет информацию об оплате, отправляет заказ и ждет до- ставки свежей и горячей пиццы. Эта последовательность операций представлена на рис. 9.2.

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

1   Честно признаться, я не смог придумать, где в приложении Spitter мож- но было бы применить последовательность. Поэтому, вместо того чтобы насильно пытаться впихнуть пример использования Spring Web Flow в приложение Spitter, мы рассмотрим применение этого фреймворка на примере заказа пиццы.

2   Да, я знаю, что в Сингапуре действительно существует пиццерия Spizza. Но речь совсем не о ней.

Рис. 9.2. Процедура заказа пиццы легко реализуется с помощью простой последовательности

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

В листинге 9.1 показано определение последовательности верхне- го уровня, реализующей процедуру заказа пиццы.

Листинг 9.1. Реализация процедуры заказа пиццы в виде последовательности Spring Web Flow

<?xml  version="1.0"  encoding="UTF-8"?>

<flow      xmlns="http://www.springframework.org/schema/webflow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">

<var  name="order"

class="com.springinaction.pizza.domain.Order"/>

<!– Вызов подпоследовательности идентификации клиента –>

<subflow-state id="identifyCustomer" subflow="pizza/customer">

<output  name="customer"  value="order.customer"/>

<transition on="customerReady" to="buildOrder" />

</subflow-state>

<!– Вызов подпоследовательности оформления заказа –>

<subflow-state id="buildOrder" subflow="pizza/order">

<input  name="order"  value="order"/>

<transition on="orderCreated" to="takePayment" />

</subflow-state>

<!– Вызов подпоследовательности приема оплаты –>

<subflow-state  id="takePayment"  subflow="pizza/payment">

<input  name="order"  value="order"/>

<transition  on="paymentTaken"  to="saveOrder"/>

</subflow-state>

<action-state id="saveOrder">          <!– Сохранить заказ –>

<evaluate expression="pizzaFlowActions.saveOrder(order)" />

<transition to="thankCustomer" />

</action-state>

<view-state id="thankCustomer">      <!– Выражение благодарности клиенту –>

<transition  to="endState"  />

</view-state>

<end-state  id="endState"  />

<global-transitions>        <!–  Глобальный  переход  в  случае  отмены  заказа  –>

<transition  on="cancel"  to="endState"  />

</global-transitions>

</flow>

Самое первое, что встречается в этом определении последователь- ности, – объявление переменной order. Каждый раз, когда будет за- пускаться эта последовательность, будет создаваться новый объект Order. Класс Order, представленный в листинге 9.2, имеет свойства, хранящие всю необходимую информацию о заказе, включая инфор- мацию о клиенте, список заказанных пицц и сведения об оплате.

Листинг 9.2. Класс Order хранит всю информацию, имеющую отношение к заказу

package com.springinaction.pizza.domain;

import  java.io.Serializable; import java.util.ArrayList; import   java.util.List;

public  class  Order  implements  Serializable  {

private static final long serialVersionUID = 1L;

private Customer customer; private  List<Pizza>  pizzas; private Payment payment;

public  Order()  {

pizzas   =   new   ArrayList<Pizza>(); customer  =  new  Customer();

}

public  Customer  getCustomer()  { return   customer;

}

public  void  setCustomer(Customer  customer)  { this.customer   =   customer;

}

public  List<Pizza>  getPizzas()  { return   pizzas;

}

public  void  setPizzas(List<Pizza>  pizzas)  { this.pizzas   =   pizzas;

}

public  void  addPizza(Pizza  pizza)  { pizzas.add(pizza);

}

public float getTotal() { return  0.0f;

}

public  Payment  getPayment()  { return   payment;

}

public  void  setPayment(Payment  payment)  { this.payment   =   payment;

}

}

Основной частью определения последовательности являются объявления состояний. По умолчанию первое состояние в опреде- лении последовательности является также состоянием, где произой- дет первая остановка. В данном случае это состояние identifyCustomer (вызов подпоследовательности). Однако в случае необходимости можно явно определить, какое состояние будет первым, указав его идентификатор в атрибуте start-state элемента <flow>:

<?xml  version="1.0"  encoding="UTF-8"?>

<flow      xmlns="http://www.springframework.org/schema/webflow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd" start-state="identifyCustomer">

</flow>

Идентификация клиента, оформление заказа и получение опла- ты – все эти операции слишком сложные, чтобы их можно было выразить в виде единственных состояний. Именно поэтому позд- нее мы определим их как самостоятельные последовательности. Но в последовательности верхнего уровня достаточно объявить их с помощью элемента <subflow-state>.

Переменная order будет заполняться в первых трех состояниях и затем сохраняться в четвертом. Для заполнения свойства customer объекта заказа состояние-подпоследовательность identifyCustomer ис- пользует элемент <output>, присваивая ему результат вызова подпо- следовательности идентификации клиента. Состояния buildOrder и takePayment действуют иначе, передавая с помощью элемента <input> переменную order на вход своих подпоследовательностей, которые заполняют соответствующие свойства заказа внутри.

После заполнения заказа информацией о клиенте, количестве пицц и об оплате заказ можно сохранить. Эту задачу выполняет состояние saveOrder, являющееся состоянием-действием. В нем ис- пользуется элемент <evaluate>, вызывающий метод saveOrder() компо- нента с идентификатором pizzaFlowActions, которому передается со- храняемый заказ. После сохранения заказа это состояние выполняет переход к состоянию thankCustomer.

Состояние thankCustomer – это простое состояние-представление, возвращающее JSP-файл /WEBINF/flows/pizza/thankCustomer.jsp, пред- ставленный в листинге 9.3.

Листинг 9.3. Представление в формате JSP, отображающее благодарность клиенту за сделанный заказ

<html xmlns:jsp="http://java.sun.com/JSP/Page">

<jsp:output  omit-xml-declaration="yes"/>

<jsp:directive.page  contentType="text/html;charset=UTF-8"  />

<head><title>Spizza</title></head>

<body>

<h2>Thank you for your order!</h2>

<!– Возбуждает заключительное событие –>

<![CDATA[

<a  href=’${flowExecutionUrl}&_eventId=finished’>Finish</a>

]]>

</body>

</html>

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

Фреймворк Spring Web Flow предоставляет переменную flowExecu- tionUrl, содержащую URL последовательности, для использования в представлении. Ссылка Finish (Конец) включает в URL параметр

_eventId, обеспечивающий передачу события finished обратно в по- следовательность. Это событие переводит последовательность в ко- нечное состояние.

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

Это все, что относится к последовательности заказа пиццы верхне- го уровня. Но нам необходимо определить еще подпоследовательно- сти для состояний identifyCustomer, buildOrder и takePayment. Определим их далее, начав с подпоследовательности идентификации клиента.

Источник:   Уоллс К., Spring в действии. – М.: ДМК Пресс, 2013. – 752 с.: ил.

По теме:

  • Комментарии