本連載では、サンプル・アプリケーションの開発を通じて Java Platform, Enterprise Edition 6 (Java EE 6)の仕様とその魅力をお伝えすることを目的としています。今回から2回にわたって、 JavaServer Faces (JSF)をとりあげます。現在は Web ベースの企業システムが広く普及していますが、リッチなユーザー・インタフェースへのニーズの高まりやスマートフォン/タブレットなどのマルチチャネル・アクセスなど、アプリケーションの複雑性は増す一方です。 JSF は Java EE における Web アプリケーション開発のための標準フレームワークです。今回は、 JSF を利用することで Web アプリケーション、特にユーザー・インタフェース開発がどのように効率化できるかを説明します。(日本オラクル Fusion Middleware 事業統括本部智野潤子) |
JSF の特長
JSF は MVC モデル2に基づいたフレームワークです。 MVC モデル2に基づいた Web アプリケーション開発フレームワークは、 Apache Struts など、これまでにも数多く提供されてきました。 JSF が旧来のフレームワークと異なるのは、ユーザー・インタフェースの開発を効率化することにフォーカスしている点です。 JSF の特長は次のようにまとめることができます。
- UIコンポーネントの提供JSF では、ボタンや入力フォームなどユーザー・インタフェースを構成する部品を「UI コンポーネント」として提供しています。 UI コンポーネントは、拡張性、再利用性が十分に考慮されて設計されています。また、プロパティの設定値によって振る舞いや見た目をカスタマイズできることから、カスタム・タグやスクリプトレットを中心とした旧来の Web アプリケーション開発と比べて IDE (統合開発環境)との親和性がとても高いです。
- サードパーティ製の UI コンポーネントの利用JSF の実装が提供する UI コンポーネントだけでなく、サードパーティ製の UI コンポーネントも提供されます。例えば、オラクルではADF Facesという JSF コンポーネント群を提供しています。 ADF Faces は、ツリーやグラフ、ピボット・テーブルなど、JSF 標準の UI コンポーネントにはない、高度な UI コンポーネントを多数提供しています(Oracle ADF Faces Hosted Components Demoでは、実際に ADF Faces を利用したサンプル・アプリケーションが公開されています)。
- イベント・ドリブンなプログラミング・モデルUI コンポーネントは、「ボタンが押された」「テキスト・フィールドの値が変わった」といった「イベント」を処理する機能を提供します。このイベント・ドリブンなプログラミング・モデルを採用した JSF は、 HTTP リクエスト/レスポンスを強く意識する必要があった旧来の Web アプリケーションよりも、 Ajax を活用しやすいです。
JSF は Java プラットフォームの標準化プロセスである Java Community Process(JCP)によって仕様が策定されています。 Java EE 6に採用されているJSF 2.0はJSR-314で規定されています。 JSF 2.0では、Facelets の導入やアノテーションのサポート、ページ・ナビゲーション機能の改善など、強力な新機能が追加されました。今回は、JSFの基本的な機能に加えて JSF 2.0の主要な新機能についても説明していきます。
作成するアプリケーション
今回から2回にわたって作成するアプリケーションは、数字当てゲームです。ルールと処理の流れは次のとおりです。
- ユーザーがアプリケーションにアクセスすると、開始ページが表示されます。
- ユーザーは開始ページに名前を入力し、「開始」ボタンをクリックします。
- 名前の入力は必須です。
- 名前が5文字未満の場合は、再入力を求められます。
- サーバー上で正解の数字が生成されゲーム・ページが表示されます。
- ユーザーはゲーム・ページに0から9までの整数から3つを入力します。
- 「077」「888」のように同じ数字を1度に2回以上入力することはできません。
- 数字以外の文字を入力した場合は再入力を求められます。
- ユーザーが「回答」ボタンをクリックすると、入力した数字がサーバーに送信され、正解の数字とを比較します。
- ユーザーが入力した数字が正解の場合は、ゲーム・ページに正解だったことを知らせるメッセージが表示されます。
- ユーザーが入力した数字が不正解の場合は、ヒントとして数字と順番が合っていた個数(Hit)、数字は合っているが順番は合っていない個数(Blow)が表示されます。
- 正解が「012」、ユーザーが入力した数字が「024」の場合は「1 Hit/1 Blow」
- ユーザーが入力した数字と Hit/Blow の数は回答履歴に残ります。
- 「やり直し」ボタンをクリックすると、最初の画面に戻ります。
今回は次の機能を実装していきます。
- 開始ページとゲーム・ページの共通部分を定義したページ・テンプレートの作成
- 開始ページの作成
- ゲーム・ページの作成
- データの受け渡しの設定
- ページ・ナビゲーションの設定
アプリケーション開発の準備
本連載では、 Oracle Enterprise Pack for Eclipse (OEPE)を使用してサンプル・アプリケーションの開発を進めます。 OEPE や WebLogic Server 12c のインストールおよび設定が終わっていない方は、前回の記事「[連載] WebLogic Server 12cでJava EE 6 を動かしてみよう!(1) 概要」を参考にしてください。
ここでは、Eclipse のプロジェクトを作成します。 Eclipse のメニュー・バーから「New」→「Dynamic Web Project」を選択します。「New Dynamic Web Project」ウィンドウが表示されたら、「Project Name」として「jsfsample」、「Configuration」として「JavaServer Faces v2.0 Project」を選択し、「Finish」ボタンをクリックします。
- WebContent/index.xhtmlデフォルトのJSFページです。
- WebContent/WEB-INF/faces-config.xmlJSF の構成ファイルです。エラー・メッセージの国際化などに使用するリソース・バンドルの情報が記述されています。
- WebContent/WEB-INF/web.xmlJSF のフロント・コントローラの役割を担う FacesServlet の定義情報が記述されています。
- WebContent/WEB-INF/weblogic.xmlWebLogic Server 固有のデプロイメント・ディスクリプタです。
- src/resources/application.propertiesfaces-config.xml に登録されたリソース・バンドルのソースです。
ページ・テンプレートの作成
JSF 1.2 までは、ページをJSPで記述する必要があり、UI コンポーネントは JSP のカスタム・タグ・ライブラリの形式で提供されていました。 JSP と JSF はリクエストを処理するライフサイクルが異なるので、HTML タグと UI コンポーネントが混在しているようなページでは、開発者が意図したデザインにならないことがありました。
JSF 2.0 では、Facelets という XML ドキュメントでページを定義します。 Facelets が導入されたことで、JSF 1.2においてJSPに起因する問題が解消されるだけでなく、JSP コンパイラによるオーバヘッドが発生しないので、パフォーマンス向上の効果も期待できます。
また、Facelets はページの共通部分を外出しにするテンプレートを作成することができます。今回は HTML タグを使用して Web ページのレイアウトを定義するので、 Facelets は XHTML 形式で作成します。テンプレートには、次の3つを定義します。
- ページごとに定義された「title」によってページ・タイトルを指定(
ui:insert
タグ) - すべてのページで共通のページ・ヘッダー
- ページごとに定義された「content」を表示(
ui:insert
タグ)
XHTML ファイルを作成するには、Eclipse のメニュー・バーから「File」→「New」→「XHTML Page」を選択します。「New XHTML Page」ウィンドウの「HTML」画面では、「Enter or select the parent folder」に「jsfsample/WebContent」を、「File name」に「template.xhtml」と入力して、「次へ」をクリックします(図3)。
「New XHTML Page」ウィンドウの「Select XHTML Template」ページでは、「Use HTML Template」をチェックし、「New JavaServer Faces (JSF) Page (XHTML)」を選択して「Finish」をクリックします(図4)。
図3: 「New XHTML Page」ウィンドウ 「HTML」ページ(クリックして拡大) | 図4: 「New XHTML Page」ウィンドウ 「Select XHTML Template」ページ(クリックして拡大) |
テンプレートの定義で使用するui:insert
タグを使用するためには、 template.xhtml にネームスペースとして「xmlns:ui="http://java.sun.com/jsf/facelets"
」を追加します。
template.xhtml のソースは次のようになります。
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><!-- a. ページごとに定義するページ・タイトル --><title><ui:insert name="title">JFS Template</ui:insert></title></head><body><!-- b. 全ページで共通のページ・ヘッダー --><div id="header" style="background-color:#F00; color:#FFF"><h1>数字当てゲーム</h1></div><!-- c. 各ページで異なるコンテンツを表示する領域 --><ui:insert name="content">ページごとのコンテンツ</ui:insert></body></html>
開始ページの作成
- 適用するテンプレートを指定(
ui:composition
タグ) - ページごとに固有の設定(title/content)を指定(
ui:define
タグ) - HTTP ポスト・リクエストを送信するための
form
タグ(h:form
タグ) - 名前を入力するためのテキスト・フィールド(
h:inputText
タグ) - 入力された名前をサーバーに送信し、ゲームを開始するためのボタン(
h:commandButton
タグ)
今回は、プロジェクト作成時に生成された index.xhtml ファイルを次のように編集します。
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets"><!-- a. 適用するテンプレートの指定 --><ui:composition template="template.xhtml"><!-- b. ページ固有の設定(title)を指定 --><ui:define name="title">ようこそ</ui:define><!-- b. ページ固有の設定(content)を指定 --><ui:define name="content"><!-- c. HTTPポスト・リクエストを送信するためのformタグ --><h:form><div> あなたのお名前は?<!-- d. 名前を入力するためのテキスト・フィールド --><h:inputText size="12"/><!-- e. 入力された名前をサーバーに送信し、ゲームを開始するためのボタン --><h:commandButton value="開始"/></div></h:form></ui:define></ui:composition></html>
ゲーム・ページの作成
- 適用するテンプレートを指定(
ui:composition
タグ) - ページごとに固有の設定(title/content)を指定(
ui:define
タグ) - HTTP ポスト・リクエストを送信するための form タグ(
h:form
タグ) - ユーザーへのメッセージ(
h:outputFormat
タグ/f:param
タグ) - 数字を入力するためのテキスト・フィールド(
h:inputText
タグ) - サーバーに回答を送信するためのボタン(
h:commandButton
タグ) - ゲームをやり直す(開始ページに戻る)ためのボタン(
h:commandButton
タグ)
template.xhtml を作成した時と同様の手順で、game.xhtml を作成します。game.xhtml のソースは次のとおりです。
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"><!-- a. 適用するテンプレートの指定 --><ui:composition template="template.xhtml"><!-- b. ページ固有の設定(title)を指定 --><ui:define name="title">数字当てゲーム</ui:define><!-- b. ページ固有の設定(content)を指定 --><ui:define name="content"><!-- c. HTTPポスト・リクエストを送信するためのformタグ --><h:form><div><!-- d. ユーザーへのメッセージ --><h:outputFormat value="{0}さん、{1}"><f:param value="ユーザー名"/><!-- {0}に入る値 --><f:param value="3つの異なる数字を入力してください。"/><!-- {1}に入る値--></h:outputFormat><!-- 実行時「ユーザー名さん、3つの異なる数字を入力してください。」と表示される--></div><div><!-- e. 数字を入力するためのテキスト・フィールド --><h:inputText size="2" maxlength="1"/><h:inputText size="2" maxlength="1"/><h:inputText size="2" maxlength="1"/><!-- f. サーバーに回答を送信するためのボタン --><h:commandButton value="回答"/><!-- g. ゲームをやり直すためのボタン --><h:commandButton value="やり直す"/></div><h2>回答履歴</h2><!-- 次回ここに回答履歴のテーブルを追加 --></h:form></ui:define></ui:composition></html>
データの受け渡しの設定
JSF では、テキスト・フィールドなどに入力されたデータの受け渡しに JavaBeans を使用します。それらの JavaBeans は、インスタンスの有効期間をスコープとして指定する必要があります。このスコープの設定に応じて JavaBeans のインスタンスのライフサイクルが Web コンテナによって管理されることから、JSF ではマネージド Bean と呼ばれます。 JSF 2.0 では、マネージド Bean のスコープとして次の6種類を設定できます。
- application: Web アプリケーションが起動してから終了するまでの間
- session: HTTP セッションが有効な間
- request: HTTP リクエストを受けてからレスポンスを返すまでの間
- view: ページがロードされてから他のページにナビゲートするまでの間【JSF 2.0新機能】
- flash: ページが別のページにナビゲートする間【JSF 2.0新機能】
- none: スコープには属さない(他のマネージド Bean から参照されるマネージド Bean などに使用)
jsfsample.UserBean
クラス)を作成します。このマネージド Bean はname
プロパティを持ち、ユーザーの名前を格納します。ユーザーの名前は2つの画面にまたがって保持したいので、スコープは session に設定します。jsfsample.UserBean
クラスのソースは次のとおりです。package jsfsample; import java.io.Serialized; @javax.faces.bean.ManagedBean // マネージドBeanであることを宣言するアノテーション @javax.faces.bean.SessionScope // このマネージドBeanがsessionスコープであることを表すアノテーション public class UserBean implements Serialized { private String name; // ユーザーの名前を格納するプロパティ public String getName() { return name; } public void setName(String name) { this.name = name; } }
JSF では、マネージド Bean に定義されたプロパティやアプリケーション・メソッドにアクセスするために、EL 式(Expression Language)を使用します。 EL 式は JSP 2.0 で導入された技術なので、使用したことがある開発者の方も多いと思います。 JSP と JSF は以前、それぞれ異なる EL 式の仕様を策定していましたが、 Java EE 5 以降は、JSP/JSF から独立した仕様として策定されています。マネージド Bean のプロパティにアクセスするための EL 式は、次のような形式になります。
#{マネージドBean名.プロパティ名}
今回のようにマネージド Bean をアノテーションで定義した場合、「マネージドBean名」は、クラス名の最初の文字を小文字に置き換えたものです。今回使用するマネージド Bean のクラス名はUserBean
なので、マネージド Bean 名は「userBean
」になります。なお、マネージド Bean 名は、明示的に指定することもできます。マネージド Bean 名を明示的に指定するには、アノテーション@ManagedBean
のname
属性を使用します。
@ManagedBean(name="mybean")
index.xhtml のテキスト・フィールド(h:inputTextタグ)に入力されたデータをUserBean
のname
プロパティに格納するためには、次のようにh:inputText
タグのvalue
属性に EL 式を追加します。
<h:inputText size="12"/>
<h:inputText size="12" value="#{userBean.name}"/>
index.xhtml で入力された名前(UserBean
のname
プロパティの値)を game.xhtml に表示させるためには、次の部分を変更します。
<f:param value="ユーザー名"/>
<f:param value="#{userBean.name}"/>
ページ・ナビゲーションの設定
JSF 1.2 では、あるページから別のページにナビゲートさせるためには、 faces-config.xml にナビゲーション・ルールを定義する必要がありあました。
<navigation-rule><from-view-id>/index.jsp</from-view-id><navigation-case><from-outcome>start</from-outcome><to-view-id>/game.jsp</to-view-id></navigation-case></navigation-rule>
上の例のようにナビゲーション・ルールが定義されている場合、 index.jsp に配置されたh:commandButton
タグ(ボタン)やh:commandLink
タグ(リンク)のaction
属性にナビゲーション・ルールで定義されたfrom-outcome
要素の値「start
」を指定することで、ボタン/リンクがクリックされた時に game.jsp にナビゲートされます。
JSF 2.0 からは、暗黙的ナビゲーションが使用できます。暗黙的ナビゲーションでは、action
属性にナビゲート先の Facelets ページの名前(拡張子は省略可能)を指定します。
faces-config.xml にナビゲーション・ルールを記述する必要はありません。今回のアプリケーションでは、 index.xhtml に定義した「開始」ボタンをクリックしたら game.xhtml にナビゲーションさせるので、次のようにh:commandButton
タグのaction
属性の値を「game
」と指定します。
<h:commandButton value="開始"/>
<h:commandButton value="開始" action="game"/>
game.xhtml に定義した「やり直し」ボタンをクリックした時に開始ページ(index.xhtml)にナビゲートする場合は、同様にh:commandButton
タグのaction
属性に「index
」を指定します。
<h:commandButton value="やり直す" />
<h:commandButton value="やり直す" action="index"/>
作成したアプリケーションを実行してみましょう。「Project Explorer」ペインで「jsfsample」→「WebContent」→「index.xhtml」を右クリックし、「Run as」→「Run on Server」を選択します。「Run on Server」ウィンドウが表示されたら、実行に使用するWebLogicドメインを選択し、「Finish」ボタンをクリックします(このとき、「Always use this server when running this project」をチェックしておくと、次回からは「Run on Server」ウィンドウがスキップされて便利です)。
エディタ・ウィンドウに開始ページが表示されたら、名前を入力して「開始」ボタンをクリックします(図8)。ゲーム・ページには、開始ページに入力した名前が表示されます。ゲーム・ページの「やり直し」ボタンをクリックしたら、開始ページに戻ります(図9)。
図8: 実行画面: 開始ページ (クリックして拡大) | 図9: 実行画面: ゲーム・ページ (クリックして拡大) |
まとめ
今回は JSF の特長について簡単に説明し、JSF ページを作成して画面遷移の設定を行いました。作成したアプリケーションでは次の JSF 2.0 の新機能を使用しました。
- Facelets
- ページ・テンプレート
- アノテーションによるマネージドBeanの定義
- 暗黙的ナビゲーション
次回は、ユーザーが入力したデータを変換するコンバータや検証するためのバリデータを設定したり、アプリケーション・ロジックを実装したりする予定です。また、Ajax テクノロジを使用した部分ページ・レンダリングの機能を使用します。