Spring BootとThymeleafでLayoutを共通化する方法
Spring BootとThymeleafでLayoutを共通化する方法です。
Thymeleaf の Layoutは、Tiles のように共通レイアウトを定義する仕組みです。
ヘッダ・ナビゲーション・コンテンツ・フッタを、それぞれ部品化することで生産性・保守性の向上が図れます。
以前、「Spring Bootでヘッダ・フッタの共通化する方法」でも書きましたが、今回はもう少し実務に寄った使い方を紹介したいと思います。
ここでは Spring BootとThymeleafでLayoutを共通化する方法 を紹介します。
Sponsored Links
この記事で作られるWebアプリ
最終形はこうです。
一般的な Web サイトの構成ですね。
これを Thymeleaf の Layout dialect でやってみたいと思います。この機能を利用すると、ベースとなるテンプレートページに、各コンテンツページを組み込んでページを生成することができるようになります。
Sponsored Links
環境
- Spring Boot 1.4.1
- Thymeleaf 3.0.2
- Windows7
- Java8
- Eclipse 4.6 Neon
こちらの「Spring Bootで静的ページを配置する方法」を参考に、Spring Bootのサンプルアプリを作ってみてください。すでにSpring Boot Webアプリがある場合には読み飛ばして結構です。
Layout作成
プロジェクトの pom.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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>jp.demos.spbfe</groupId> <artifactId>spring-boot-frontend</artifactId> <version>0.0.1-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.1.RELEASE</version> </parent> <properties> <java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <thymeleaf.version>3.0.2.RELEASE</thymeleaf.version> <thymeleaf-layout-dialect.version>2.0.5</thymeleaf-layout-dialect.version> </properties> <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>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>bootstrap</artifactId> <version>3.3.7</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>1.12.4</version> </dependency> </dependencies> </project>
まず、templates フォルダー内に layout フォルダーを作り、パーツとなる 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="$CONTENT_TITLE | $LAYOUT_TITLE">Thymeleaf de layout</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 rel="stylesheet" media="all" th:href="@{/webjars/bootstrap/3.3.7/css/bootstrap.min.css}" /> <link rel="stylesheet" media="all" th:href="@{/css/style.css}" /> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]--> </head> <body> <div layout:replace="~{layout/header::header}"></div> <div layout:replace="~{layout/navi::navbar}"></div> <div id="content" class="clearfix"> <div class="container"> <div layout:fragment="content" th:remove="tag"></div> </div> </div> <div layout:replace="~{layout/footer::footer}"></div> <script type="text/javascript" th:src="@{/webjars/jquery/1.12.4/jquery.min.js}"></script> <script type="text/javascript" th:src="@{/webjars/bootstrap/3.3.7/js/bootstrap.min.js}"></script> </body> </html>
Thymeleaf layout dialect 機能を使うにはhtmlタグに
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
と記述します。
タイトルを切り替えるために layout:title-pattern を使います。「$CONTENT_TITLE」がコンテンツページのタイトルで、「$LAYOUT_TITLE」が Web サイトのタイトルになります。
<title layout:title-pattern="$CONTENT_TITLE | $LAYOUT_TITLE">Thymeleaf de layout</title>
次に、部品化したコンテンツページ(ヘッダ部など)を読み込みます。
<div layout:replace="~{layout/header::header}"></div>
これは layout フォルダー内の header.html の header という名前を付けた部分(th:fragment="名前")を、この位置に読み込むという意味になります。replace なのでタグごと置換されます。
そして、メインコンテンツの読み込みです。ここが動的に切り替わる部分となります。
<div layout:fragment="content" th:remove="tag"></div>
・header.html
ヘッダ部の 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> <header id="global-header" layout:fragment="header"> <div class="container"> <div id="row"> <div class="col-sm-9 col-md-9"> <a href="/">ロゴ</a> </div> <div class="col-sm-3 col-md-3"> <a href="/contact/" title="Contact us">お問い合わせ</a> </div> </div> </div> </header> </body> </html>
・navi.html
ナビバーの 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 id="global-navbar" layout:fragment="navbar" class="clearfix"> <nav class="navbar navbar-default" role="navigation"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <span class="navbar-brand visible-xs">メニュー</span> </div> <div class="navbar-collapse collapse"> <ul class="nav navbar-nav"> <li><a href="/" title="ホーム">ホーム<br/><small>HOME</small></a></li> <li><a href="/company/" title="会社概要">会社概要<br/><small>COMPANY</small></a></li> <li><a href="/service/" title="サービス">サービス<br/><small>SERVICE</small></a></li> <li><a href="/recruit/" title="採用情報">採用情報<br/><small>RECRIT</small></a></li> </ul> </div> </div> </nav> </div> </body> </html>
・footer.html
フッターの 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 id="global-footer" layout:fragment="footer"> <footer> <p class="text-right"><small>Copyright(C) Sakakibara Engineering Co.,Ltd, All rights reserved.</small></p> </footer> </div> </body> </html>
・index.html
templates 配下の index.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:decorate="~{layout/layout}"> <head> <title>TOP PAGE</title> <meta name="keywords" content="springboot,thymeleaf,layout,トップページ" /> <meta name="description" content="SpringBootとThymeleafのLayoutを使ってWebサイトを作るサンプルです。ここはトップページです。" /> </head> <body> <div layout:fragment="content"> <p style="height:150px;"> トップページです。 </p> </div> </body> </html>
ポイントは
layout:decorate="~{layout/layout}"
です。
layout:decorate を使うことで、layout.html をベーステンプレートして扱うことができます。
ここまでできたら「mvn clean」、「mvn test」を実行して動作を確認します。
こんなページができると思います。
おお、いい感じですねー^^
Sponsored Links
ページを増やしてみる
では、早速ページを増やしてみましょう。
templates 配下に contents フォルダーを作って、下図のようにページを配備します。
・company.html
会社情報のページを作ります。内容は index.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:decorate="~{layout/layout}"> <head> <title>会社情報</title> <meta name="keywords" content="springboot,thymeleaf,layout,会社情報" /> <meta name="description" content="SpringBootとThymeleafのLayoutを使ってWebサイトを作るサンプルです。ここは会社情報のページです。" /> </head> <body> <div layout:fragment="content"> <p style="height:150px;"> 会社情報のページです。 </p> </div> </body> </html>
他のページもコピペで作ってみてください。
・IndexController
各ページへ遷移できるように、コントローラークラスを変更します。
package jp.demos.spbfe; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller public class IndexController { @RequestMapping(value = "/", method = RequestMethod.GET) String index() { return "index"; } @RequestMapping(value = "/company/", method = RequestMethod.GET) String comapny() { return "contents/company"; } @RequestMapping(value = "/service/", method = RequestMethod.GET) String service() { return "contents/service"; } @RequestMapping(value = "/recruit/", method = RequestMethod.GET) String recruit() { return "contents/recruit"; } @RequestMapping(value = "/contact/", method = RequestMethod.GET) String contact() { return "contents/contact"; } }
「mvn clean」、「mvn test」を実行して動作を確認します。
各グローバルメニューをクリックしてページ遷移を確認しましょう。
おおお、うまくいきましたねー^^
参考サイト
・Rename layoutdecorator to layoutdecorate · Issue #95 · ultraq-thymeleaf-layout-dialect · GitHub
・[MAJOR FEAT] Fragment Expressions · Issue #451 · thymeleaf-thymeleaf · GitHub
Sponsored Links
まとめ
Spring BootとThymeleafでLayoutを共通化する方法を紹介しました。
Thymeleaf の Layout を使うと、ページを部品化・共通化できて、とてもいい感じに仕上がります。同じ記述を何度も書くなんて生産性も保守性も悪いですからね。これをうまく活用して、開発効率を上げたいものです。
あ、Tiles に慣れた方ならすぐに使えるようになると思いますよー^^
皆さんも試してみてください。
おつかれさまでした。
Sponsored Links