JSF の基礎

メニュー

初めに

 この章では、JSF に関する内容を記述します。ブラウザに返される HTML をどのように構築するのかがテーマになります。具体的には、画面の要素は xhtml により構築します。その要素に表示する実際のデータは管理 Bean と呼ばれる Java のクラスが管理します。xhtml ファイルと管理 Bean クラスとの対応を EL 式と呼ばれる特別な記述方法で指定していきます。
  JSF はバージョンの変動が大きく、かつ整理が不十分のように思います。特に、CDI のアノテーション表記に統一感や下位の互換性が無いので使いづらさを感じています。サンプルでは JSF 2.x を想定して作成してあります。

 JSF には多くの機能がまとめられています。その全般を議論するだけの知識はありませんので、今回作成するサンプルの動きを理解できる範囲しか記述してありません。xhtml ファイルと管理 Bean の Java クラスから HTML を動的に作成する部分は Web サーバで行われます。特に管理 Bean の管理は Web サーバにより自動化されています。そのサーバの処理は、ブラウザからの要求を受信し、ブラウザへの応答を返す間に6つのフェーズで処理されます。こうした処理に関しても記述しませんので、必要に応じてネット検索してください。
 JSF でプログラムを開発していて、全く問題が発生しなければこのような内部処理の知識が必要になることは少ないでしょう。ところが、初めて JSF に取り掛かった場合、なぜこのような動作になるのだろうといった場面に直面しないというのは考えられません。そのような不可解な現象にであった時に、いろいろと試行錯誤してください。このサンプルを完成するにもそうした作業の繰り返しでした。

JSF の記述方法

  JSF のバージョンは JSF 2.x 特に 2.1 を中心に記述してあります。同じ 2.x であっても xhtml の書式が3種類あります。これは混在が可能ですが、以下のようになっています。

JSF のバージョン Java EE のバージョン 説明
2.0 以前 Java EE 6 h: プレフィックスをつけた独自タグを使用
2.1 Java EE 6 HTML のタグに jsfc 属性で JSF 用のタグを指定
2.2 Java EE 7 HTML のタグに jsf: プレフィックスで JSF 用の記述を指定

 私は主に2番目の記述で通しています。それは、3番目の記述の使い方がよくわからないこと、その有難味もまた分からないためでした。
 但し、1番目の独自タグ方式は原則使用しません。2番目の記法を採用しているのは、 Web アプリケーションを開発しようと考える人であれば、 HTML の表記法は必須の知識です。既に知っていることを活用して、新たに覚えなければいけないことは少なくしたいです。ただし、原則となっている理由は1つだけです。jsfc 属性は HTML のタグに付けます。つまりは JSF のタグと変換後の HTML タグとが1対1に対応しているものにしかつけられません。HTML タグとして存在しない処理を指定するには、 JSF 専用のタグで記述する必要があります。

 jsf: プレフィックスの使い方が分からないと書きましたが、少しばかり調べてみました。何が分からなかったかといいますと、 HTML のどの属性にこのプレフィックスを付けたらよいかが分かりませんでした。その後、任意の属性1つだけに付ければよいと分かりました。実際に試してみても正しく動作します。するとどの属性を使用するのが良いかとなりますが、その一番の候補は id 属性でしょう。この判断は HTML の書式を理解している人であれば同意していただけると思います。
 このことをプログラマの立場からみますと、きわめて長い専用タグを正確に記述することから、 jsf:id と書くだけで済むことになります。また HTML の書式としての可読性も上がります。もちろん <h:messages> といったタグや f: ui: といった独自の名前空間の必要性がなくなったわけではありませんが、 HTML の可読性が高くなるのはうれしいことです。

 このサンプルでは jsfc を使用した記述のままにしておきますが、今後は jsf: プレフィックスを使用した書式を採用することにします。

HTML タグを使用する場合

  JSF 2.1 の表記方法で、 HTML のタグに jsfc 属性を指定する方法を説明します。その jsfc 属性の値には、JSF の専用タグ名をしっかりと書く必要があります。だとすると、専用タグ名を覚えることとあまり差がないように思えるかもしれません。しかし、変換用リストを用意すれば済むこと・専用タグは記述の書式が HTML のタグと大きく変わっているものがあること・ HTML しか知らないデザイン系の担当者とも会話が可能になること、このような理由でこの表記法は有効だと思います。

 このサンプルでは、 JSF 2.1 の表記方法を使用していますが、その後調査の結果、 JSF 2.2 で採用された jsf: プレフィックスを使用することに考えが変わりました。このサンプルを jsf: プレフィックス用に書き換えることは簡単です。まず、 jsfc 属性の部分を削除します。そして、 id 属性を jsf:id と書き換えるだけです。もしそのタグに id 属性が付けられていない場合はどうするか?その場合は新たに id 属性を付けるのが1つの方法です。もう一つの方法は、そのタグは JSF の処理が必ず必要なタグですから、 JSF 用の記述(特に EL 式)がどこかにあるはずです。その属性に jsf: プレフィックスを付ければ大丈夫です。

一覧表

 それでは、HTML のタグと JSF のタグの対応表を示します。ここでは網羅を考慮せず、今回のサンプルで使用していることを中心にしてあります。また1つの HTML タグが複数の JSF タグに対応していることもあることに注意してください。

HTML のタグ JSF のタグ サンプル
<!DOCTYPE> <h:doctype>
<head></head> <h:head></h:head>
<body></body> <h:body></h:body>
<form></form> <h:form></h:form>
<a></a> <h:outputLink>
</h:outputLink>
<h:outputLink value="http://mycom">
    <h:outputText value="リンク" />
</h:outputLink>
<span></span> <h:outputLabel>
</h:outputLabel>
<h:outputLabel for="userId">
    <h:outputText id="userId" value="ラベル" />
</h:outputLabel>
<input type="text" /> <h:inputText /> <h:inputText value="good" />
<input type="password" /> <h:inputSecret /> <h:inputSecret value="" />
<input type="hidden" /> <h:inputHidden /> <h:inputHidden value="hidden" />
<input type="submit" /> <h:commandButton /> <h:commandButton value="保存" action="saveData" />
<input type="button" /> <h:button /> <h:button value="GET button" outcome="otherpage" />
<input type="checkbox" /> <h:selectBooleanCheckbox /> <h:selectBooleanCheckbox value="登録希望" />
<input type="checkbox" /> <h:selectManyCheckbox>
</h:selectManyCheckbox>
<h:selectManyCheckbox value="#{myBean.selectManyCheckbox1}">
    <f:selectItem itemLabel="選択1" itemValue="check1"/>
    <f:selectItem itemLabel="選択2" itemValue="check2"/>
</h:selectManyCheckbox>
<input type="radio" /> <h:selectOneRadio>
</h:selectOneRadio>
<h:selectOneRadio value="#{myBean.selectOneRadio}">
    <f:selectItems value="#{selectManyList}"/>
</h:selectOneRadio>
<select></select> <h:selectOneMenu>
</h:selectOneMenu>
<h:selectOneMenu value="#{myBean.selectOneMenu}">
    <f:selectItems value="#{selectManyList}"/>
</h:selectOneMenu>
<select size="5"></select> <h:selectOneListbox>
</h:selectOneListbox>
<h:selectOneListbox value="#{myBean.selectOneListbox}">
    <f:selectItems value="#{selectManyList}"/>
</h:selectOneListbox>
<select size="5" multiple>
</select>
<h:selectManyListbox>
</h:selectManyListbox>
<h:selectManyListbox value="#{myBean.selectManyListbox}">
    <f:selectItem itemLabel="List1" itemValue="List1"/>
    <f:selectItem itemLabel="List2" itemValue="List2"/>
</h:selectManyListbox>
<img /> <h:graphicImage /> <h:graphicImage url="image/sample.gif" />
<textarea></textarea> <h:inputTextarea /> <h:inputTextarea value="contents" />
<label></label> <h:outputLabel></h:outputLabel>
<link /> <h:outputStyleSheet>
<script></script> <h:outputScript>
</h:outputScript>
<table>
</table>
<h:dataTable>
    <h:column></h:column>
</h:dataTable>

<h:panelGrid>
    <h:panelGroup></h:panelGroup>
</h:panelGrid>
<table>
    <thead>
        <tr>
            <th>ヘッダ1</th>
            <th>ヘッダ2</th>
        </tr>
    </thead>
    <tbody>
        <tr jsfc="ui:repeat" var="itemBean" value="#{listBean.items}">
            <td>#{itemBean.name}</td>
            <td>#{itemBean.phone}</td>
        </tr>
    </tbody>
</table>

 簡単な例として、body タグの場合を以下に示します。 jsfc 属性に対応する h:body を指定する必要するだけです。ここで注意が必要なのは、 HTML タグのままで jsfc 属性を指定しなかった場合は、そのまま HTML とみなされます。 EL 式を書いたとしてもただの文字列と扱われます。

                     
    <body jsfc="h:body">
        …
    </body>
        

                 

table タグの場合

 上記の一覧表で特異なのは、 table タグだと思います。 table タグに対応する JSF の独自タグは2つあります。私はこの独自タグを使用したことはありません。 table タグは複雑な構造をもつもので、 JSF が変換した後の結果が直観的ではありません。そのため、 table タグを直接使用することにしています。

 一覧表にあるサンプルを再録して、その説明をします。

                     
<table>
    <thead>
        <tr>
            <th>ヘッダ1</th>
            <th>ヘッダ2</th>
        </tr>
    </thead>
    <tbody>
        <tr jsfc="ui:repeat" var="itemBean" value="#{listBean.items}">
            <td>#{itemBean.name}</td>
            <td>#{itemBean.phone}</td>
        </tr>
    </tbody>
</table>

                 

  jsfc 属性を付けるのは、 tbody にある繰り返し部分に該当する tr タグになります。その値は、ui:repeat となり、これは JSF において繰り返し処理を記述する方法です。
 その value 属性の値は、#{listBean.items} となっています。これは EL 式の記述です。 Web サーバの管理下にある ListBean というクラスのインスタンスに対して、 getItems メソッドを呼び出します。このメソッドの戻り値は何らかの集合になります。その集合の全要素に対して、繰り返し処理を行います。その要素がここでは、var="itemBean" の記述から itemBean の変数名で操作できるようになります。 table の各行は2つの列から構成され、それぞれ getName と getPhone メソッドの値となります。クラス名やメソッド名への置換は、 Java のクラス名・メソッド名の慣習から自動的に決められます。こうした命名は独自ルールを使用するのではなく、慣習に従ったほうが楽ですね。

 以下は余談。 table タグを使用する場合は、きちんと thead タグ tbody タグを記述するのが好みです。記述を省略しても正しくブラウザで表示されます。そして、ブラウザでは thead tbody を自動的に補ってくれます。しかし、 jQuery を使用して動的に table の構造を操作する場合、ブラウザが自動的に追加した thead tbody タグが存在することを知らないと、 table の構造を壊してしまう可能性があります。そのため、明示的に thead tbody タグを記述するのが私の好みです。

独自タグを使用する場合

 独自タグは対応する HTML タグが存在しないものになります。具体的には、xhtml ファイルから HTML ファイルを動的に作成する際の処理に関する指示を与えるタグになります。

一覧表

 ここでも網羅することは考えていません。このサンプルで使用しているタグに限定しました。

タグ名 説明 サンプル
<h:message /> 特定項目専用のメッセージを表示するためのタグ <h:message id="invalidDate" />
<h:messages /> 全てのメッセージを1ケ所に表示するためのタグ <h:messages />
<h:panelGrid>
</h:panelGrid>
別のタグ要素を収容するためのタグ
<f:convertDateTime/ > 日付の書式を指定するためのタグ <h:outputText value="#{knowledge.getRDate()}" >
    <f:convertDateTime pattern="yyyy/MM/dd" />
</h:outputText>
<f:ajax /> AJAX の機能を利用するためのタグ <f:ajax listener="#{knowledgeListBean.majorChanged}" render="minors" />
<ez:pagingPart /> 複合コンポーネントを利用するためのタグ <ez:pagingPart pagingModel="#{knowledgeListBean}" />
<f:metadata>
</f:metadata>
管理 Bean のメソッド呼び出しのためのタグ <f:metadata>
    <f:viewParam name="page" value="#{knowledgeListBean.page}"/>
    <f:event type="preRenderView" listener="#{knowledgeListBean.preRender}"/>
</f:metadata>

  h:message と h:messages に関しては次章に記述します。

  f:convertDateTime は日付の書式に使用します。ただし、このタグは h:outputText タグに囲まれている必要があるため、 h:outputText を使用せざるをえません。これを意味的には同等と思われる jsfc="h:outputText" 属性をもつ HTML のタグに変更してもエラーとなりました。

  h:panelGrid は通常は使用する必要がないと思います。今回 f:ajax タグの関連で使用することが必要になりました。 AJAX とはブラウザ上でユーザが操作しているときに、 Web サーバと非同期に通信してブラウザの画面の一部だけを更新する技術です。たまたま、その更新する部分が複数のタグにわたっており、その部分の EL 式がサーバで評価される必要があります。そのためその複数のタグを h:panelGrid で囲んでいます。 この部分は、別の場所で説明します。

  ez:pagingPart はページングの機能を実現するために必要になりました。f:metadata は同じくページングの機能を実現するためと GET 呼び出し時のパラメータを知るときに使用しています。両方とも、別の場所で説明します。

h:messages タグの場合

  h:message や h:messages タグをプログラムから操作する方法は、 こちら を参照してください。

  h:message は特定の HTML の要素を指定してメッセージを表示するためのタグであり、 h:messages はすべてのメッセージを1ケ所に表示するためのタグです。サンプルではエラーの表示に使用しています。但し、この2つのタグを混在して使用するのは困難と考えます。それは h:message を使用して表示したメッセージであっても、自動的に h:messages タグに表示されてしまうためです。つまり、同じメッセージが個別の場所と共通の場所の2か所に表示されてしまうのです。これを禁止する方法は見つけることができませんでした。このサンプルでは h:messages だけを使用しています。

 そのサンプルは以下です。

                     
    <h:messages class="text-danger bg-danger" />

                 

  text-danger と bg-danger はそれぞれ文字色と背景色の指定です。 Bootstrap の CSS 値を使用しています。


 ここでエラー処理に関して考えてみます。 Web アプリケーションが遭遇するエラーには、その発生場所として2つ考えられます。1つはサーバで発生・発見したエラーです。このエラーは h:messages に表示することになります。もう1つはブラウザ上で jQuery(または javascript)により発見したエラーです。例えば、必須入力の検査をブラウザ上で行い、未入力の場合にその旨のメッセージを表示したいといった場合です。どちらのエラーも同じように、つまりは h:messages タグ一つで表示したいのですが、このことが実現できませんでした。h:messages タグは標準ではサーバ上でエラーが発見されない場合には、 HTML ファイルからは削除されてしまいます。エラーの有無に限らず、必ず HTML に出力するように変更できます。しかしながら、このようにしたとしても、サーバでのエラーの有無によって出力される HTML のタグの種類が異なってしまうのです。

 私がとった解法は、サーバで発見したエラーを表示するタグ―つまりは、h:messages タグと、ブラウザで検出したエラーを表示するタグを並べるというものです。これ以上のアイデアは出てきませんでした。xhtml のソース(部分)はこれです。

                     
    <ul id="errorMessage" class="text-danger bg-danger"></ul>
    <h:messages class="text-danger bg-danger" />

                 

 上のタグがブラウザで発見したエラーを表示する用のタグ。下のタグはサーバ上のエラー表示用です。エラーは ul タグで表示しますので、 jQuery を使って書式を合わせる必要があります。背景色と文字色の指定は Bootstrap の値を使用しています。

EL 式

 すでに EL 式の例がでてきていますが、EL 式は #{ } の書式で記述し、 Web サーバにより解釈実行されて、その結果の文字列に置換されます。 xhtml で書かれた画面構成と管理 Bean が所有しているデータ自体とを関連付ける役割を果たしています。

 以下では majorPage.xhtml ファイルとその管理 Bean である MajorPageBean クラスを例として見てみましょう。まずは、xhtml のごく一部のソースです。

                     
        <div class="form-group">
            <label for="inputId" class="col-md-2 control-label">ID</label>
                <div class="col-md-1">
                    <input jsfc="h:inputText" id="inputId" class="form-control" type="text" maxlength="2" value="#{majorPageBean.id}" readonly="#{majorPageBean.getId().length() > 0}" />
                </div>
        </div>           

                 

 この例では2つの EL 式があります。1つは #{majorPageBean.id} です。この名前から MajorPageBean クラスのインスタンスが Web サーバの管理対象となります。ブラウザからの要求に応じて HTML を返す場合は、そのインスタンスに対して getId メソッドを呼び出し、その値で置換されます。逆にブラウザから submit されて、サーバに返された要求に存在する同じタブの値は setId メソッドを呼び出して、そのインスタンスが正しく構築されます。

 もう1つの例は、#{majorPageBean.getId().length() > 0} です。同じように MajorPageBean のインスタンスの ID 変数の長さを調べて、その値により readonly 属性を決めています。


 次に、管理 Bean クラスである MajorPageBean の関連するソース(部分)を見てみましょう。

                     
@Named
@RequestScoped
public class MajorPageBean extends BaseBean implements Serializable {
    public MajorPageBean() { }
    
    private String id = "";
    
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}                  

                 

  @Named はこのクラスが管理 Bean クラスであることを示します。 @RequestScoped はこのクラスのインスタンスの寿命を指定します。リクエストスコープですので、ブラウザからの要求を受信して、ブラウザに応答を返すまでが有効となります。ブラウザに応答を返した後では、このインスタンスはすべて破棄されてしまいます。これは一番一般的な Web アプリケーションのインスタンスの寿命になります。
 また こちら にあるように BaseBean クラスから派生する必要があります。

 このインスタンスの管理、 EL 式の解釈や実行はすべて Web サーバにより自動化されています。