先ほどのサンプルコードを見ただけでは、JSFはボタンに呼び出すメソッドを記述して画面遷移するだけのフレームワークと思われたかもしれません。実際、簡単なアプリケーションを作るのであればその理解だけで構いません。
ですが、ボタン以外のイベント処理を行うようなJSFの機能を使いこなすためには、JSFとStruts 1の根本的な設計思想の違いを知っておく必要があります。両者の違いを一言で表現すると、「Struts 1はアクションベースのフレームワークで、JSFはコンポーネントベースのフレームワークだ」と言えるでしょう。
アクションベースとは、URLによってサーバ側で実行するアクション(プログラム)を決定し、アクションのレスポンスとしてHTMLなどのデータを返す方式です。
HTTPの基本的な仕組みであるリクエストとレスポンスにのっとったシンプルな構成であり、Servlet(サーブレット)やStruts 1、前回紹介したJAX-RS、Spring MVC、Play Frameworkなど多くのフレームワークはアクションベースに分類できます。
アクションベースは、構造が単純で理解しやすく、拡張もしやすいといった特徴があります。
コンポーネントベースとは、HTTPを抽象化してViewを構成するパーツであるコンポーネントを中心に据えたフレームワークです。
先に示したサンプルコードでも、URLやHTTPリクエスト・レスポンスといったものが一切登場しませんでした。それは、JSFがHTTPを隠蔽(いんぺい)し、XHTMLに記述したコンポーネントの内容からViewの組み立てや、入力チェック、バッキングBeanへの入力値設定やメソッド呼び出しといった共通的な処理を内部で行っているためです。
コンポーネントベースは、Viewの再利用性を高め、コードの記述量を減らせるといった特徴があります。コンポーネントベースのフレームワークはJSFやApache Wicket、■http://www.atmarkit.co.jp/ait/articles/1303/26/news035.htmlASP.NETのWebForms■などが該当します。
アクションベースとコンポーネントベースの主な違いはViewにあります。アクションベースではViewはHTTPレスポンスに書き込むデータなので、HTMLの他、JSON、XMLなどさまざまな形式を扱えます。
コンポーネントベースではViewにコンポーネントを記述するといった決まりがあります。Controllerでもコンポーネントを前提としたコードを書く必要があります。
そのため、アクションベースは自由度が高く、WebアプリケーションやRESTベースのアプリケーションなど、適用範囲が広いといえます。しかし実装方法を自分で考える必要があります。
コンポーネントベースは実装ルールが決まっており、適用範囲も限定されます。実際JSFではHTMLベースのWebアプリケーションに限定されます。しかし、実装ルールに従えばコードの削減や再利用が望めます。
さて以降では、JSFならではの3つの特徴を紹介します。
リスト1のXHTMLには、「h:form」のような独自のFacelets要素がありました。
JSFでは、よりHTMLに近い形式でXHTMLを書くことができます。リスト1を書き直したものが以下です。
<?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:jsf="http://xmlns.jcp.org/jsf"> <!-- 割愛 --> <h1>ログイン</h1> <form class="form" jsf:id="form"> <div> <span jsfc="h:messages" id="message"/> </div> <input type="text" jsf:value="#{loginAction.id}" placeholder=”user1を入力” /> <input type="password" jsf:value="#{loginAction.password}" /> <input type="submit" jsfc="h:commandButton" action="#{loginAction.login}" value="ログイン"/> </form> <!-- 割愛 --> </html>
リスト3に登場する要素は全てHTMLにあるものだけです。そのためデザイナーが作ったHTMLの変換も容易になります。どうやってFaceletsのコンポーネントを指定しているのかというと、いくつかのHTML要素内に書かれている「jsfc」属性と、「jsf:value」などの「jsf:」で始まる属性が鍵となります。
「jsfc」属性は、JSFコンポーネントを属性値に記述する方法で、HTML形式でViewを定義する基本的な方法です。
「jsf:」で始まる属性は「パススルーエレメント」と呼ばれます。これはJSF 2.2 から導入されたコンポーネントを自動認識する仕組みであると同時に、HTML5の属性を扱うための仕組みでもあります。自動認識に対応している要素は「TagDecorator(Java EE 7 Specification APIs)」を参照してください。
Viewには、ヘッダやフッタなど、どの画面にも共通で出現する部分があったり、似たような記述を毎回しなければならないパーツのようなものがあったりします。Faceletsでは、前者に対してはテンプレート機能を、後者に対しては自作コンポーネントを提供することで、繰り返し登場するものを一元管理して再利用できるようにしています(この辺りの解説は割愛しますが、興味のある方はサンプルコードを参照してみてください)。
JSFコンポーネントはオープンソースで多数公開されています。例えば、「Oracle ADF」「PrimeFaces」などがあります。
これらの自作コンポーネントを導入することで、リッチなViewを簡単に作成できるようになります。
リッチなViewを作成しようとすると、ボタンを押したとき以外にも何らかの処理が必要となることがあります。
アクションベースのフレームワークでイベント処理を行うには、JavaScriptでAjaxを使用してデータを取得し、HTMLを変更するといったようなコードを書く必要があり、サーバサイド、クライアントサイドともに煩雑なコードが必要になります。
JSFではコンポーネントがイベントを検知したときに、バッキングBeanのメソッドを呼び出せるようになっており、その結果をJavaScriptのコードを書くことなしにAjaxで差分更新できるようになっています。
「3桁の国コードを入力すると、その隣に国名が表示される」という例で説明します。
まずは、Viewです。
<h:form> 国コード <h:inputText id="code" size="3" value="#{countryAction.code}" valueChangeListener="#{countryAction.find}"> <f:ajax execute="code" render="name" event="change"/> </h:inputText> :国名 <span jsf:id="name">#{countryAction.name}</span> </h:form>
ここでは入力項目に対して「valueChangeListener」という属性で、入力値が変わったときに実行するバッキングBeanのメソッドとして、「CountryAction」クラスのfindメソッドを指定しています。そして「f:ajax」タグでchangeイベントが起きたら、その結果をidが"name"のコンポーネントに反映するように指定しています。
このようにViewの中の一部だけを書き換える仕組みは、JSFがViewをコンポーネントの集合で管理しているために実現できています。
次に、バッキングBeanの内容です。
@RequestScoped @Named public class CountryAction { // 簡易的な国コードと国名のマップ private static final Map<String, String> map = new HashMap<String, String>(){{ put("JPN", "日本"); put("USD", "アメリカ"); }}; // Viewの入出力値 private String code; private String name; // 入力項目の変更イベントで呼ばれるメソッド public void find(ValueChangeEvent e) { // イベント変更値から表示用項目に国名を設定。 if (map.containsKey(e.getNewValue())) { name = map.get(e.getNewValue()); } else { name = ""; } } // アクセッサは省略 }
リスト5のfindメソッドは入力値の変更に伴って呼び出されるメソッドです。ValueChangeEventを引数に取り、変更前後の入力値を受け取れます。findメソッドでは、名称フィールドの値を更新するだけです。その後のViewの反映はXHTMLに記述してある内容に従って行われます。
このようにJSFが提供している機能に従うだけで、Ajax処理が簡単に実現できます。
Copyright © ITmedia, Inc. All Rights Reserved.