この記事は、Java EE Advent Calendar 2013の18日目の記事です。
昨日は @yumix_h さんの私がJava EE開発の現場から学んだことでした。
明日は誕生日の @aoetk さんです。

みなさんJSF使ってますか?
JSFってちょっと取っ付きにくいところがありますよね。でもそんなJSFもバージョンが2.2になって、 ちょっと良い感じになってきたので使ってみませんか、 ということでJSFのマークアップについて書いてみたいと思います。

デザイナーとプログラマの作業の分担

JSFはデザイナーとプログラマで作業が分担できるということを良く聞きます。 デザイナーを雇うほど大きなプロジェクトでJSFを使ったことがないし、 分担しているということもあまり見聞きしませんが、実際この分担というのはどういうことなんでしょう?

デザイナーはHTMLは分かりますがJSFはわかりません。
プログラマはHTMLもJSFも分かりますが、デザインセンスはそれを専属でやっているデザイナーのほうに 一日の長があると思うので、素直にデザインは任せた方が良いでしょう。

このようにHTMLしか分からない人が、HTMLに注力できるようにするには、 そのファイルがHTMLとして認識、つまりAPサーバーを経由しなくても、ブラウザでレイアウトが表示できる必要があります。 昔のJSPのように、JSPのタグやスクリプトレットで動的にレイアウトをするようにしていると、 ブラウザでレイアウトが表示できないのでダメということですね。

JSFはFaceletsというテンプレートエンジンを取り込んでいるので、 特別なファイルではなく、XHTMLとして画面を作ることができます。 そのため、JSFのコンポーネントを埋め込まなければ、このままブラウザで表示することができます。

ですが、何も埋め込まないのでは静的なHPと何も変わらないので、 JSFのコンポーネントを埋め込んでいく必要があり、下記のようなコンポーネントを埋め込んでしまうと、 デザイナーが理解できない状態、ブラウザでレイアウトを確認できない状態になってしまいます。

<h:commandButton value="OK" action=" #{managedBean.doAction}"/>

ではどうしたら良いのでしょう?

JSF 2.1

JSF 2.1では、例えば下記のようにHTMLのタグにJSFのコンポーネント名を設定することによって、 JSFのコンポーネントとして認識させることができます。もちろんJSF 2.2でもできます。

<input type="submit" value="OK" jsfc="h:commandButton" action="#{managedBean.doAction}"/>

これをブラウザで表示してみます。

h:commandButtonの方は見事に表示されませんが、jsfc属性で書いた方は普通のボタンとして表示されています。

JSF 2.2

jsfc属性でJSFコンポーネントをHTMLとして認識させるのには十分でしたが、 それぞれのJSFコンポーネント名をいちいち記載するのは面倒でした。コンポーネント名を正確に覚えていなければならないし…。 JSF 2.2ではそこがさらに改善され、下記のようにコンポーネント名を書かなくても、JSFコンポーネントとして認識してくれるようになりました。 namespaceはxmlns:jsf="http://xmlns.jcp.org/jsf"です。

<input type="submit" value="OK" jsf:action="#{managedBean.doAction}"/>

詳しくはJava EE 7 Tutorialを参考にしてください。

ちょっと発展

ここまでで、JSFコンポーネントのマークアップが簡単だということが分かりました。 ただ、ビジネスアプリでは必ず登場するテーブルのJSFコンポーネントはちょっと考え方を変えないと、 HTMLとして認識させるのは難しそうです。

通常、JSFのテーブルコンポーネントは下記の形になります。

<h:dataTable var="item" value="#{managedBean.items}">
    <h:column>
        <f:facet name="header">ヘッダ1</f:facet>
        <h:outputText value="#{item.value1}"/>
    </h:column>
    <h:column>
        <f:facet name="header">ヘッダ2</f:facet>
        <h:outputText value="#{item.value2}"/>
    </h:column>
</h:dataTable>

これ、前から思ってたんですけど、HTMLのテーブルタグに慣れていると、 ちょっと直感的ではないのですぐに組み方を忘れてしまいませんか? 僕はいつも忘れてしまいます。 それにHTMLとして表示もできません。 これをHTMLとして表示できるように、なるべくテーブルタグに近づけていきたいと思います。

まずは通常のテーブルタグを書きます。ここまではデザイナーの分担ですね。

<table>
    <thead>
        <tr>
            <th>ヘッダ1</th>
            <th>ヘッダ2</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>値1</td>
            <td>値2</td>
        </tr>
    </tbody>
</table>

ここにJSFのコンポーネントを組み込んでいきます。

<table>
    <thead>
        <tr>
            <th>ヘッダ1</th>
            <th>ヘッダ2</th>
        </tr>
    </thead>
    <tbody>
        <tr jsfc="ui:repeat" var="item" value="#{managedBean.items}">
            <td>#{item.value1}</td>
            <td>#{item.value2}</td>
        </tr>
    </tbody>
</table>

tbodyのtrタグの部分にjsfc属性でui:repeatを組み込みます。 JSF 2.2のjsfプレフックスは使えません。 こうすることでサーバー経由で表示したh:dataTableと同じになるはずです。 そうそう、ちゃんとHTMLとして表示されなければ意味がないので確認してみます。

分かりにくいのでボーダーを表示していますが、ちゃんとレイアウト通り表示されました。

まとめ

こんな具合にJSFコンポーネントの情報を、HTMLのタグの属性として組み込めるようになっているので、 今までよりもずっとデザイナーとプログラマの作業の分担がやり易くなっていると思います。 まあ、デザイナーがいなくてもHTMLとして認識できるようにしておけば、 いちいちサーバーを起動しなくてもレイアウトが確認できるので、 JSFを使う場合は固有のタグではなく、HTMLの属性としてJSFを利用するようにした方が良いと思います。

補足

IntelliJ IDEA 13 でもjsfプレフィックスでの補完は完全には効かなかったので、 知らないとちょっと面倒かも :P

Enjoy!