1.5. Seam ページフロー : 数字当てゲームサンプル


自由型ナビゲーション (アドホック) 付きの Seam アプリケーションの場合、 ページフローの定義には JSF / Seam ナビゲーションルールが適しています。 ただし、 画面遷移に制約が多いスタイルのアプリケーションの場合、 特にさらにステートフルなユーザーインタフェースの場合、 ナビゲーションルールではシステムの流れを本当に理解するのは困難です。 ビューページ、 アクション、 ナビゲーションルールからの情報を組み合わせて考えると、このフローが理解し易くなります。
Seam では次に示す数字当てゲームのサンプルに見られるように、ページフローの定義に jPDL プロセス定義を使用することができます。

1.5.1. コードの理解

このサンプルは 1 つの JavaBean、3 つの JSP ページ、それと 1 つの jPDL プロセスフロー定義を使用します。 ページフローから見ていきましょう。

例1.23 pageflow.jpdl.xml

<pageflow-definition 
    xmlns="http://jboss.com/products/seam/pageflow"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://jboss.com/products/seam/pageflow 
                        http://jboss.com/products/seam/pageflow-2.2.xsd"
    name="numberGuess">
  
  <start-page name="displayGuess" view-id="/numberGuess.jspx">                        
    <redirect/>
    <transition name="guess" to="evaluateGuess">                                      
      <action expression="#{numberGuess.guess}"/>                                     
    </transition>
    <transition name="giveup" to="giveup"/>
    <transition name="cheat" to="cheat"/>
  </start-page>
  
  <decision name="evaluateGuess" expression="#{numberGuess.correctGuess}">            
    <transition name="true" to="win"/>
    <transition name="false" to="evaluateRemainingGuesses"/>
  </decision>
  
  <decision name="evaluateRemainingGuesses" expression="#{numberGuess.lastGuess}">
    <transition name="true" to="lose"/>
    <transition name="false" to="displayGuess"/>
  </decision>
  
  <page name="giveup" view-id="/giveup.jspx">
    <redirect/>
    <transition name="yes" to="lose"/>
    <transition name="no" to="displayGuess"/>
  </page>
  
  <process-state name="cheat">
    <sub-process name="cheat"/>
    <transition to="displayGuess"/>
  </process-state>
  
  <page name="win" view-id="/win.jspx">
    <redirect/>
    <end-conversation/>
  </page>
  
  <page name="lose" view-id="/lose.jspx">
    <redirect/>
    <end-conversation/>
  </page>
  
</pageflow-definition>
Copy to Clipboard Toggle word wrap

1

<page> エレメントは待ち状態を定義し、そこではシステムは特定の JSF ビューを表示し、ユーザー入力を待ちます。view-id は純粋な JSF ナビゲーションルールで使用されているのと同じ JSF ビュー ID です。ページに移動すると redirect 属性は Seam に post-then-redirect を使用するよう指示します (これにより使い易いブラウザ URL となります)。

2

<transition> エレメントは JSF 結果に名前を付けます。JSF アクションがその結果になると遷移が引き起こされます。jBPM 遷移アクションが呼び出された後、実行はページフローグラフの次のノードに進みます。

3

遷移の <action> は jBPM の遷移が起こるときに発生するという点以外は、JSF アクションのようなものです。遷移アクションはどの Seam コンポーネントでも呼び出すことが可能です。

4

<decision> ノードはページフローを分岐させ、 JSF EL 式を評価することによって次に実行するノードを決定します。
JBoss Developer Studio のページフローエディタではページフローは次のようになります。
このページフローを覚えておくと残りのアプリケーション部分を理解するのがとても簡単になります。
これがアプリケーションの中心のページ numberGuess.jspx です。

例1.24 numberGuess.jspx

<?xml version="1.0"?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" 
          xmlns:h="http://java.sun.com/jsf/html"
          xmlns:f="http://java.sun.com/jsf/core"
          xmlns:s="http://jboss.com/products/seam/taglib"
          xmlns="http://www.w3.org/1999/xhtml"
          version="2.0">
  <jsp:output doctype-root-element="html" 
              doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
              doctype-system=
              "http://www.w3c.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/>
  <jsp:directive.page contentType="text/html"/>
  <html>
    <head>
      <title>Guess a number...</title>
      <link href="niceforms.css" rel="stylesheet" type="text/css" />
      <script language="javascript" type="text/javascript" 
              src="niceforms.js" />
    </head>
    <body>
      <h1>Guess a number...</h1>
      <f:view>
        <h:form styleClass="niceform">
          
          <div>
            <h:messages globalOnly="true"/>
            <h:outputText value="Higher!" 
                          rendered="#{
                                    numberGuess.randomNumber gt 
                                    numberGuess.currentGuess}"/>
            <h:outputText value="Lower!" 
                          rendered="#{
                                    numberGuess.randomNumber lt 
                                    numberGuess.currentGuess}"/>
          </div>
          
          <div>
            I'm thinking of a number between 
            <h:outputText value="#{numberGuess.smallest}"/> and 
            <h:outputText value="#{numberGuess.biggest}"/>. You have 
            <h:outputText value="#{numberGuess.remainingGuesses}"/> 
            guesses.
          </div>
          
          <div>
            Your guess: 
            <h:inputText value="#{numberGuess.currentGuess}" 
                         id="inputGuess" required="true" size="3" 
                         rendered="#{
                                   (numberGuess.biggest-numberGuess.smallest) gt 
                                   20}">
              <f:validateLongRange maximum="#{numberGuess.biggest}" 
                                   minimum="#{numberGuess.smallest}"/>
            </h:inputText>
            <h:selectOneMenu value="#{numberGuess.currentGuess}" 
                             id="selectGuessMenu" required="true"
                             rendered="#{
                                       (numberGuess.biggest-numberGuess.smallest) le 
                                       20 and 
                                       (numberGuess.biggest-numberGuess.smallest) gt 
                                       4}">
              <s:selectItems value="#{numberGuess.possibilities}" 
                             var="i" label="#{i}"/>
            </h:selectOneMenu>
            <h:selectOneRadio value="#{numberGuess.currentGuess}" 
                              id="selectGuessRadio" 
                              required="true"
                              rendered="#{
                                        (numberGuess.biggest-numberGuess.smallest) le 
                                        4}">
              <s:selectItems value="#{numberGuess.possibilities}" 
                             var="i" label="#{i}"/>
            </h:selectOneRadio>
            <h:commandButton value="Guess" action="guess"/>
            <s:button value="Cheat" view="/confirm.jspx"/>
            <s:button value="Give up" action="giveup"/>
          </div>
          
          <div>
            <h:message for="inputGuess" style="color: red"/>
          </div>
          
        </h:form>
      </f:view>
    </body>
  </html>
</jsp:root>
Copy to Clipboard Toggle word wrap
アクションを直接呼び出す代わりに、 コマンドボタンが guess 遷移の名前付けを行っていることに注意してください。
win.jspx ページはごく普通のものです。

例1.25 win.jspx

<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" 
          xmlns:h="http://java.sun.com/jsf/html"
          xmlns:f="http://java.sun.com/jsf/core"
          xmlns="http://www.w3.org/1999/xhtml"
          version="2.0">
  <jsp:output doctype-root-element="html"
              doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
              doctype-system="http://www.w3c.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/>
  <jsp:directive.page contentType="text/html"/>
  <html>
    <head>
      <title>You won!</title>
      <link href="niceforms.css" rel="stylesheet" type="text/css" />
    </head>
    <body>
      <h1>You won!</h1>
      <f:view>
        Yes, the answer was 
        <h:outputText value="#{numberGuess.currentGuess}" />.
        It took you 
        <h:outputText value="#{numberGuess.guessCount}" /> guesses.
        <h:outputText value="But you cheated, so it doesn't count!" 
                      rendered="#{numberGuess.cheat}"/>
        Would you like to <a href="numberGuess.seam">play again</a>?
      </f:view>
    </body>
  </html>
</jsp:root>
Copy to Clipboard Toggle word wrap
lose.jspx はほぼ同じですのでここでは記載しません。
最後に、 実際のアプリケーションコードを見ましょう。

例1.26 NumberGuess.java

@Name("numberGuess")
@Scope(ScopeType.CONVERSATION)
public class NumberGuess implements Serializable {
   
   private int randomNumber;
   private Integer currentGuess;
   private int biggest;
   private int smallest;
   private int guessCount;
   private int maxGuesses;
   private boolean cheated;
   
   @Create                                                   
   public void begin()
   {
      randomNumber = new Random().nextInt(100);
      guessCount = 0;
      biggest = 100;
      smallest = 1;
   }
   
   public void setCurrentGuess(Integer guess)
   {
      this.currentGuess = guess;
   }
   
   public Integer getCurrentGuess()
   {
      return currentGuess;
   }
   
   public void guess()
   {
      if (currentGuess>randomNumber)
      {
         biggest = currentGuess - 1;
      }
      if (currentGuess<randomNumber)
      {
         smallest = currentGuess + 1;
      }
      guessCount ++;
   }
   
   public boolean isCorrectGuess()
   {
      return currentGuess==randomNumber;
   }
   
   public int getBiggest()
   {
      return biggest;
   }
   
   public int getSmallest()
   {
      return smallest;
   }
   
   public int getGuessCount()
   {
      return guessCount;
   }
   
   public boolean isLastGuess()
   {
      return guessCount==maxGuesses;
   }

   public int getRemainingGuesses() {
      return maxGuesses-guessCount;
   }

   public void setMaxGuesses(int maxGuesses) {
      this.maxGuesses = maxGuesses;
   }

   public int getMaxGuesses() {
      return maxGuesses;
   }

   public int getRandomNumber() {
      return randomNumber;
   }

   public void cheated()
   {
      cheated = true;
   }
   
   public boolean isCheat() {
      return cheated;
   }
   
   public List<Integer> getPossibilities()
   {
      List<Integer> result = new ArrayList<Integer>();
      for(int i=smallest; i<=biggest; i++) result.add(i);
      return result;
   }
   
}
Copy to Clipboard Toggle word wrap

1

初めて JSP ページが numberGuess コンポーネントを求めると、Seam によりそのページに対し新しいコンポーネントが作成され、@Create メソッドが呼び出され、コンポーネントがそれ自体を初期化することができます。
pages.xml ファイルにより Seam の 対話 が開始し、対話のページフローに使用するページフロー定義を指定します。詳細は 8章対話とワークスペースの管理 を参照してください。

例1.27 pages.xml

<?xml version="1.0" encoding="UTF-8"?>
<pages xmlns="http://jboss.com/products/seam/pages"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.2.xsd">
  <page view-id="/numberGuess.jspx">
    <begin-conversation join="true" pageflow="numberGuess"/>
  </page>
</pages>
Copy to Clipboard Toggle word wrap
このコンポーネントは純粋なビジネスロジックです。 ユーザーインタラクションのフローについての情報は必要としないため、 再利用できる可能性が高くなります。
トップに戻る
Red Hat logoGithubredditYoutubeTwitter

詳細情報

試用、購入および販売

コミュニティー

Red Hat ドキュメントについて

Red Hat をお使いのお客様が、信頼できるコンテンツが含まれている製品やサービスを活用することで、イノベーションを行い、目標を達成できるようにします。 最新の更新を見る.

多様性を受け入れるオープンソースの強化

Red Hat では、コード、ドキュメント、Web プロパティーにおける配慮に欠ける用語の置き換えに取り組んでいます。このような変更は、段階的に実施される予定です。詳細情報: Red Hat ブログ.

会社概要

Red Hat は、企業がコアとなるデータセンターからネットワークエッジに至るまで、各種プラットフォームや環境全体で作業を簡素化できるように、強化されたソリューションを提供しています。

Theme

© 2025 Red Hat