[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]