2.4. クイックスタートサンプルの検証
2.4.1. helloworld クイックスタート
helloworld
クイックスタートは JBoss EAP に単純なサーブレットをデプロイする方法を示します。ビジネスロジックは Jakarta Contexts and Dependency Injection (Jakarta コンテキストと依存関係の挿入) Bean として提供されるサービスにカプセル化され、サーブレットに挿入されます。このクイックスタートに基づいて、サーバーを適切に設定および起動することができます。
コマンドラインを使用してこのクイックスタートをビルドしデプロイする手順の詳細については、helloworld
クイックスタートディレクトリーのルートにある README.html
ファイルを参照してください。このトピックでは、Red Hat CodeReady Studio を使用してクイックスタートを実行する方法を説明します (Red Hat CodeReady Studio がインストールされ、Maven が設定された状態で helloworld
クイックスタートがインポートされ、正常に実行されたことを前提とします)。
前提条件
- Red Hat CodeReady Studio をインストールします。手順については、Red Hat CodeReady StudioInstallation Guideの Installing CodeReady Studio stand-alone using the Installer を参照してください。
-
helloworld
クイックスタートを実行します。手順は Red Hat Developer Studio でのクイックスタートの実行 を参照してください。 -
Web ブラウザーを開いて、
http://localhost:8080/helloworld
でアプリケーションにアクセスし、helloworld クイックスタートが正常に JBoss EAP にデプロイされたことを確認します。
ディレクトリー構造の確認
helloworld
クイックスタートのコードは QUICKSTART_HOME/helloworld/
ディレクトリーにあります。helloworld
クイックスタートは、サーブレットと Jakarta Contexts and Dependency Injection Bean で設定されます。また、バージョン番号が 1.1 であり、bean-discovery-mode
が all
であるアプリケーションの WEB-INF
ディレクトリーに beans.xml
ファイルが含まれます。このマーカーファイルにより、WAR が Bean アーカイブとして識別され、JBoss EAP がこのアプリケーションで Bean を検索し、Jakarta Contexts and Dependency Injection をアクティベートするよう指示されます。
src/main/webapp/
ディレクトリーにクイックスタートのファイルが含まれます。このサンプルのすべての設定ファイルは、src/main/webapp/
内の WEB-INF/
ディレクトリーにあり、beans.xml
ファイルが含まれます。src/main/webapp/
ディレクトリーには index.html
ファイルも含まれています。このファイルは簡単なメタリフレッシュ (meta refresh) を使用して、ユーザーのブラウザーを http://localhost:8080/helloworld/HelloWorld にあるサーブレットにリダイレクトします。このクイックスタートには web.xml
ファイルは必要ありません。
コードの確認
パッケージの宣言とインポートはこれらのリストからは除外されています。完全リストはクイックスタートのソースコードで確認できます。
HelloWorldServlet
コードを確認します。HelloWorldServlet.java
ファイルはsrc/main/java/org/jboss/as/quickstarts/helloworld/
ディレクトリーにあります。このサーブレットが情報をブラウザーに送ります。例: HelloWorldServlet クラスコード
42 @SuppressWarnings("serial") 43 @WebServlet("/HelloWorld") 44 public class HelloWorldServlet extends HttpServlet { 45 46 static String PAGE_HEADER = "<html><head><title>helloworld</title></head><body>"; 47 48 static String PAGE_FOOTER = "</body></html>"; 49 50 @Inject 51 HelloService helloService; 52 53 @Override 54 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 55 resp.setContentType("text/html"); 56 PrintWriter writer = resp.getWriter(); 57 writer.println(PAGE_HEADER); 58 writer.println("<h1>" + helloService.createHelloMessage("World") + "</h1>"); 59 writer.println(PAGE_FOOTER); 60 writer.close(); 61 } 62 63 }
表2.1 HelloWorldServlet の詳細
行 注記 43
必要な作業は
@WebServlet
アノテーションを追加し、サーブレットにアクセスするために使用する URL にマッピングを提供するだけです。46〜48
各 Web ページには適切な形式の HTML が必要になります。本クイックスタートは静的な文字列を使用して最低限のヘッダーとフッターの出力を書き出します。
50〜51
これらの行は、実際のメッセージを生成する HelloService Jakarta Contexts and Dependency Injection Bean を挿入します。HelloService の API を変更しない限り、ビューレイヤーを変更せずに HelloService の実装を後で変更することが可能です。
58
この行はサービスを呼び出し、Hello World というメッセージを生成して HTTP 要求へ書き出します。
HelloService
コードを確認します。HelloService.java
ファイルはsrc/main/java/org/jboss/as/quickstarts/helloworld/
ディレクトリーにあります。このサービスは単にメッセージを返します。XML やアノテーションの登録は必要ありません。例: HelloService クラスコード
public class HelloService { String createHelloMessage(String name) { return "Hello " + name + "!"; } }
2.4.2. numberguess クイックスタート
numberguess
クイックスタートは単純な非永続アプリケーションを作成し、JBoss EAP にデプロイする方法を示します。情報は Jakarta Server Faces ビューを使用して表示され、ビジネスロジックは 2 つの Jakarta Contexts and Dependency Injection Bean にカプセル化されます。numberguess
クイックスタートでは 1 から 100 までの数字を当てるチャンスが 10 回与えられます。数字を選択した後、その数字が正解の数字よりも大きいかまたは小さいかが表示されます。
numberguess
クイックスタートのコードは QUICKSTART_HOME/numberguess/
ディレクトリーにあります。QUICKSTART_HOME
は JBoss EAP のクイックスタートをダウンロードし、展開したディレクトリーです。numberguess
クイックスタートは複数の Bean、設定ファイル、および Facelets Jakarta Server Faces ビューによって設定され、WAR モジュールとしてパッケージ化されています。
コマンドラインを使用してこのクイックスタートをビルドしデプロイする手順の詳細については、numberguess
クイックスタートディレクトリーのルートにある README.html
ファイルを参照してください。以下の例では、Red Hat CodeReady Studio を使用してクイックスタートを実行します。
前提条件
- Red Hat CodeReady Studio をインストールします。手順については、Red Hat CodeReady StudioInstallation Guideの Installing CodeReady Studio stand-alone using the Installer を参照してください。
-
numberguess
クイックスタートを実行します。手順については、Red Hat CodeReady Studio でのクイックスタートの実行 を参照し、手順のhelloworld
をnumberguess
に置き換えてください。 -
Web ブラウザーを開いて
http://localhost:8080/numberguess
でアプリケーションにアクセスし、numberguess クイックスタートが正常に JBoss EAP にデプロイされたことを確認します。
設定ファイルの確認
このサンプルのすべての設定ファイルは、クイックスタートの QUICKSTART_HOME/numberguess/src/main/webapp/WEB-INF/
ディレクトリーにあります。
faces-config.xml
ファイルを確認します。本クイックスタートは
faces-config.xml
ファイル名の Jakarta Server Faces 2.2 バージョンを使用します。Facelets の標準的なバージョンが Jakarta Server Faces 2.2 のデフォルトのビューハンドラーであるため、設定は必要ありません。このファイルはルート要素のみで設定され、JSF をアプリケーションで有効にする必要があることを示すマーカーファイルにすぎません。<faces-config version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"> </faces-config>
beans.xml
ファイルを確認します。beans.xml
ファイルには、1.1 のバージョン番号とall
のbean-discovery-mode
が含まれます。このファイルは WAR を Bean アーカイブとして識別するマーカーファイルで、JBoss EAP がこのアプリケーションで Bean を検索し、Jakarta Contexts and Dependency Injection をアクティベートするよう指示されます。<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd" bean-discovery-mode="all"> </beans>
このクイックスタートは web.xml
ファイルを必要としません。
2.4.2.1. Jakarta Server Faces コードの確認
Jakarta Server Faces はソースファイルに .xhtml
ファイル拡張子を使用しますが、レンダリングされたビューは .jsf
拡張子で提供されます。home.xhtml
ファイルは src/main/webapp/
ディレクトリーにあります。
例: Jakarta Server Faces のソースコード
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 Jakarta Contexts and Dependency Injection 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>
以下の行番号は、Red Hat CodeReady Studio でファイルを表示するときに示されるものに対応します。
表2.2 Jakarta Server Faces の詳細
線 | 注記 |
---|---|
36〜40 | これらはユーザーに送信できるメッセージ、Higher(より大きい) と Lower(より小さい) です。 |
45〜48 | ユーザーが数を選択するごとに数字の範囲が狭まります。有効な数の範囲が分かるようにこの文章は変更されます。 |
55〜58 | この入力フィールドは値式を使用して Bean プロパティーにバインドされます。 |
58 | ユーザーが誤って範囲外の数字を入力しないようにバリデーターのバインディングが使用されます。バリデーターがないと、ユーザーが範囲外の数字を使用する可能性があります。 |
59〜61 | ユーザーの選択した数字をサーバーに送る方法がなければなりません。ここでは、Bean 上のアクションメソッドをバインドします。 |
2.4.2.2. クラスファイルの確認
numberguess
クイックスタートのソースファイルはすべて QUICKSTART_HOME/numberguess/src/main/java/org/jboss/as/quickstarts/numberguess/
ディレクトリーにあります。パッケージの宣言とインポートはこれらのリストからは除外されています。完全リストはクイックスタートのソースコードで確認できます。
Random.java
修飾子コードの検証修飾子は、型を基にしたインジェクションの対象となる 2 つの bean 間のあいまいさを取り除くために使用されます。修飾子に関する情報は、JBoss EAPDevelopment Guideの Use a Qualifier to Resolve an Ambiguous Injection を参照してください。
@Random
修飾子は乱数のインジェクトに使用されます。@Target({ TYPE, METHOD, PARAMETER, FIELD }) @Retention(RUNTIME) @Documented @Qualifier public @interface Random { }
MaxNumber.java
修飾子コードの検証@MaxNumber
qualifier
は最大許可数の挿入に使用されます。@Target({ TYPE, METHOD, PARAMETER, FIELD }) @Retention(RUNTIME) @Documented @Qualifier public @interface MaxNumber { }
Generator.java
コードの検証Generator
クラスは、producer メソッドを介して乱数を作成し、producer メソッドを介して最大可能数を公開します。このクラスはアプリケーションスコープであるため、毎回異なる乱数になることはありません。@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; } }
Game.java
コードの検証セッションスコープのクラス
Game
は、アプリケーションのプライマリーエントリーポイントです。ゲームの設定や再設定、ユーザーが選択する数字のキャプチャーや検証、FacesMessage
によるユーザーへのフィードバック提供を行います。コンストラクト後の lifecycle メソッドを使用し、@Random Instance<Integer>
bean から乱数を取得することによりゲームを初期化します。このクラスの
@Named
アノテーションを見てください。このアノテーションは Jakarta Expression Language を使用して Bean が Jakarta Server Faces ビューにアクセスできるようにしたい場合のみ必要です。この場合#{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 Jakarta Server Faces 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); } } }