内容
- 前回の続き
- SpringBootで簡単なCRUDアプリを作る
- 今回はThymeleafの共通部分をくくりだすリファクタリングをする
現状の確認
- ここまで以下の4つのhtmlファイルを作成している
src/main/resources/templates
└── players
├── edit.html
├── index.html
├── new.html
└── show.html
- 以下のように4つ全てのファイルでheadタグの内容はほとんど同じものになっている
- 違うのはtitleだけ
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8" />
<title>XXXX - baseball</title>
<link rel="stylesheet" href="/css/bootstrap.css" />
<script src="/js/jquery.js"></script>
<script src="/js/bootstrap.js"></script>
</head>
<body>
<!-- ここはページによって違う -->
</body>
</html>
- もしも新しくCSSやJavaScriptの読み込みを追加したりmetaタグを追加することになった場合、全てのファイルに同じ修正を加える必要がありメンテナンス性が良くない
- なので共通部分をくくりだしそれを全てのファイルから使うように修正する
手順
dependenciesの追加(SpringBoot2系の場合のみ)
- mavenの人は
pom.xml
、gradleの人はbuild.gradle
にライブラリのdependenciesを追加する - SpringBoot1系の場合はなくても動作する
pom.xml
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
</dependency>
build.gradle
compile('nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect')
共通ファイルの作成
-
src/main/resources/templates
にlayout.html
というファイルを作成し以下の内容を記述する
<!DOCTYPE html>
<!-- ① -->
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<meta charset="utf-8" />
<!-- ② -->
<title layout:title-pattern="$DECORATOR_TITLE - $CONTENT_TITLE">baseball</title>
<link rel="stylesheet" href="/css/bootstrap.css" />
<script src="/js/jquery.js"></script>
<script src="/js/bootstrap.js"></script>
</head>
<body>
<!-- ③ -->
<div layout:fragment="content"></div>
</body>
</html>
- ①:これまでのファイルとの違いは以下の記述が追加されている点である。
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
- この記述を追加することで共通ファイルとして扱うことができるようになる
- ②:titleはページごとに変更したいためその対応を記述している
-
$DECORATOR_TITLE
には各ページで定義したtitleが代入される -
$CONTENT_TITLE
には共通ファイル(このファイル)に定義したtitleが代入される - 今回の例の場合は以下のようなフォーマットでtitleが設定されることになる
各ページのタイトル - baseball
-
- ③:
<div layout:fragment="content"></div>
という目印をつけておくことで、各ページのコンテンツをこの部分と入れ替えることができる
共通ファイルの利用
- まずは
src/main/resources/templates/players/index.html
を修正する
<!DOCTYPE html>
<!-- ① -->
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="layout">
<head>
<!-- ② -->
<title>Listing Players</title>
</head>
<body>
<!-- ③ -->
<div class="container" layout:fragment="content">
<h1>Listing Players</h1>
<!-- 長いので省略 -->
</div>
</body>
</html>
- ①:以下の2つの記述が追加されている
- A:
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
- B:
layout:decorator="layout"
- Aは共通ファイルと同様のもので、これを書くことで共通ファイルの利用ができるようになる
- Bは利用する共通ファイルを指定している
- =の右辺が共通ファイルの拡張子を除いたファイル名と一致している
- 例えばもし共通ファイルが
template/sample/common.html
にあったとすると、Bの記述は以下のようになるlayout:decorator="sample/common"
- SpringBoot2系の人はこのままでも動くが公式のサンプルに従うと以下のよう書くと良い
layout:decorate="~{sample/common}"
- A:
- ②:headタグの中身がtitleだけになっている
- css等の読み込みは共通ファイルでやっているので全て削除している
- titleは各ページ固有の内容も設定するようにしているのでここで渡している
- この例では共通ファイルのtitleと組み合わさって以下のようなtitleになる
Listing Players - baseball
- この例では共通ファイルのtitleと組み合わさって以下のようなtitleになる
- もしこのページのみでheadタグに記載したい内容がある場合は、ここに記載するとことで共通ファイルの内容に追加して定義することができる
- ③:
layout:fragment="content"
とすることでこの記述以下のhtmlを、共通ファイルでlayout:fragment="content"
と記述した部分と入れ替えることができる
他のファイルも同様の修正を加える
src/main/resources/templates/players/new.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="layout">
<head>
<title>New Player</title>
</head>
<body>
<div class="container" layout:fragment="content">
<!-- 長いので省略 -->
</div>
</body>
</html>
src/main/resources/templates/players/edit.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="layout">
<head>
<title>Editing Player</title>
</head>
<body>
<div class="container" layout:fragment="content">
<!-- 長いので省略 -->
</div>
</body>
</html>
src/main/resources/templates/players/show.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="layout">
<head>
<title>Show Player</title>
</head>
<body>
<div class="container" layout:fragment="content">
<!-- 長いので省略 -->
</div>
</body>
</html>
動作確認
- 従来と同様の動作をすればOK