【JSF】テンプレートを利用してみる

#概要
JSFのテンプレートに思った以上に苦戦したので
私なりにまとめてみました。
理解してみれば実にシンプルな内容でした。

#環境

 - IDE : Eclipse 4.7 Oxygen
 - APサーバ : GlassFish 4.1.1
 - JDK 1.8
 - OS : Windows7
 - [プロジェクトの設定](http://qiita.com/nifram/items/123ec5689da654b365aa#eclipse%E3%81%AE%E8%A8%AD%E5%AE%9A)

#対象読者

 - Facelets(JSF)初心者

#実装

【図１．完成イメージ】
![テンプレート４.png](https://qiita-image-store.s3.amazonaws.com/0/190666/0ba5d36e-9c6f-7a8b-daf9-e9143b771bfd.png)

このTmeplateSampleページは左右共に
4つのxhtmlファイルを組み合わせて作成されています。

![テンプレート２.png](https://qiita-image-store.s3.amazonaws.com/0/190666/37a058ee-cda2-a25e-310e-70a860993dc7.png)　　　![テンプレート３.png](https://qiita-image-store.s3.amazonaws.com/0/190666/92e07064-f80b-89e6-63ea-bdc97c848c8f.png)

 - index.xhtml or board.xhtml　（コンテンツ要素）
 
　　　　＋

 - header.xhtml（ヘッダー要素）
 - left.xhtml（メニュー要素）
 - footer.xhtml（フッター要素）


そしてこれら要素をどういった形で組み合わせるか定義しているものがテンプレートです。

 - template.xhtml


##パターン１

まずはテンプレートから。 
`<ui:insert>`タグとname属性を用いて、要素（ヘッダーとかフッターとか）を入れる場所を設定します。

```template.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://xmlns.jcp.org/jsf/html"
	xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<h:head>
	<title>TemplateSample</title>
</h:head>
<h:body>
	<div align="center">
		<table border="1">
			<tr>
				<td colspan="2"><ui:insert name="header" /></td>
			</tr>
			<tr>
				<td><ui:insert name="left" /></td>
				<td><ui:insert name="content" /></td>
			</tr>
			<tr>
				<td colspan="2"><ui:insert name="footer" /></td>
			</tr>
		</table>
	</div>
</h:body>
</html>
```
これで基本的なページのレイアウトが`template.xhtml`に定義されました。

次に各要素を準備します。

```header.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
<title>TemplateSample</title>
</h:head>
<h:body>
<h2>Template Site</h2>
</h:body>
</html>
```
```footer.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
<title>TemplateSample</title>
</h:head>
<h:body>
Copyright 2017 ○○.
</h:body>
</html>
```
```menu.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://xmlns.jcp.org/jsf/html"
	xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<h:head>
<title>TemplateSample</title>
</h:head>
<h:body>
	<ul>
		<li><a href="index.xhtml">TOP</a></li>
		<li><a href="board.xhtml">掲示板</a></li>
	</ul>
</h:body>
</html>
```
ヘッダー、フッター、メニュー要素が出来ました。

次にテンプレートを利用する、メインとなるページを作成します。

`<ui:conposition>`タグを利用し、template属性にテンプレートとなるxhtmlを指定します。
`<ui:define>`タグのname属性で、テンプレートの`<ui:insert>`タグのname属性で設定した要素を挿入する場所を指定します。
必要であれば、`<ui:include>`タグのsrc属性で利用する要素(xhtmlファイル)を指定します。

共通部分でなければ`ui:define`タグの中に、コンテンツ内容を記述します。

```index.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://xmlns.jcp.org/jsf/html"
	xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<h:head>
<title>TemplateSample</title>
</h:head>
<h:body>

<!-- 利用するテンプレートを宣言 -->
<ui:composition template="template.xhtml">

	<!-- テンプレートのnameに対応した位置に読み込みたいxhtmlを設定 -->
	<ui:define name="header">
		<ui:include src="header.xhtml" />
	</ui:define>
	<ui:define name="left">
		<ui:include src="menu.xhtml" />
	</ui:define>
	<ui:define name="footer">
		<ui:include src="footer.xhtml" />
	</ui:define>
	
	<!-- ここからメインコンテンツ -->
	<ui:define name="content">
		<h:inputText value="#{indexBean.mainText}" style="color:blue" />
	</ui:define>

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


掲示板ページも同様に記述します。
メインコンテンツ以外は`index.xhtml`と共通のヘッダー、フッター、メニューを利用しています。

```board.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://xmlns.jcp.org/jsf/html"
	xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<h:head>
<title>TemplateSample</title>
</h:head>
<h:body>

<!-- 利用するテンプレートを宣言 -->
<ui:composition template="template.xhtml">

	<!-- テンプレートのパーツ名に対応した位置にxhtmlを読み込み（header） -->
	<ui:define name="header">
		<ui:include src="header.xhtml" />
	</ui:define>
	<ui:define name="left">
		<ui:include src="menu.xhtml" />
	</ui:define>
	<ui:define name="footer">
		<ui:include src="footer.xhtml" />
	</ui:define>

	<!-- ここにメインコンテンツ -->
	<ui:define name="content">
		<h:inputTextarea value="#{indexBean.boardArea}" style="color:green" />
	</ui:define>

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

最後に管理Beanです。

```IndexBean.java
package bean;

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named
@RequestScoped
public class IndexBean {

	private String mainText = "メインコンテンツ";
	private String boardArea = "掲示板";

	public String getMainText() {
		return mainText;
	}
	public void setHeaderText(String mainText) {
		this.mainText = mainText;
	}
	public String getBoardArea() {
		return boardArea;
	}
	public void setBoardArea(String boardArea) {
		this.boardArea = boardArea;
	}
}

```

##パターン２（テンプレートに直接要素を埋め込む）

header.xhtml
fooer.xhtml
menu.xhtml

及び管理Beanはパターン１と同一です。

パターン１の場合、埋め込むファイル名等に変更があった場合、
全てのコンテンツファイル（index.xhtmlやboard.xhtml）を変更しなければなりません。

パターン２のようにテンプレートに要素を直接埋め込むことで、
ファイル名に変更があってもテンプレート（template.xhtml）１つを編集するだけで済みます。

```template.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://xmlns.jcp.org/jsf/html"
	xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<h:head>
	<title>TemplateSample</title>
</h:head>
<h:body>
	<div align="center">
		<table border="1">
			<tr>
				<td colspan="2"><ui:include src="header.xhtml"/></td>
			</tr>
			<tr>
				<td><ui:include src="menu.xhtml"/></td>
				<td><ui:insert name="content" /></td>
			</tr>
			<tr>
				<td colspan="2"><ui:include src="footer.xhtml"/></td>
			</tr>
		</table>
	</div>
</h:body>
</html>
```

```index.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://xmlns.jcp.org/jsf/html"
	xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<h:head>
<title>TemplateSample</title>
</h:head>
<h:body>

<!-- 利用するテンプレートを宣言 -->
<ui:composition template="template.xhtml">

	<!-- メインコンテンツ -->
	<ui:define name="content">
		<h:inputText value="#{indexBean.mainText}" style="color:blue" />
	</ui:define>

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

```board.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://xmlns.jcp.org/jsf/html"
	xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<h:head>
<title>TemplateSample</title>
</h:head>
<h:body>

<!-- 利用するテンプレートを宣言 -->
<ui:composition template="template.xhtml">

	<!-- ここにメインコンテンツ -->
	<ui:define name="content">
		<h:inputTextarea value="#{indexBean.boardArea}" style="color:green" />
	</ui:define>

</ui:composition>
</h:body>
</html>
```
パターン１と同様の表示結果になります。

###注意点として
`index.xhtml`、`board.xhtml`等テンプレートを利用しているソースは
`<ui:composition>`タグの外にコンポーネントを配置しても反映されません。
テンプレートは利用するけど、テンプレートの外にもコンポーネントを配置したい！という場合は
`<ui:decorate>`タグを使うそうです。