Зміст
Як згадувалося раніше, Spring Web Flow дозволяє реалізувати автомат переходів. І якщо в попередній статті виконання програми було лінійним, то в цій з'являться переходи. Якщо користувач введе коротке ім'я, то програма сповістить його про це і запропонує ввести довший пароль.
Для початку змінимо файл index.jsp, який був автоматично створений в директорії WEB-INF. У цьому файлі додамо посилання на наш flow:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Hello John - Spring Web Flow 2.x Tutorial | seostella.com</title>
</head>
<body>
<h1>Spring Web Flow 2.x Tutorial - Hello John</h1>
<a href="<%= request.getContextPath() %>/hellojohn"
title="Go!">Go!</a>
</body>
</html>
Перейдемо до безпосереднього створення програми. Щоб зберегти ім'я користувача створимо клас User, що містить всього одну властивість name:
package com.seostella.swfhellojohn.domain;
import java.io.Serializable;
/**
*
* @author seostella.com
*/
@SuppressWarnings("serial")
public class User implements Serializable {
private String name;
public User() {
}
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Нічого специфічного в цьому класі немає. Єдина рідко використовувана конструкція - це @SuppressWarnings("serial"). Якщо Ваш клас реалізує інтерфейс java.io.Serializeable, то він повинен містити властивість serialVersionUID. Якщо ж цієї властивості нема, то Ви отримаєте застереження на етапі компіляції. Щоб позбутися цього застереження досить додати @SupressWarnings("serial") перед оголошенням класу.
Також нам знадобиться ще один клас-компонент, який буде обробляти дії, прописані у flow. Назвемо його HellojohnFlowActions:
package com.seostella.swfhellojohn.flow;
import com.seostella.swfhellojohn.domain.User;
import org.springframework.stereotype.Component;
/**
*
* @author seostella.com
*/
@Component
public class HellojohnFlowActions {
public User createUser(String name) {
User user = new User(name);
return user;
}
}
Клас містить тільки один метод createUser, який по імені повертає об'єкт класу User. Ще одна особливість - об'єкт цього класу буде автоматично створений через те, що перед оголошенням класу знаходиться анотація @Component, а в конфігураційному файлі SWFHelloJohn-servlet.xml є конструкція, завдяки якій проводиться пошук на компоненти у всіх класах пакета com.seostella.swfhellojohn:
<context:component-scan base-package="com.seostella.swfhellojohn" />
Створимо flow, в якому опишемо всі дії, необхідні для даної веб-програми. Конструкція
<flow:flow-registry id="flowRegistry"
flow-builder-services="flowBuilderServices"
base-path="/WEB-INF/flows">
<flow:flow-location-pattern value="/**/*-flow.xml" />
</flow:flow-registry>
вказує на те, що flow необхідно створити в піддиректорії, яка знаходиться в директорії /WEB-INF/flows/.
Рис 2. Структура WEB-INF
Тобто, створюємо директорію /WEB-INF/flows/hellojohn/, а в ній файл hellojohn-flow.xml:
<?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="user"
class="com.seostella.swfhellojohn.domain.User"/>
<subflow-state id="identifyUser" subflow="hellojohn/user">
<output name="user" value="user"/>
<transition on="userReady" to="hellojohn" />
</subflow-state>
<view-state id="hellojohn">
<transition to="endState" />
</view-state>
<end-state id="endState" />
</flow>
З нових елементів - var і subflow-state. var - змінна, яка ініціалізується при старті flow і буде доступна під час виконання flow. class - клас змінної, який повинен реалізовувати інтерфейс java.io.Serializable.
При старті управління передається елементу subflow-state з ідентифікатором identifyUser. У свою чергу стан subflow-state означає, що поточний flow передає управління іншому flow, шлях до якого міститься в атрибуті subflow тега subflow-state. В нашому випадку це flow під назвою hellojohn/user.
Можливість передачі управління від одного flow іншому створена для полегшення написання коду. Коли кількість станів починає обчислюватися десятками або сотнями, набагато легше об'єднати кілька станів в один flow, тим самим поліпшити якість читання коду. Отже, subflow-state містить 2 атрибута: id (унікальний ідентифікатор) і subflow (шлях до flow, якому передається управління).
<output name="user" value="user"/>
- цією конструкцією ми передаємо змінну user в flow hellojohn/user. Якщо в дочірньому flow змінній присвоється інше значення, то вона сама зміниться і в батьківському flow.
<transition on="userReady" to="hellojohn" />
- означає, що після виконання стану userReady дочірнього flow, управління передається стану hellojohn. Між тим, userReady є також кінцевим станом hellojohn/user.
Також в цьому flow є один стан-відображення з ідентифікатором hellojohn. Як було сказано в першій частині статті, для відображення буде обраний файл з таким же ім'ям, тобто, hellojohn.jspx:
<html xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:form="http://www.springframework.org/tags/form">
<jsp:output omit-xml-declaration="yes"/>
<jsp:directive.page contentType="text/html;charset=UTF-8" />
<head><title>Hello John - Spring Web Flow 2.x Tutorial | seostella.com</title></head>
<body>
<h2>Hello ${user.name}!!!</h2>
<p>Spring Web Flow 2.x Tutorial</p>
</body>
</html>
В конструкції "Hello ${user.name}!" замість тексту ${user.name} підставитися значення властивості name об'єкта user (тобто, ім'я, яке введе користувач).
Переходимо до дочірнього flow під назвою hellojohn/user. Цей flow повинен розташовуватися в піддиректорії user по відношенню до hellojohn. Створимо директорію /WEB-INF/flows/hellojohn/user і файл user-flow.xml в ній (структуру файлів директорії WEB-INF Ви можете переглянути на Рис.2):
<?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="user" class="com.seostella.swfhellojohn.domain.User"/>
<view-state id="welcome">
<transition on="nameEntered" to="createUser"/>
</view-state>
<action-state id="createUser">
<evaluate result="user" expression=
"hellojohnFlowActions.createUser(requestParameters.name)" />
<transition to="userReady" />
</action-state>
<end-state id="userReady">
<output name="user" />
</end-state>
</flow>
В даному flow присутній один стан-відображення. Це стан з ідентифікатором welcome. Тому створимо файл welcome.jspx:
<html xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:form="http://www.springframework.org/tags/form">
<jsp:output omit-xml-declaration="yes"/>
<jsp:directive.page contentType="text/html;charset=UTF-8" />
<head>
<title>Hello John - Spring Web Flow 2.x Tutorial | seostella.com</title>
</head>
<body>
<h2>Welcome! Please introduce yourself</h2>
<form:form>
<input type="hidden" name="_flowExecutionKey"
value="${flowExecutionKey}"/>
<input type="text" name="name"/><br/>
<input type="submit" name="_eventId_nameEntered"
value="Submit" />
</form:form>
</body>
</html>
Рис 3. Сторінка welcome.jspx
Вищеописана сторінка міститиме форму з трьома полями: прихований _flowExecutionKey, поле для введення тексту name і кнопка відправки даних Submit. Поле _flowExecutionKey і, відповідно, ${flowExecutionKey} необхідні для ідентифікації кожного з flow, які виконуються для користувача. Тобто, у кожного користувача буде свій унікальний _flowExecutionKey.
Поле name - це звичайне поле для введення тексту. Більш цікава кнопка для відправки форми, ім'я якої _eventId_nameEntered. Це означає, що після кліка на кнопці відбуватиметься подія nameEntered. Ця подія передається назад в flow, який продовжує виконання ланцюжка дій. Тобто, відбувається перехід на стан createUser як показано нижче:
<view-state id="welcome">
<transition on="nameEntered" to="createUser"/>
</view-state>
Розглянемо ще один стан createUser:
<action-state id="createUser">
<evaluate result="user" expression=
"hellojohnFlowActions.createUser(requestParameters.name)" />
<transition to="userReady" />
</action-state>
Це стан-дія, в якому виконується метод createUser об'єкта hellojohnFlowActions. Об'єкт hellojohnFlowActions - це екземпляр класу HellojohnFlowActions, код якого наведений нижче. requestParameters.name - текст, введений користувачем в текстовому полі name.
package com.seostella.swfhellojohn.flow;
import com.seostella.swfhellojohn.domain.User;
import org.springframework.stereotype.Component;
@Component
public class HellojohnFlowActions {
public User createUser(String name) {
User user = new User(name);
return user;
}
}
Після виконання методу createUser управління передається стану userReady, який є кінцевим в flow під назвою user. Тому, управління передається назад батьківському flow hellojohn:
...
<subflow-state id="identifyUser" subflow="hellojohn/user">
<output name="user" value="user"/>
<transition on="userReady" to="hellojohn" />
</subflow-state>
<view-state id="hellojohn">
<transition to="endState" />
</view-state>
...
Як легко здогадатися - рядок
<html xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:form="http://www.springframework.org/tags/form">
<jsp:output omit-xml-declaration="yes"/>
<jsp:directive.page contentType="text/html;charset=UTF-8" />
<head><title>Hello John - Spring Web Flow 2.x Tutorial | seostella.com</title></head>
<body>
<h2>Hello ${user.name}!!!</h2>
<p>Spring Web Flow 2.x Tutorial</p>
</body>
</html>
На цій сторінці користувач побачить вітання Hello %ім'я_користувача%. Наприклад, якщо Ви введете ім'я Bob, то Вам відобразиться Hello Bob! як показано нижче:
Рис 4. Сторінка hellojohn.jspx
Для запуску flow перейдіть на наступну адресу:
http://localhost:8080/SWFHelloJohn/hellojohn
Код веб-програми доступний за наступною адресою - Завантажити код Spring Web Flow HelloJohn
В заключній частині статті ми трохи модифікуємо програму. Користувачеві необхідно буде ввести ім'я, що містить не менше 3-х символів, для того, щоб побачити вікно вітання.
< | Spring Web Flow. Hi John! Частина 1. Налаштування програми | Spring Web Flow. Hi John! Частина 3. Модифікація | > |