[HOME][JSFfollow-up]
Facelets入門(第三回)テンプレートと再利用
by Jacob Hookom
03 Feb 2006 02:15 EST
[原文]
良質なビューテクノロジは、何らかのテンプレート機能と再利用機能を、使いやすく分かりやすい形で持っているべきです。Faceletsはこれらの機能をJavaServer Facesのために実現し、それと同時に、以前からみんながよく知っている、タグを使ったユーザインタフェイスの感覚も保ちます。本稿は、JavaServer Facesを使ったプロジェクトの再利用性を増大し、メンテナンスを楽にする方法を説明します。
Webページを作りはじめると、複数のファイルで同じコンテンツを使うことが多いな、と気づきますね。そしてオブジェクト志向の考え方に馴染んでいるデベロッパは、コンテンツの再利用をもっと効率的にできないものか、と悩みます。そのコンテンツを一か所にだけ置けばよい方法は、ないだろうか?。
では始めよう
最初のやり方は、テンプレートを作ることです。どのWebページにも、ヘッダ、ボディ、フッタといった、共通の部分があります。Faceletsでは、そういう共通の成分を一つのページにまとめて、次のようなテンプレートを作れます:
<!-- template.xhtml -->
<!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">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Sample Template</title>
</head>
<body>
<h1>#{title}</h1>
<div><ui:insert name="menu"/></div>
<p><ui:insert name="body"/></p>
</body>
</html>
menuとbodyのための<ui:insert/>タグが、各ページごとに差し替わる部分を指定します。このテンプレートを使ってmenuとbodyを表示するページは、たとえば次のように書きます:
<!-- template-client.xhtml -->
<!-- content above will be trimmed -->
<ui:composition template="template.xhtml">
<ui:param name="title" value="Here's my Title"/>
<ui:define name="menu">Here's My Menu</ui:define>
<ui:define name="body">Here's My Body</ui:define>
</ui:composition>
<!-- content below will be trimmed -->
上のページ例は、<ui:composition/>というタグを使っています。このタグには、二つの機能があります。まず、このタグの前後にあるコンテンツをすべてトリミングします。ですから、ふつうのHTMLページを使った場合でも、Faceletsは<ui:composition/>タグの中身だけを表示します。そしてこのタグのtemplate属性を使うと、コンテンツのレイアウトの方式やタイミングを指定できます。
このページと、さきほどのテンプレートを結びつけるために、テンプレートの<ui:insert/>とマッチするname属性で、<ui:define/>タグを使います。このページに単純にテンプレートの変数の値やテキストを渡すためには、<ui:param/>タグを使います。そのvalue属性で指定した値が、テンプレートの中の変数(title)の値として使われます。
Faceletsがテンプレートを使ってこのページを表示するときには、こんな出力結果になります:
<!-- template.xhtml -->
<!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">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Sample Template</title>
</head>
<body>
<h1>Here's my Title</h1>
<div>Here's My Menu</div>
<p>Here's My Body</p>
</body>
</html>
テンプレート中で、各ページごとの可変部分が一つだけの場合には、こんな簡単なテンプレートを使えます:
<!-- simple-template.xhtml -->
...
<body>
<h1>Title</h1>
<!-- editable body -->
<p><ui:insert/></p>
</body>
...
このテンプレートを使うページは、たとえばこのように書きます:
<!-- simple-template-client.xhtml -->
<ui:composition template="simple-template.xhtml">
Here's My Simple Body
</ui:composition>
includeを使う
上で見たcomposition(組み立て)方式は、Webページのコンテンツの再利用性を実現するための相当強力な方法です。上の例では、compositionの表示形式をテンプレートで指定しました。しかし、あるページでほかのページのcompositionを使いたいこともありますね。それはたとえば、複数の部品から一つのFORMを組み立てるとか、複数のドキュメントの中にある要素を拾って複雑なメニューを組み立てる、という場合です。それを、シンプルですっきりとしたレイアウトでやりたいのです。
Faceletsには、ほかのページや、ほかのページにあるcompositionをインクルードする方法が二つあります。ひとつは、<ui:include/>タグです。このタグは、Webデベロッパにとってたいへん分かりやすいと思います:
<!-- include.xhtml -->
...
<span id="leftNav">
<ui:include src="/WEB-INF/siteNav.xhtml"/>
</span>
...
<!-- siteNav.xhtml -->
..
<ui:composition>
<!-- myfaces tomahawk components -->
<t:tree2 value="#{backingBean.options}" var="opt">
...
</t:tree2>
</ui:composition>
...
Faceletsがこのinclude.xhmlを処理すると、siteNav.xhtmlの<ui:composition/>タグのコンテンツがすべて、include.xhmlにインクルードされます。その結果は、こうなります:
<!-- include.xhtml -->
...
<span id="leftNav">
<!-- myfaces tomahawk components -->
<t:tree2 value="#{backingBean.options}" var="opt">
...
</t:tree2>
</span>
...
ツリーコンポーネントの中で使う変数をsiteNav.xhtmlに渡したいときは、次のように、<ui:param/>タグを使います:
<!-- include.xhtml -->
...
<span id="leftNav">
<ui:include src="/WEB-INF/siteNav.xhtml">
<ui:param name="menuBean" value="#{backingBean.options}"/>
</ui:include>
</span>
...
<!-- siteNav.xhtml -->
...
<ui:composition>
<!-- myfaces tomahawk components -->
<t:tree2 value="#{menuBean}" var="opt">
...
</t:tree2>
</ui:composition>
...
そうすると、インクルードされたsiteNav.xhtmlはmenuBeanという変数の実際の値が<ui:include/>タグの中で渡されている、と見なします。このやり方(変数名とその実値に分けるやり方)だと、共通的なコンポーネントやコンテンツの再利用に、柔軟性を持たせることができます。
Faceletsでは、カスタムタグを使って、<ui:include/>と<ui:param/>を、もっとすっきりした形で利用できます。ただし、ご心配なく。Javaのコードは1行も書く必要がありません。siteNav.xhtmlをタグ化するためには、次のような簡単なtaglibファイルをXMLで書くだけです:
<facelet-taglib>
<namespace>"http://www.mycompany.com/jsf"</namespace>
<tag>
<tag-name>siteNav.xhtml</tag-name>
<source>/WEB-INF/tags/siteNav.xhtml</source>
</tag>
</facelet-taglib>
ご覧のように、この新たに書いたtaglibファイルの中では、インクルードするFaceletsを指定しているだけです。このtaglibの中で、タグをいくつでも定義できます。http://wwww.mycompany.com/jsfというネームスペースを指定すると、タグをこのように使えます:
<!-- include-tag.xhtml -->
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:my="http://www.mycompany.com/jsf">
...
<span id="leftNav">
<my:siteNav menuBean="#{backingBean.options}"/>
</span>
...
このinclude-tag.xhtmlの出力は、さっきのinclude.xhtmlと同じです。menuBeanという属性は、<ui:param/>の場合と同じく、siteNav.xhtmlの中の属性を指しています。
本格的なプロジェクトでは、大量のタスタムタグを集めたライブラリを作って、それをアプリケーションJARファイルに収め、そのWebアプリケーション用のフォルダに置くだけでそれらのタグを使えます。タグについては、Faceletsのデベロッパ向けドキュメンテーションにさらに詳しく書かれています。
--第三回終わり--
[HOME][JSFfollow-up]