トッカンソフトウェア

SpringBoot Thymeleaf レイアウト

今回はThymeleafのレイアウトをやります。環境設定等はこちらを参照下さい。
単純なThymeleafの画面はこちらを参照下さい。


thymeleaf-layout-dialectを使ったレイアウト

pom.xmlにthymeleaf-layout-dialectを追加します。

pom.xml
				
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.1.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	<name>demo</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

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

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>nz.net.ultraq.thymeleaf</groupId>
			<artifactId>thymeleaf-layout-dialect</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>


			

データを連携するための単純なクラス。

UserModel.java
				
package spring.test;

public class UserModel {
	String id;
	String name;

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}


			

Thymeleafからアクセスされるコントローラクラス。

LoginControler.java
				
package spring.test.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import spring.test.UserModel;

@Controller
@RequestMapping(value = "/login")
public class LoginControler {

	@RequestMapping(method = RequestMethod.GET)
	public String loginGet(@ModelAttribute("UM") UserModel userModel) {
		userModel.setId("初期値");
		return "login";
	}

	@RequestMapping(method = RequestMethod.POST)
	public ModelAndView loginPost(@ModelAttribute("UM") UserModel userModel) {

		String id = userModel.getId();
		ModelAndView mv = new ModelAndView("login");
		if (id.equals("abc")) {
			userModel.setName("ABCさん");
			mv.addObject("msg", "ログイン成功");
		} else {
			userModel.setName("");
			mv.addObject("msg", "ログイン失敗");
		}
		return mv;
	}
}


			

各画面の共通部分にあたるHTML。layout:fragmentで置き換える場所を指定。

layout.html
				
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
	xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<title>各画面のタイトルに置き換えられる</title>;
<meta charset="UTF-8">
<meta name="description" content="layoutの説明">
<script type="text/javascript">
	alert("Hello");
</script>
</head>
<body>
	<div layout:fragment="main">各画面メイン部分</div>
	<span th:text="${msg}"></span>
</body>
</html>

			

各画面。今回はログイン画面。layout:fragmentで置き換える場所を指定。
<head>はlayout:fragmentを指定しなくても共通部分に追加される。
layout:decorateで共通HTML("~{ファイル名}")を指定する。

login.html
				
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
	xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
	layout:decorate="~{layout}">
<head>
<title>ログイン</title>
<meta charset="UTF-8">
<meta name="description" content="ログインの説明">
<script type="text/javascript">
	alert("World");
</script>
</head>
<body>
	<form layout:fragment="main" th:action="@{/login}" method="post"
		th:object="${UM}">

		ID: <input type="text" th:field="*{id}" /> 
		<input type="text" th:field="*{name}" disabled /> 
		<BR /> 
		<input type="submit" value="ログイン" /> <BR />
	</form>
	<div>ここは出力されない</div> 
</body>
</html>

			
ブラウザで表示されるHTML
				

<!DOCTYPE html>
<html>
<head>

<title>ログイン</title>
<meta charset="UTF-8">
<meta name="description" content="layoutの説明">
<script type="text/javascript">
	alert("Hello");
</script>
<meta charset="UTF-8">
<meta name="description" content="ログインの説明">
<script type="text/javascript">
	alert("World");
</script>
</head>
<body>
	<form action="/login" method="post">

		ID: <input type="text" id="id" name="id" value="abc" /> 
		<input type="text" disabled id="name" name="name" value="ABCさん" /> 
		<BR /> 
		<input type="submit" value="ログイン" /> <BR />
	</form>
	<span>ログイン成功</span>
</body>
</html>

			
ファイルの配置は以下。


実行イメージアは以下。「Hello」のダイアログ→「World」のダイアログ→WEB画面の順に表示される。

th:replace、th:insert、th:fragmentを使ったレイアウト

thymeleaf-layout-dialectを使わずにThymeleafの機能だけでレイアウトをやります。
thymeleaf-layout-dialectは使わないのでpom.xmlから外します。

pom.xml
				
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.1.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	<name>demo</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

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

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>


			

thymeleaf-layout-dialectでは共通レイアウトに各画面を埋め込むような感じでしたが、 今回は各画面に共通レイアウトの部品を埋め込むような感じになります。
th:fragmentが各画面に埋め込む部分になります。

layout.html
				
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>ここは使われない</title>
<meta charset="UTF-8">
<meta name="description" content="layoutの説明">
<script th:fragment="js" th:remove="tag" >
	alert("Hello");
</script>
</head>
<body>
	<div>ここも使われない</div>
	<span th:text="${msg}" th:fragment="message" ></span>
</body>
</html>

			

th:insert、th:replaceで共通レイアウトの部品を持ってきます。th:insertは自身のタグの中を共通レイアウトの部品で置き換え、 th:replaceは自身のタグごと置き換えます。 共通レイアウトでth:remove="tag"を加えると、共通レイアウトのth:fragmentが書かれているタグが出力されません。

login.html
				
					
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>ログイン</title>
<meta charset="UTF-8">
<meta name="description" content="ログインの説明">
<script type="text/javascript" th:insert="~{layout :: js}">
	alert("World");
</script>
</head>
<body>
	<form th:action="@{/login}" method="post" th:object="${UM}">

		ID: <input type="text" th:field="*{id}" /> 
		<input type="text" th:field="*{name}" disabled /> 
		<BR /> 
		<input type="submit" value="ログイン" /> 
		<BR />
	</form>
	<div th:replace="~{layout :: message}">置き換えられる</div>
</body>
</html>

			
ブラウザで表示されるHTML
				

<!DOCTYPE html>
<html>
<head>
<title>ログイン</title>
<meta charset="UTF-8">
<meta name="description" content="ログインの説明">
<script type="text/javascript">
	alert("Hello");
</script>
</head>
<body>
	<form action="/login" method="post">

		ID: <input type="text" id="id" name="id" value="初期値" /> 
		<input type="text" disabled id="name" name="name" value="" /> 
		<BR /> 
		<input type="submit" value="ログイン" /> 
		<BR />
	</form>
	<span ></span>
</body>
</html>

			


ページのトップへ戻る