Spring Web Flow. Hi John! Частина 2. Написання програми

січня
12
2012
Мітки: spring spring web flow

Зміст

Як згадувалося раніше, 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
Рис 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
Рис 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>
    ...

Як легко здогадатися - рядок повідомляє, що при отриманні стану userReady необхідно перейти на стан 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 %ім'я_користувача%. Наприклад, якщо Ви введете ім'я Bob, то Вам відобразиться Hello Bob! як показано нижче:

Рис 4. Сторінка hellojohn.jspx
Рис 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. Модифікація >

Напишіть перше повідомлення!

Ви повинні увійти під своїм аккаунтом щоб залишати коментарі