thymeleafのlayoutについて

# 概要

`thymeleaf layout dialect`の使い方のまとめ記事です。
Spring Bootで使用できるテンプレートエンジンであるthymeleafの`thymeleaf layout dialect`機能を使用するとベースとするテンプレートページに、各コンテンツページのコンテンツデータを組み込んでページを生成することができます。


**環境**

* Windows7 (64bit)
* Java 1.8.0_60
* spring-boot 1.3.0.M5
 * spring-boot-starter-thymeleaf 1.3.0.M5
   * thymeleaf-layout-dialect 1.2.9


**参考**

* [Thymeleaf Layout Dialect] (https://github.com/ultraq/thymeleaf-layout-dialect)
* [Thymeleaf] (http://www.thymeleaf.org/)


## アプリケーションの作成

ベースになるテンプレート(layout.html)を持つ、2つのコンテンツページ(content1.html、content2.html)を表示するサンプルアプリケーションを開発してthymeleaf layout dialectの使い方を確認します。

### プロジェクトの雛形を生成

プロジェクト名: tllo-example

**mavenでアプリケーションの雛形を作成**

```bat:generate
> mvn archetype:generate -DgroupId=com.example.tllo -DartifactId=tllo-example -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
```

```bat:eclipse
> cd tllo-example
> mvn eclipse:eclipse
```

**eclipseにインポート**

* メニューバーの"File" -> "Import..." -> "Maven" -> "Existing Maven Projects"を選択します。
* プロジェクトのディレクトリを選択し、"Finish"ボタンをクリックします。

**pom.xmlの編集**

thymeleaf layout dialectは依存関係にspring-boot-starter-thymeleafを含めることで使用できるようになります。

```xml:pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example.tllo</groupId>
  <artifactId>tllo-example</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>tllo-example</name>
  <url>http://maven.apache.org</url>

  <properties>
    <java.version>1.8</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.3.0.M5</version>
  </parent>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <repositories>
    <repository>
      <id>spring-libs-snapshot</id>
      <name>Spring</name>
      <url>http://repo.spring.io/libs-snapshot</url>
    </repository>
    <repository>
      <id>spring-snapshots</id>
      <name>Spring Snapshot</name>
      <url>http://repo.spring.io/snapshot</url>
      <snapshots>
        <enabled>true</enabled>
      </snapshots>
    </repository>
    <repository>
      <id>spring-milestones</id>
      <name>Spring Milestones</name>
      <url>http://repo.spring.io/milestone</url>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
  </repositories>

  <build>
    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-maven-plugin</artifactId>
          <version>1.2.5.RELEASE</version>
        </plugin>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <configuration>
            <verbose>true</verbose>
            <source>${java.version}</source>
            <target>${java.version}</target>
            <encoding>${project.build.sourceEncoding}</encoding>
          </configuration>
        </plugin>
        <plugin>
          <groupId>org.codehaus.mojo</groupId>
          <artifactId>versions-maven-plugin</artifactId>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>
```

**resourcesフォルダの作成**

設定ファイルやテンプレートファイルなどを配置するresourcesフォルダをsrc/main下に作成します。

作成したらプロジェクトに反映させます。

* "Build Path" -> "Configure Build Path" -> "Java Buld Path" -> "Source"タブを選択する。
* "Add Folder"ボタンをクリック -> 作成した"resources"フォルダにチェックを入れる。

**application.ymlの作成**

src/main/resourcesフォルダ内にapplication.ymlを作成します。

```yml:application.yml
# EMBEDDED SERVER CONFIGURATION (ServerProperties)
server:
  port: 9000

spring:
# THYMELEAF (ThymeleafAutoConfiguration)
  thymeleaf:
    enabled: true
    cache: false
# INTERNATIONALIZATION (MessageSourceAutoConfiguration)
  messages:
    basename: messages
    cache-seconds: -1
    encoding: UTF-8
```

**ビルド**

この時点で動作検証を兼ねてビルドします。

```bat:package
> mvn package
```

ビルドが成功したら生成したjarファイルを実行します。
コマンドプロンプトに"Hello World!"と表示されれば成功です。

```bat:jar
> cd target
> java -jar tllo-example-1.0-SNAPSHOT.jar
Hello World!
```


### アプリケーションの開発

#### App

エンドポイントとなるクラスを作成します。
すでにサンプルのApp.javaがありますので、このファイルを下記のように変更します。

```java:App.java
package com.example.tllo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class App {
  public static void main( String[] args ) {
    SpringApplication.run(App.class, args);
  }
}
```

#### Controller

サンプルページ用のコントローラーを作成します。

* http://localhost:9000/content1 … コンテンツ1ページ (content1.html)
* http://localhost:9000/content2 … コンテンツ2ページ (content2.html)

```java:IndexController.java
package com.example.tllo.web;

import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.example.tllo.DateHelper;
import com.example.tllo.domain.Orders;

@Controller
@RequestMapping(value = "/")
public class IndexController {
  private static Logger logger = LoggerFactory.getLogger(IndexController.class);

  @RequestMapping(value = "content1", method = RequestMethod.GET)
  public String content1(Model model) {
    logger.debug("IndexController:[content1] Passing through...");
    model.addAttribute("gmsg1", "グローバルメッセージ1");
    model.addAttribute("gmsg2", "グローバルメッセージ2");
    model.addAttribute("gmsg3", "グローバルメッセージ3");

    model.addAttribute("msg1", "メッセージ1");
    model.addAttribute("msg2", "メッセージ2");
    model.addAttribute("msg3", "メッセージ3");

    List<Orders> list = new ArrayList<>();

    Orders order1 = new Orders();
    order1.setId("1");
    order1.setOrderNumber(10100L);
    order1.setOrderDate(DateHelper.parse("2011-01-06"));
    order1.setRequiredDate(DateHelper.parse("2011-01-13"));
    order1.setShippedDate(DateHelper.parse("2011-01-10"));
    order1.setStatus("Shipped");
    order1.setComments(null);
    order1.setCustomerNumber(363L);
    list.add(order1);

    Orders order2 = new Orders();
    order2.setId("2");
    order2.setOrderNumber(10101L);
    order2.setOrderDate(DateHelper.parse("2011-01-09"));
    order2.setRequiredDate(DateHelper.parse("2011-01-18"));
    order2.setShippedDate(DateHelper.parse("2011-01-11"));
    order2.setStatus("Shipped");
    order2.setComments("Check on availability.");
    order2.setCustomerNumber(128L);
    list.add(order2);

    model.addAttribute("list", list);
    return "Index/content1";
  }

  @RequestMapping(value = "content2", method = RequestMethod.GET)
  public String content2(Model model) {
    logger.debug("IndexController:[content2] Passing through...");
    model.addAttribute("gmsg1", "グローバル電文1");
    model.addAttribute("gmsg2", "グローバル電文2");
    model.addAttribute("gmsg3", "グローバル電文3");

    Orders order = new Orders();
    order.setId("1");
    order.setOrderNumber(10100L);
    order.setOrderDate(DateHelper.parse("2011-01-06"));
    order.setRequiredDate(DateHelper.parse("2011-01-13"));
    order.setShippedDate(DateHelper.parse("2011-01-10"));
    order.setStatus("Shipped");
    order.setComments(null);
    order.setCustomerNumber(363L);

    model.addAttribute("order", order);

    return "Index/content2";
  }

}
```

#### Model

```java:Orders.java
package com.example.tllo.domain;

import java.util.Date;

public class Orders {

  private String id;

  private Long orderNumber;

  private Date orderDate;

  private Date requiredDate;

  private Date shippedDate;

  private String status;

  private String comments;

  private Long customerNumber;

  ...getter/setterは省略...
}
```

### テンプレート

thymeleaf layout dialect機能を使ったテンプレートを作成します。
作成するテンプレートファイルは下記のとおりです。

```text:tree
templates
 │  inc1.html
 │  layout.html
 │  rep1.html
 │
 └─Index
         content1.html
         content2.html
         partial3.html
```

#### レイアウトページ

layout.htmlは各コンテンツページのベースになるテンプレートです。
thymeleaf layout dialect機能を使うにはhtmlタグに`xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"`を記述します。

コンテンツページ(content1.html、content2.html)のコンテンツをlayout.htmlに取り込む記述は下記の箇所になります。

コンテンツページのpartial1という名前を付けた要素をこの位置に取り込みます。

```html:partila1
<div layout:fragment="partial1" th:remove="tag"></div>
```

コンテンツページのpartial2という名前を付けた要素をこの位置に取り込みます。

```html:partila2
<div layout:fragment="partial2" th:remove="tag"></div>
```

コンテンツページのpartial3という名前を付けた要素をこの位置に取り込みます。

```html:partila3
<div layout:fragment="partial3" th:remove="tag"></div>
```

コンテンツページのscriptsという名前を付けた要素をこの位置に取り込みます。

```html:scripts
<div layout:fragment="scripts" th:remove="tag"></div>
```

**layout.html全文**

```html:layout.html
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
  <title layout:title-pattern="$DECORATOR_TITLE - $CONTENT_TITLE">tllo-example</title>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <link href="/vendor/bootstrap-3.3.5/css/bootstrap.min.css" th:href="@{/vendor/bootstrap-3.3.5/css/bootstrap.min.css}" rel="stylesheet" />
</head>
<body>

  <!-- container start -->
  <div class="container">

    <div class="page-header">
      <h1>header</h1>
    </div>

    <!-- navi start -->
    <div class="row navi">
      <div class="col-md-12">
        <ul class="nav nav-pills">
          <li role="presentation"><a href="/content1" th:href="@{/content1}">content1</a></li>
          <li role="presentation"><a href="/content2" th:href="@{/content2}">content2</a></li>
        </ul>
      </div>
    </div>
    <!-- navi end -->

    <div class="row">
      <div class="col-md-12 well">
        <h3>dummy</h3>
        <p th:text="${gmsg1}"></p>
        <p th:text="${gmsg2}"></p>
        <p th:text="${gmsg3}"></p>
      </div>
    </div>

    <!-- contents -->
    <div layout:fragment="partial1" th:remove="tag"></div>

    <div layout:include="inc1 :: partial(id='message', header='Message')" class="row"></div>

    <div layout:replace="rep1 :: partial('メッセージ１', 'message2', '電文3')"></div>

    <!-- contents -->
    <div layout:fragment="partial2" th:remove="tag"></div>

    <!-- contents -->
    <div layout:fragment="partial3" th:remove="tag"></div>

    <div class="page-footer">
      <h3>footer</h3>
    </div>

  </div>
  <!-- container end -->

  <!-- scripts start -->
  <div layout:fragment="scripts" th:remove="tag"></div>
  <!-- scripts end -->

  <script src="/vendor/jquery/jquery-1.11.3.js" th:src="@{/vendor/jquery/jquery-1.11.3.js}"></script>
  <script src="/vendor/bootstrap-3.3.5/js/bootstrap.js" th:src="@{/vendor/bootstrap-3.3.5/js/bootstrap.js}"></script>
</body>
</html>
```

##### 部品ページ1(inc1.html)

部品化したページの取り込み方法の例その1です。
inc1.htmlは、layout.htmlへはめ込む要素(fragment="partial")を定義したテンプレートです。
この要素はlayout.htmlから渡された2つの引数(id, header)を受け取ります。

呼び出し元のlayout.htmlは下記のようになっています。
layout:includeを使用するとこの要素(divタグ)の中に、部品ページのlayout:fragmentの中の要素が取り込まれます。

```html:layout.html.include
<div layout:include="inc1 :: partial(id='message', header='Message')" class="row"></div>
```

**inc1.html全文**

```html:inc1.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<body>

    <div layout:fragment="partial(id, header)">
      <div class="col-md-12 well">
        <h3>partial - include</h3>
        <div>
          <ul>
            <li th:text="${id}">id</li>
            <li th:text="${header}">header</li>
          </ul>
        </div>
      </div>
    </div>

</body>
</html>
```

##### 部品ページ2(rep1.html)

部品化したページの取り込み方法の例その2です。
rep1.htmlは、layout.htmlへはめ込む要素(fragment="partial")を定義したテンプレートです。
この要素はlayout.htmlから渡された3つの引数(msg1, msg2, msg3)を受け取ります。

呼び出し元のlayout.htmlは下記のようになっています。
layout:replaceを使用するとこの要素(divタグ)が、部品ページのlayout:fragmentの要素に置き換わります。

```html:layout.html.replace
<div layout:replace="rep1 :: partial('メッセージ１', 'message2', '電文3')"></div>
```

**rep1.html全文**

```html:rep1.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<body>

  <div layout:fragment="partial(msg1, msg2, msg3)" class="row">
    <div class="col-md-12 well">
      <h3>partial - replace</h3>
      <div>
        <ul>
          <li th:text="${msg1}">message1</li>
          <li th:text="${msg2}">message2</li>
          <li th:text="${msg3}">message3</li>
        </ul>
      </div>
    </div>
  </div>

</body>
</html>
```

#### コンテンツページ1

thymeleaf layout dialect機能を使うにはhtmlタグに`xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"`と`layout:decorator="layout"`を記述します。

ベースのテンプレートのファイル名(拡張子は無し)を下記の場所で指定します。

```
layout:decorator="layout"
```

**headタグ**

headタグ内に記述した要素はベースのテンプレートにマジされます。

```html:content1.head
<title>content1</title>
<meta name="keywords" content="content1" />
<meta name="description" content="content1" />
```

下記はベースのレイアウトのheadタグです。
titleタグの`layout:title-pattern`を使用するとコンテンツページのtitleタグとベースレイアウトのtitleタグのテキストを指定したパターンで合成します。

```html:layout.head
<title layout:title-pattern="$DECORATOR_TITLE - $CONTENT_TITLE">tllo-example</title>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="/vendor/bootstrap-3.3.5/css/bootstrap.min.css" th:href="@{/vendor/bootstrap-3.3.5/css/bootstrap.min.css}" rel="stylesheet" />
```

アウトプットは下記の通りコンテンツページとベースレイアウトのheadタグの内容がマージされたものとなります。

```html
<title>tllo-example - content1</title>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="keywords" content="content1" />
<meta name="description" content="content1" />
<link href="/vendor/bootstrap-3.3.5/css/bootstrap.min.css" rel="stylesheet" />
```

**fragment**

下記のようにベースレイアウトにはめ込む要素を`layout:fragment`で名前をつけて記述します。
headタグとは違ってfragmentになっていない要素はベースレイアウトには一切反映されません。

```html
<div layout:fragment="partial1">
  ...コンテンツ...
</div>
```

**content1.html全文**

```html:Index/content1.html
<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorator="layout">
<head>
  <title>content1</title>
  <meta name="keywords" content="content1" />
  <meta name="description" content="content1" />
</head>
<body>

  <!-- container -->
  <div class="container">

    <div layout:fragment="partial1">
    <!-- partial1 start -->
    <div class="row partial1">
      <div class="col-md-12 well">
        <h3>content1 - partial1</h3>

        <table class="table table-striped" th:if="${list}">
          <thead>
            <tr>
              <th>#</th>
              <th>order Number</th>
              <th>order Date</th>
              <th>required Date</th>
              <th>shipped Date</th>
              <th>status</th>
              <th>customer Number</th>
            </tr>
          </thead>
          <tbody>
            <tr th:each="order, status : ${list}" th:object="${order}">
              <td th:text="${status.count}">#</td>
              <td th:text="*{orderNumber}">orderNumber</td>
              <td th:text="*{orderDate}">orderDate</td>
              <td th:text="*{requiredDate}">requiredDate</td>
              <td th:text="*{shippedDate}">shippedDate</td>
              <td th:text="*{status}">status</td>
              <td th:text="*{customerNumber}">customerNumber</td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>
    <!-- partial1 end -->
    </div>

    <div layout:fragment="partial2">
    <!-- partial2 start -->
    <div class="row partial2">
      <div class="col-md-12 well">
        <h3>content1 - partial2</h3>
        <div>
          <ul>
            <li th:text="${msg1}">message1</li>
            <li th:text="${msg2}">message2</li>
            <li th:text="${msg3}">message3</li>
          </ul>
        </div>
      </div>
    </div>
    <!-- partial2 end -->
    </div>

    <div layout:fragment="partial3">
    <!-- partial3 start -->
    <div layout:include="Index/partial3 :: partial(${msg1}, ${msg2}, ${msg3})" class="row"></div>
    <!-- partial3 end -->
    </div>

    <div layout:fragment="scripts">
      <!-- content1 page scripts -->
      <script src="js/content1.js" th:src="@{js/content1.js}" type="text/javascript"></script>
    </div>

  </div>
  <!-- container -->

</body>
</html>
```

##### コンテンツページ1の部品ページ

呼び出し元のcontent1.htmlは下記のようになっています。
取り込む部品ページの名前が"Index/partial3 ..."となっているように、ベーステンプレートであるlayout.htmlのある場所と部品ページの場所が異なる場合は、部品ページをベーステンプレートのある場所から指定します。

```html
<div layout:include="Index/partial3 :: partial(${msg1}, ${msg2}, ${msg3})" class="row"></div>
```

**partial3.html全文**

```html:Index/partial3.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<body>

  <div layout:fragment="partial(value1, value2, value3)">
      <div class="col-md-12 well">
        <h3>content1 - partial3</h3>
        <div>
          <ul>
            <li th:text="${value1}">value</li>
            <li th:text="${value2}">value</li>
            <li th:text="${value3}">value</li>
          </ul>
        </div>
      </div>
  </div>

</body>
</html>
```

##### アウトプット

```html
<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>tllo-example - content1</title>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <meta name="keywords" content="content1" />
  <meta name="description" content="content1" />
  <link href="/vendor/bootstrap-3.3.5/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>

  <!-- container start -->
  <div class="container">

    <div class="page-header">
      <h1>header</h1>
    </div>

    <!-- navi start -->
    <div class="row navi">
      <div class="col-md-12">
        <ul class="nav nav-pills">
          <li role="presentation"><a href="/content1" shape="rect">content1</a></li>
          <li role="presentation"><a href="/content2" shape="rect">content2</a></li>
        </ul>
      </div>
    </div>
    <!-- navi end -->

    <div class="row">
      <div class="col-md-12 well">
        <h3>dummy</h3>
        <p>グローバルメッセージ1</p>
        <p>グローバルメッセージ2</p>
        <p>グローバルメッセージ3</p>
      </div>
    </div>

    <!-- contents -->
    <!-- partial1 start -->
    <div class="row partial1">
      <div class="col-md-12 well">
        <h3>content1 - partial1</h3>

        <table class="table table-striped">
          <thead>
            <tr>
              <th>#</th>
              <th>order Number</th>
              <th>order Date</th>
              <th>required Date</th>
              <th>shipped Date</th>
              <th>status</th>
              <th>customer Number</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>1</td>
              <td>10100</td>
              <td>Thu Jan 06 00:00:00 JST 2011</td>
              <td>Thu Jan 13 00:00:00 JST 2011</td>
              <td>Mon Jan 10 00:00:00 JST 2011</td>
              <td>Shipped</td>
              <td>363</td>
            </tr>
            <tr>
              <td>2</td>
              <td>10101</td>
              <td>Sun Jan 09 00:00:00 JST 2011</td>
              <td>Tue Jan 18 00:00:00 JST 2011</td>
              <td>Tue Jan 11 00:00:00 JST 2011</td>
              <td>Shipped</td>
              <td>128</td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>
    <!-- partial1 end -->

    <div class="row">
      <div class="col-md-12 well">
        <h3>partial - include</h3>
        <div>
          <ul>
            <li>message</li>
            <li>Message</li>
          </ul>
        </div>
      </div>
    </div>

    <div class="row">
      <div class="col-md-12 well">
        <h3>partial - replace</h3>
        <div>
          <ul>
            <li>メッセージ１</li>
            <li>message2</li>
            <li>電文3</li>
          </ul>
        </div>
      </div>
    </div>

    <!-- contents -->
    <!-- partial2 start -->
    <div class="row partial2">
      <div class="col-md-12 well">
        <h3>content1 - partial2</h3>
        <div>
          <ul>
            <li>メッセージ1</li>
            <li>メッセージ2</li>
            <li>メッセージ3</li>
          </ul>
        </div>
      </div>
    </div>
    <!-- partial2 end -->

    <!-- contents -->
    <!-- partial3 start -->
    <div class="row">
      <div class="col-md-12 well">
        <h3>content1 - partial3</h3>
        <div>
          <ul>
            <li>メッセージ1</li>
            <li>メッセージ2</li>
            <li>メッセージ3</li>
          </ul>
        </div>
      </div>
    </div>
    <!-- partial3 end -->

    <div class="page-footer">
      <h3>footer</h3>
    </div>

  </div>
  <!-- container end -->

  <!-- scripts start -->
      <!-- content1 page scripts -->
      <script src="js/content1.js" type="text/javascript"></script>
  <!-- scripts end -->

  <script src="/vendor/jquery/jquery-1.11.3.js" xml:space="preserve"></script>
  <script src="/vendor/bootstrap-3.3.5/js/bootstrap.js" xml:space="preserve"></script>
</body>
</html>
```

![content1.png](https://qiita-image-store.s3.amazonaws.com/0/22772/d6d2ed56-2c2e-aada-f5f5-ef856c645fde.png)



#### コンテンツページ2

**content2.html全文**

```html:Index/content2.html
<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorator="layout">
<head>
  <title>content2</title>
  <meta name="keywords" content="content2" />
  <meta name="description" content="content2" />
</head>
<body>

  <!-- container -->
  <div class="container">

    <div layout:fragment="partial1">
    <!-- partial1 start -->
    <div class="row partial1">
      <div class="col-md-12 well">
        <h3>content2 - partial1</h3>
        <table class="table" th:if="${order}" th:object="${order}">
          <tbody>
            <tr>
              <th class="field-label col-xs-3 active">id</th>
              <td class="col-md-9" th:text="*{id}">id</td>
            </tr>
            <tr>
              <th class="field-label col-xs-3 active">order Number</th>
              <td class="col-md-9" th:text="*{orderNumber}">orderNumber</td>
            </tr>
            <tr>
              <th class="field-label col-xs-3 active">order Date</th>
              <td class="col-md-9" th:text="*{orderDate}">orderDate</td>
            </tr>
            <tr>
              <th class="field-label col-xs-3 active">required Date</th>
              <td class="col-md-9" th:text="*{requiredDate}">requiredDate</td>
            </tr>
            <tr>
              <th class="field-label col-xs-3 active">shipped Date</th>
              <td class="col-md-9" th:text="*{shippedDate}">shippedDate</td>
            </tr>
            <tr>
              <th class="field-label col-xs-3 active">status</th>
              <td class="col-md-9" th:text="*{status}">status</td>
            </tr>
            <tr>
              <th class="field-label col-xs-3 active">comments</th>
              <td class="col-md-9" th:text="*{comments}">comments</td>
            </tr>
            <tr>
              <th class="field-label col-xs-3 active">customer Number</th>
              <td class="col-md-9" th:text="*{customerNumber}">customerNumber</td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>
    <!-- partial1 end -->
    </div>

  </div>

</body>
</html>
```

##### アウトプット

```html
<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>tllo-example - content2</title>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <meta name="keywords" content="content2" />
  <meta name="description" content="content2" />
  <link href="/vendor/bootstrap-3.3.5/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>

  <!-- container start -->
  <div class="container">

    <div class="page-header">
      <h1>header</h1>
    </div>

    <!-- navi start -->
    <div class="row navi">
      <div class="col-md-12">
        <ul class="nav nav-pills">
          <li role="presentation"><a href="/content1" shape="rect">content1</a></li>
          <li role="presentation"><a href="/content2" shape="rect">content2</a></li>
        </ul>
      </div>
    </div>
    <!-- navi end -->

    <div class="row">
      <div class="col-md-12 well">
        <h3>dummy</h3>
        <p>グローバル電文1</p>
        <p>グローバル電文2</p>
        <p>グローバル電文3</p>
      </div>
    </div>

    <!-- contents -->
    <!-- partial1 start -->
    <div class="row partial1">
      <div class="col-md-12 well">
        <h3>content2 - partial1</h3>
        <table class="table">
          <tbody>
            <tr>
              <th class="field-label col-xs-3 active">id</th>
              <td class="col-md-9">1</td>
            </tr>
            <tr>
              <th class="field-label col-xs-3 active">order Number</th>
              <td class="col-md-9">10100</td>
            </tr>
            <tr>
              <th class="field-label col-xs-3 active">order Date</th>
              <td class="col-md-9">Thu Jan 06 00:00:00 JST 2011</td>
            </tr>
            <tr>
              <th class="field-label col-xs-3 active">required Date</th>
              <td class="col-md-9">Thu Jan 13 00:00:00 JST 2011</td>
            </tr>
            <tr>
              <th class="field-label col-xs-3 active">shipped Date</th>
              <td class="col-md-9">Mon Jan 10 00:00:00 JST 2011</td>
            </tr>
            <tr>
              <th class="field-label col-xs-3 active">status</th>
              <td class="col-md-9">Shipped</td>
            </tr>
            <tr>
              <th class="field-label col-xs-3 active">comments</th>
              <td class="col-md-9"></td>
            </tr>
            <tr>
              <th class="field-label col-xs-3 active">customer Number</th>
              <td class="col-md-9">363</td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>
    <!-- partial1 end -->

    <div class="row">
      <div class="col-md-12 well">
        <h3>partial - include</h3>
        <div>
          <ul>
            <li>message</li>
            <li>Message</li>
          </ul>
        </div>
      </div>
    </div>

    <div class="row">
      <div class="col-md-12 well">
        <h3>partial - replace</h3>
        <div>
          <ul>
            <li>メッセージ１</li>
            <li>message2</li>
            <li>電文3</li>
          </ul>
        </div>
      </div>
    </div>

    <!-- contents -->

    <!-- contents -->

    <div class="page-footer">
      <h3>footer</h3>
    </div>

  </div>
  <!-- container end -->

  <!-- scripts start -->
  
  <!-- scripts end -->

  <script src="/vendor/jquery/jquery-1.11.3.js" xml:space="preserve"></script>
  <script src="/vendor/bootstrap-3.3.5/js/bootstrap.js" xml:space="preserve"></script>
</body>
</html>
```

![content2.png](https://qiita-image-store.s3.amazonaws.com/0/22772/85afb827-5984-3ecd-7810-aaf4703da8c4.png)