Red Hat Training

A Red Hat training course is available for Red Hat JBoss Enterprise Application Platform

1.4.3.2. numberguess クイックスタート

概要

このクイックスタートでは、簡単なアプリケーションを作成して JBoss EAP 6 にデプロイする方法を示します。このアプリケーションは情報を保持しません。情報は JSF ビューを使用して表示され、ビジネスロジックは 2 つの CDI (コンテキストと依存性注入) Bean にカプセル化されます。numberguess クイックスタートでは、1 から 100 までの数字を推測する試みが 10 回行われます。数字を選択した後、その数字が正解の数字よりも大きいかまたは小さいかが表示されます。

numberguess のクイックスタートのコードは、QUICKSTART_HOME/numberguess ディレクトリーにあります。numberguess クイックスタートは複数の Bean、設定ファイル、および Facelets (JSF) ビューによって構成され、WAR モジュールとしてパッケージ化されています。
コマンドラインを使用してこのクイックスタートをビルドしデプロイする手順の詳細については、numberguess クイックスタートディレクトリーのルートにある README.html ファイルを参照してください。ここでは、Red Hat JBoss Developer Studio を使用してクイックスタートを実行する方法を示します。このトピックは、Red Hat JBoss Developer Studio をインストールし、Maven を設定し、numberguess クイックスタートをインポートして正常に実行したことを前提としています。

前提条件

手順1.11 設定ファイルの確認

この例のすべての設定ファイルは、クイックスタートの src/main/webapp/ ディレクトリーにある WEB-INF/ ディレクトリーに配置されています。
  1. faces-config.xml ファイルを確認します。
    本クイックスタートは faces-config.xml ファイル名の JSF 2.0 バージョンを使用します。Facelets の標準化されたバージョンは JSF 2.0 のデフォルトのビューハンドラーであるため、実際に設定する必要はありません。JBoss EAP 6 は、ここで JavaEE を超えています。この設定ファイルを含めると、JSF が自動的に設定されます。その結果、設定はルート要素のみで設定されます。
    19. <faces-config version="2.0"
    20.    xmlns="http://java.sun.com/xml/ns/javaee"
    21.    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    22.    xsi:schemaLocation="
    23.       http://java.sun.com/xml/ns/javaee>
    24.       http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd">
    25.      
    26. </faces-config>
    
  2. beans.xml ファイルを確認します。
    空の beans.xml ファイルもあります。これは、JBoss EAP 6 にこのアプリケーションで Bean を検索し、CDI をアクティブ化するように指示します。
  3. web.xml ファイルはありません
    クイックスタートには web.xml ファイルも必要ないことに注意してください。

手順1.12 JSF コードの確認

JSF はソースファイルに .xhtml ファイル拡張子を使用しますが、レンダリングされたビューは .jsf 拡張子で提供されます。
  • home.xhtml コードを調べます。
    home.xhtml ファイルは src/main/webapp/ ディレクトリーにあります。
    19. <html xmlns="http://www.w3.org/1999/xhtml"
    20.    xmlns:ui="http://java.sun.com/jsf/facelets"
    21.    xmlns:h="http://java.sun.com/jsf/html"
    22.    xmlns:f="http://java.sun.com/jsf/core">
    23.
    24. <head>
    25. <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    26. <title>Numberguess</title>
    27. </head>
    28.
    29. <body>
    30.    <div id="content">
    31.       <h1>Guess a number...</h1>
    32.       <h:form id="numberGuess">
    33.
    34.          <!-- Feedback for the user on their guess -->
    35.          <div style="color: red">
    36.             <h:messages id="messages" globalOnly="false" />
    37.             <h:outputText id="Higher" value="Higher!"
    38.                rendered="#{game.number gt game.guess and game.guess ne 0}" />
    39.             <h:outputText id="Lower" value="Lower!"
    40.                rendered="#{game.number lt game.guess and game.guess ne 0}" />
    41.          </div>
    42.
    43.          <!-- Instructions for the user -->
    44.          <div>
    45.             I'm thinking of a number between <span
    46.                id="numberGuess:smallest">#{game.smallest}</span> and <span
    47.                id="numberGuess:biggest">#{game.biggest}</span>. You have
    48.             #{game.remainingGuesses} guesses remaining.
    49.          </div>
    50.
    51.          <!-- Input box for the users guess, plus a button to submit, and reset -->
    52.          <!-- These are bound using EL to our CDI beans -->
    53.          <div>
    54.             Your guess:
    55.             <h:inputText id="inputGuess" value="#{game.guess}"
    56.                required="true" size="3"
    57.                disabled="#{game.number eq game.guess}"
    58.                validator="#{game.validateNumberRange}" />
    59.             <h:commandButton id="guessButton" value="Guess"
    60.                action="#{game.check}"
    61.                disabled="#{game.number eq game.guess}" />
    62.          </div>
    63.          <div>
    64.             <h:commandButton id="restartButton" value="Reset"
    65.                action="#{game.reset}" immediate="true" />
    66.          </div>
    67.       </h:form>
    68.
    69.    </div>
    70.
    71.    <br style="clear: both" />
    72.
    73. </body>
    74. </html>
    

    表1.2 JSF の詳細

    注記
    36〜40 これらはユーザーに送信できるメッセージ、「Higher」(より大きい) と「Lower」(より小さい) です。
    45〜48 ユーザーが数を選択するごとに数字の範囲が狭まります。有効な数の範囲が分かるようにこの文章は変更されます。
    55〜58 この入力フィールドは値式を使用して Bean プロパティーにバインドされます。
    58 ユーザーが誤って範囲外の数字を入力しないようにバリデーターのバインディングが使用されます。バリデーターがないと、ユーザーが範囲外の数字を使用する可能性があります。
    59〜61 ユーザーの選択した数字をサーバーに送る方法がなければなりません。ここでは、Bean 上のアクションメソッドをバインドします。

手順1.13 クラスファイルの確認

すべての numberguess クイックスタートソースファイルは、src/main/java/org/jboss/as/quickstarts/numberguess/ ディレクトリーにあります。パッケージの宣言とインポートはこれらのリストからは除外されています。完全リストはクイックスタートのソースコードで確認できます。
  1. Random.java 修飾子コードの検証
    修飾子は、型を基にしたインジェクションの対象となる 2 つの bean 間のあいまいさを取り除くために使用されます。修飾語の詳細については、以下を参照してください。 「修飾子を使用したあいまいなインジェクションの解決」
    @Random 修飾子は乱数のインジェクトに使用されます。
    @Target({ TYPE, METHOD, PARAMETER, FIELD })
    @Retention(RUNTIME)
    @Documented
    @Qualifier
    public @interface Random {
    
    }
  2. MaxNumber.java 修飾子コードの検証
    @MaxNumber qualifier は最大許可数の挿入に使用されます。
    @Target({ TYPE, METHOD, PARAMETER, FIELD })
    @Retention(RUNTIME)
    @Documented
    @Qualifier
    public @interface MaxNumber {
    
    }
  3. Generator.java コードの検証
    Generator クラスは、プロデューサーメソッドを介して乱数を作成するロールを果たします。また、プロデューサーメソッドを介して可能な最大数を公開します。このクラスはアプリケーションスコープであるため、毎回異なる乱数になることはありません。
    @SuppressWarnings("serial")
    @ApplicationScoped
    public class Generator implements Serializable {
    
        private java.util.Random random = new java.util.Random(System.currentTimeMillis());
    
        private int maxNumber = 100;
    
        java.util.Random getRandom() {
            return random;
        }
    
        @Produces
        @Random
        int next() {
            // a number between 1 and 100
            return getRandom().nextInt(maxNumber - 1) + 1;
        }
    
        @Produces
        @MaxNumber
        int getMaxNumber() {
            return maxNumber;
        }
    }
  4. Game.java コードの検証
    セッションスコープのクラス Game は、アプリケーションの主要なエントリーポイントです。ゲームの設定や再設定、ユーザーが選択する数字のキャプチャーや検証、FacesMessage によるユーザーへのフィードバック提供を行います。コンストラクト後の lifecycle メソッドを使用し、@Random Instance<Integer> bean から乱数を取得することによりゲームを初期化します。
    このクラスの @Named アノテーションを見てください。このアノテーションは式言語 (EL) を使用して Bean が JSF ビューにアクセスできるようにしたい場合のみ必要です。この場合 #{game} が EL になります。
    @SuppressWarnings("serial")
    @Named
    @SessionScoped
    public class Game implements Serializable {
    
        /**
         * The number that the user needs to guess
         */
        private int number;
    
        /**
         * The users latest guess
         */
        private int guess;
    
        /**
         * The smallest number guessed so far (so we can track the valid guess range).
         */
        private int smallest;
    
        /**
         * The largest number guessed so far
         */
        private int biggest;
    
        /**
         * The number of guesses remaining
         */
        private int remainingGuesses;
    
        /**
         * The maximum number we should ask them to guess
         */
        @Inject
        @MaxNumber
        private int maxNumber;
    
        /**
         * The random number to guess
         */
        @Inject
        @Random
        Instance<Integer> randomNumber;
    
        public Game() {
        }
    
        public int getNumber() {
            return number;
        }
    
        public int getGuess() {
            return guess;
        }
    
        public void setGuess(int guess) {
            this.guess = guess;
        }
    
        public int getSmallest() {
            return smallest;
        }
    
        public int getBiggest() {
            return biggest;
        }
    
        public int getRemainingGuesses() {
            return remainingGuesses;
        }
    
        /**
         * Check whether the current guess is correct, and update the biggest/smallest guesses as needed. Give feedback to the user
         * if they are correct.
         */
        public void check() {
            if (guess > number) {
                biggest = guess - 1;
            } else if (guess < number) {
                smallest = guess + 1;
            } else if (guess == number) {
                FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Correct!"));
            }
            remainingGuesses--;
        }
    
        /**
         * Reset the game, by putting all values back to their defaults, and getting a new random number. We also call this method
         * when the user starts playing for the first time using {@linkplain PostConstruct @PostConstruct} to set the initial
         * values.
         */
        @PostConstruct
        public void reset() {
            this.smallest = 0;
            this.guess = 0;
            this.remainingGuesses = 10;
            this.biggest = maxNumber;
            this.number = randomNumber.get();
        }
    
        /**
         * A JSF validation method which checks whether the guess is valid. It might not be valid because there are no guesses left,
         * or because the guess is not in range.
         * 
         */
        public void validateNumberRange(FacesContext context, UIComponent toValidate, Object value) {
            if (remainingGuesses <= 0) {
                FacesMessage message = new FacesMessage("No guesses left!");
                context.addMessage(toValidate.getClientId(context), message);
                ((UIInput) toValidate).setValid(false);
                return;
            }
            int input = (Integer) value;
    
            if (input < smallest || input > biggest) {
                ((UIInput) toValidate).setValid(false);
    
                FacesMessage message = new FacesMessage("Invalid guess");
                context.addMessage(toValidate.getClientId(context), message);
            }
        }
    }