第3回 JSFベースのプレゼンテーション・デザインを考える


西ヶ谷岳(サン・マイクロシステムズ)
2005/8/27

  Page.1 Page.2

 第2回「鍵はPOJOベースのアプリケーション・デザイン」では、JSF、Spring、HibernateがPOJOベースのアプリケーション・アーキテクチャをサポートするプラットフォームであることの概要を説明しました。3回目となる今回はJSFに注目し、プレゼンテーション層のデザイン方法について解説します。以下の解説は、JSFの機能を網羅するものではないことに注意してください。JSFが持つDIコンテナとして特長を利用し、POJOベースのプレゼンテーション層のデザイン方法を理解していただくことを目的としています。

 POJOを意識してJSFベースのプレゼンテーションを
 デザインする

 前回述べたように、JSFはPOJOベースでアプリケーションを設計しやすいプラットフォームであることが大きな特徴になっています。POJOとして定義したビジネス・オブジェクト(アプリケーションで使用する特定のデータ構造のクラス)は、インテグレーション層ではHibernateによって、POJOのままデータベースの入出力に使用することができます。これと同様にプレゼンテーション層にJSFを利用することにより、Webブラウザとの入出力にPOJOなビジネス・オブジェクトをそのまま使用することができます。

 例えば顧客情報を検索するWebアプリケーションを考えてみましょう。このアプリケーションでは、図1に示すビジネス・オブジェクトを扱うものとします。

図1 ビジネス・オブジェクトの例

 顧客情報の主となるオブジェクトはCustomerBOクラスです。顧客名は姓(first)と名(last)から構成されるため、これをCustomerNameBOクラスとして分離し、CustomerBOとコンポジションの関係になるように定義します。また、顧客が属する会社情報については、CompanyBOクラスとして定義し、CustomerBOからmany-to-oneの関連を持つものとします。

 ここではまだ、これらのビジネス・オブジェクトとデータベース・テーブルとのマッピングは考えないものとします。ちょうど、ユースケースから抽出したドメイン・モデルを、トップダウン手法で意味的な粒度のオブジェクトに具体化した状態のものと考えてください。

 ページ・セントリック・デザイン

 次に、顧客情報の検索結果を表示する検索画面の構成要素を考えます。検索画面のイメージは図2のように、画面の上半分に検索条件の入力フォームがあり、下半分に検索結果をリスト形式で出力するものとします。

図2 検索画面の例

 JSFではStrutsと同等のMVCモデルを基本としながら、ASP.NETのWebFormと同様のページ・セントリックなコントローラ(バッキング・ビーンと呼びます)を定義することができます。JSFページは、従来のJSPページよりもMVCモデルのビューとしての役割に徹し、ボタンやリンクがクリックされたときのロジックはすべてバッキング・ビーンが担うことになります。バッキング・ビーンには、フィールドの値が変更された時のイベント・リスナやボタンが押されたときのアクション・メソッドを定義します。

 JSFの仕様上の制約ではありませんが、通常1つのJSFページに対して、1つのバッキング・ビーンを定義するのが一般的です。例えば、顧客情報検索画面のJSFページlist.jspを用意する場合、それに対応して1対1の関係でListBean.javaというバッキング・ビーンを定義するとよいでしょう。そして、list.jspに配置された複数のコントロール(ボタンやリンク)に対するイベント・リスナやアクション・メソッドは、対応するListBean.javaにすべて定義するようにします。このように、プレゼンテーション層の振る舞いをページ・セントリックにデザインすることで、設計効率と保守性の高いコンポーネントに仕上げることができます。

 顧客検索画面の例に戻って、バッキング・ビーンに必要な定義を考えます。バッキング・ビーンには、基本的に以下の3つのコンポーネントを関連付けておきます。

  1. ユーザーからの入力データを格納するオブジェクト
  2. 1の入力を基にビジネスロジックを実行するサービス・オブジェクト
  3. 2のサービス・オブジェクトの実行結果を格納するオブジェクト


 顧客検索の入力としては顧客名と会社名を考え、これをCustomerCriteriaクラスとして定義します。また、検索ロジックを実行するサービス・オブジェクトにはCustomerServiceインターフェイスを定義し、CustomerCriteriaを引数とするfindCustomer()メソッドを用意します。また、findCustomer()メソッドの実行結果は、CustomerBOオブジェクトのリストになります。これらをすべて、バッキング・ビーンListBeanのプロパティとして関連付けると図3のようになります。

図3 バッキング・ビーンListBeanと関連コンポーネント

 「関係付ける」とはいっても、Javaのソースコード上ではコンポーネント間の関係をビーン・プロパティ(setterおよびgetterメソッド)で定義するだけです。実際のコンポーネント間の結合は、JSFランタイムが設定ファイルに従ってワイヤリングしてくれます。バッキング・ビーンとコンポーネント間のワイヤリングは、JSF設定ファイルにおける<managed-bean>タグの定義に基づいて行われます。以下に、図3に示したコンポーネントの関連をJSF設定ファイルで定義した場合の例を示します。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE faces-config PUBLIC 
  "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN" 
  "http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
<faces-config>
  <application>
    <variable-resolver>
      org.springframework.web.jsf.DelegatingVariableResolver
    </variable-resolver>
  </application>

  <managed-bean>
    <description>顧客検索画面</description>
    <managed-bean-name>listBean</managed-bean-name>

    <managed-bean-class>
      com.example.web.ListBean
    </managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
    <managed-property>
      <property-name>criteria</property-name>
      <value>#{criteria}</value>
    </managed-property>
    <managed-property>
      <property-name>customerService</property-name>
      <value>#{customerService}</value>
    </managed-property>
  </managed-bean>

  <managed-bean>
    <description>検索条件</description>
    <managed-bean-name>criteria</managed-bean-name>
    <managed-bean-class>
      com.example.business.CustomerCriteria
    </managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
  </managed-bean>
</faces-config>

 最初の<managed-bean>タグでは、ListBeanオブジェクトを名前listBeanで参照することを定義しています。また、<managed-property>タグでListBeanオブジェクトのプロパティcriteriaに名前criteriaで宣言された別のmanaged-beanを関連付けることを宣言しています。2つの目のmanaged-beanに名前criteriaのCustomerCriteriaオブジェクトが宣言されていますので、これをListBeanオブジェクトのsetCriteria(CustomerCriteria)メソッドを通じてセッター・インジェクションされることが分かります。

 このように、基本的には関連付けられるオブジェクトはすべて<managed-bean>タグで宣言しておく必要がありますが、ListBeanオブジェクトのプロパティcustomerServiceに設定されている名前customerServiceのオブジェクトは、<managed-bean>タグの宣言がないことに注意してください。ここでは名前customerServiceのオブジェクトはサービス・オブジェクトであり、ビジネス層のSpringフレームワークにより管理されることを想定しています。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC
  "-//SPRING//DTD BEAN//EN"
  "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
  <!-- サービスオブジェクト:CustomerService -->
  <bean name="customerService"
        class="com.example.business.CustomerServiceImpl">
  </bean>
</beans>

 通常、Spring管理下のオブジェクトをJSFのmanaged-beanとして参照することはできません。しかし、JSFのVariableResolverをSpringフレームワークのカスタムVariableResolverに置き換えることによって、"#{customerService}"のようなJSF-ELを用いてSpring管理下のオブジェクトが参照できるようになります。

    <application>
    <variable-resolver>
      org.springframework.web.jsf.DelegatingVariableResolver
    </variable-resolver>
  </application>

 このようにして、プレゼンテーション層のJSFとビジネス層のSpringフレームワークは互いに異なる実装のDIコンテナでありながら、DelegatingVariableResolverのおかげで、両者のPOJOは互いの実装に依存することなく、シームレスに結合することができるわけです。このことは、POJOとして実装されたコンポーネントが、その配下のコンテナの実装に対して強い独立性を示している1つの証拠であり、同様にPOJOをサポートするJava EE 5においてもアプリケーション・コンポーネントの再利用の可能性を高めることができると予想できます。

  1/2

 INDEX

第3回 JSFベースのプレゼンテーション・デザインを考える

Page1
POJOを意識してJSFベースのプレゼンテーションをデザインする
ページ・セントリック・デザイン

  Page2
JSFページとバッキング・ビーンをJSF-ELで関係付ける
画面遷移とパラメータの引き継ぎ
JSFをプレゼンテーション層に採用する場合の注意


Java Solution全記事一覧



Java Agile フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Java Agile 記事ランキング

本日 月間