JSF 2.0のテンプレート機能を使う

そういやテンプレートについてあんまり書かなかったなと思い書いてみる。

新規作成でNetBeansのウィザードを利用してはいるが、生成されたコードも全て載せてるので特にIDE依存は無いのでご安心を。

まずテンプレートファイルを作成する。新規作成ウィザードでfaceletsテンプレートを選ぶ。
http://shin.cside.com/diary/2010/0712-01.png

雛形を選択。ここでは2列に分けるタイプを選んでみる。
http://shin.cside.com/diary/2010/0712-02.png

できあがったテンプレートファイルは以下の通り。cssファイルが2つ作られているのがわかる。

<?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">
    
    <h:head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <link href="./resources/css/default.css" rel="stylesheet" type="text/css" />
        <link href="./resources/css/cssLayout.css" rel="stylesheet" type="text/css" />
        <title>Facelets Template</title>
    </h:head>
    
    <h:body>
        
        <div id="left">
            <ui:insert name="left">Left</ui:insert>
        </div>
        <div id="content" class="left_content">
            <ui:insert name="content">Content</ui:insert>
        </div>
        
    </h:body>
    
</html>

タグが埋め込みを表している。中身は差し替えられるので適当に書いたままにしておいてよい。レイアウトを確認しながらDreamWeaver等で作れるので便利だ。


出来上がったプロジェクトファイル一覧は現時点でこうなっている。
http://shin.cside.com/diary/2010/0712-03.png



続いてテンプレートクライアントを作成する。
テンプレートクライアントとは実際に埋め込むべきデータとそのセットを現すもの。StrutsのTilesの設定ファイルと各種JSPのテンプレートが一緒になっている感じかな。
http://shin.cside.com/diary/2010/0712-04.png


最初に作ったテンプレートファイルを選択する。
http://shin.cside.com/diary/2010/0712-05.png




テンプレートクライアントウィザードで出来上がったコードは以下の通り。

<?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">
    
    <body>
        
        <ui:composition template="./newTemplate.xhtml">
            
            <ui:define name="left">
                left
            </ui:define>

            <ui:define name="content">
                content
            </ui:define>

        </ui:composition>
        
    </body>
</html>

が差し替えるべきもの。


これを以下のように書き換える。

<?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">
    <body>
        <ui:composition template="./newTemplate.xhtml">
ここは表示される?
            <ui:define name="left">
                左側のエリア
            </ui:define>
ここは表示される?
            <ui:define name="content">
                コンテンツエリア
            </ui:define>
ここは表示される?
        </ui:composition>
    </body>
</html>

実行すると以下のようになる。
http://shin.cside.com/diary/2010/0712-06.png

予想通り、ui:defineタグの外側は一切表示されない。HTMLの部分抜きだしを自動でやってくれるということ。貧弱なテンプレート環境ではHTMLの部分的なものを意識して作成しないといけない。しかし、それではDreamWeaver等で作業が出来ないという問題点がある。このJSF2を利用するとfaceletsが標準のため、HTMLを作成するだけでよい。

URLを見ればわかるようにテンプレートクライアントをさすようにしている。


ここのleft部分を書き換えてpage2.xhtmlとして別名保存してみる。

<!--
            <ui:define name="left">
                左側のエリア
            </ui:define>
-->

実行結果は省略するが、左側のエリアには「Left」と表示される。テンプレートクライアントで定義されていない部分はテンプレートファイルの中身そのまま出るようだ。


動的に生成(といっても定数返すだけだが)するためにコードも入れてみる。

package managed;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;

@ManagedBean
@RequestScoped
public class Page {
    public String getSide(){
        return "サイドは共通とか";
    }
    public String getPage1Content(){
        return "Page1コンテンツ";
    }
    public String getPage2Content(){
        return "Page2コンテンツ";
    }
}

テンプレートは以下の部分をさしかえる。
page1.xhtml

            <ui:define name="left">
                #{page.side}
            </ui:define>
            <ui:define name="content">
                #{page.page1Content}
            </ui:define>


page2.xhtml

            <ui:define name="left">
                #{page.side}
            </ui:define>
            <ui:define name="content">
                #{page.page2Content}
            </ui:define>

実行。

http://shin.cside.com/diary/2010/0712-07.png
http://shin.cside.com/diary/2010/0712-08.png

これだけ楽ちんなテンプレートもないと思う。

faceletsといえばみんな思いつくのが標準採用しているJBOSS Seamだと思う。SeamJSFを利用しつつ高効率で開発できる理由はfaceletsの恩恵が大きい。ちなみにJSF2でのfaceletsはJSF 1.2のころよりパワーアップしていて、ちゃんと思ったとおりの挙動をしてくれるはずだ。