概要
Spring BootとThymeleafを使って作るWebアプリで、各htmlのページに共通しているヘッダーやフッターを共通化する方法
環境
- Java8
- Spring Boot
- version: 2.1.9.RELEASE
- Thymeleaf
- version: 3.0.11.RELEASE
- Eclipse
- version: 2018-09 (4.9.0)
サンプル
ディレクトリ構成
Java側は省略しますが、templateと静的コンテンツの配置はこんな感じ。
src/main/resources
├── static
│ ├── css
│ │ ├── common.css
│ │ └── top.css
│ └── js
│ └── datepicker.js
└── templates
├── common.html
└── index.html
SpringBootはtemplates
配下のHTMLからCSSやJSファイルを参照する場合、
static
がルートディレクトリになるので、このような構成にしてます。
共通部品用のcommon.htmlを作成する
<html xmlns:th="http://www.thymeleaf.org">
<!-- (1)共通にしたいheadをfragment化する -->
<head th:fragment="meta_header(title,links,scripts)">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<!-- (2)共通で読み込むCSS/JS -->
<link rel="stylesheet" href="/css/common.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<!-- (3)タイトルのフォーマット -->
<title th:text="${title}+' | sample app'">各ページタイトル | sample app</title>
<!-- (4)各View固有で読み込むもの -->
<th:block th:replace="${links} ?: _" />
<th:block th:replace="${scripts} ?: _" />
</head>
<body>
<!-- (5)body内で共通化したい部品をfragment化する -->
<header th:fragment="header">
<h1><a th:href="@{'/'}">sample app</a></h1>
</header>
</body>
</html>
解説
(1) fragment名は引数を取れるのでtitle,links,scripts
を引数に設定する
(2) 各ページで共通に読み込むCSS/JSを記載する
(3) 引数のtitleを使ってth:text=""
にページタイトルのフォーマットを設定する
(4) 各ページで読み込むCSS/JSをth:replace
を使って差し込む
処理なしトークン(?: _
)を使うことで、${links}
がnullだった場合はth:block
自体が無かったものになる
(5) body内でも共通化したいものがあったらth:fragment
を使って部品化する
各html側で呼び出す
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<!-- (1)共通headerで置き換える -->
<head th:replace="common :: meta_header('top',~{::link},~{::script})">
<!-- (2)このページ固有で読み込むCSS/JS -->
<link rel="stylesheet" th:href="@{/css/top.css}" />
<script type="text/javascript" th:src="@{/js/datepicker.js}"></script>
</head>
<body>
<!-- (3)共通部品を呼び出す -->
<div th:replace="common :: header"></div>
<h2>top page</h2>
</body>
解説
(1) header
をcommon.html
で定義したものに引数を渡して置き換える
(2) このページ(このサンプルではindex.html
)固有で読み込むファイルを定義する
(3) 共通部品もth:replace="ページ名::fragment名"
で置き換える