Eclipse で Spring Boot + Thymeleaf . (その３）

## はじめに
Eclipse で Spring Boot + Thymeleaf . (その２）の続き。
そのほかのThymeleaf の機能を使用してみます。
ループと、引数付きのLayoutを使用します。

## 開発環境
Windows 10 Pro 1709(16299.192)
Eclipse pleiades-4.7.3
java 1.8.0_162
spring-boot-2.0.2.RELEASE
thymeleaf-3.0.9.RELEASE

## ファイル構造
![image.png](https://qiita-image-store.s3.amazonaws.com/0/214982/1d515c1f-3c27-23aa-21ad-7127da4389db.png)

## pom.xml 自動生成のまま
``` 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.example</groupId>
	<artifactId>MyApp</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>MyApp</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

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

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<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-devtools</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

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


</project>

```

## MyAppApplication.java 自動生成のまま
``` java:MyAppApplication.java
package com.example.demo;

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

@SpringBootApplication
public class MyAppApplication {

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

## EmployeeBean.java
``` java:EmployeeBean.java
package com.example.demo;

import lombok.Data;

@Data
public class EmployeeBean {

    private String id            = "";
    private String name          = "";
    private String email         = "";

}
```

## EmployeeListFrom.java
``` EmployeeListFrom.java
package com.example.demo;

import java.util.List;

import lombok.Data;

@Data
public class EmployeeListForm {

	private List<EmployeeBean> employees;

}
```

## EmployeeFrom.java
``` java:EmployeeFrom.java
package com.example.demo;

import lombok.Data;

@Data
public class EmployeeForm {

	private EmployeeBean employee;

}
```

## EmployeeController.java
``` java:EmployeeController.java
package com.example.demo;

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

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class EmployeeController {

    @GetMapping("/list")
    public ModelAndView list(ModelAndView mav) {
    	EmployeeListForm form = new EmployeeListForm();
    	List<EmployeeBean> list = new ArrayList<EmployeeBean>();

    	EmployeeBean bean = new EmployeeBean();
    	bean.setId("1");
    	bean.setName("Ken");
    	bean.setEmail("ken@mail.coml");
    	list.add(bean);

    	bean = new EmployeeBean();
    	bean.setId("2");
    	bean.setName("Hanako");
    	bean.setEmail("hanako@mail.coml");
    	list.add(bean);

    	form.setEmployees(list);

    	mav.addObject("employeeListForm", form);


    	EmployeeForm employeeForm = new EmployeeForm();
    	employeeForm.setEmployee(bean);

    	mav.addObject("employeeForm", employeeForm);

    	mav.setViewName("contents/employeeList");

        return mav;
    }


	@PostMapping("/detail")
    public ModelAndView list(@ModelAttribute EmployeeForm employeeForm, ModelAndView mav) {
    	mav.addObject("employeeForm", employeeForm);
    	mav.setViewName("contents/employee");

        return mav;
    }
}
```

## application.properties
``` application.properties
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=admin
spring.datasource.driverClassName=org.postgresql.Driver

# disable driver's feature detection
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults = false

# without detection you have to set the dialect by hand
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect

```

## common/base.html
``` html:common/base.html
<head th:fragment="common_header(title,links)">
  <!-- 各ページのタイトル -->
  <title th:replace="${title}">The demo application</title>

  <!-- 共通ファイル -->

  <!-- 各ページ固有で読み込むリンク -->
  <th:block th:replace="${links}" />
</head>
```

## common/header.html

``` html:common/header.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>header</title>
</head>
<body>
    <div th:fragment="common_header" th:remove="tag">
        <h1>
            <a th:href="@{/}" style="background: #e5eCf9;">Staff Management System</a>
        </h1>
    </div>
</body>
</html>
```

## common/footer.html
``` html:common/footer.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>footer</title>
</head>
<body>
    <div th:fragment="common_footer" th:remove="tag">
        <p style="text-align: center; background: #e5eCf9;">Copyright &copy; 20XX CompanyName</p>
    </div>
</body>
</html>
```

## contents/employeeList.html
``` html:contents/employeeList.html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
 <head th:replace="common/base :: common_header(~{::title},~{::link})">  <!-- 追加 -->
  <title>従業員一覧</title>
  <link rel="stylesheet" th:href="@{/css/mycss.css}">
</head>
<body>

<div th:replace="common/header :: common_header"></div>  <!-- 追加 -->

<h1>Hello, Spring Boot!</h1>

<div th:object="${employeeListForm}">
	<table>
		<caption>
			<strong>従業員検索</strong>
		</caption>
		<thead>
			<tr>
				<th>ID</th>
				<th>NAME</th>
				<th>EMAIL</th>
			</tr>
		</thead>
		<tbody>
			<tr th:each="emp : *{employees}">
			    <td th:text="${emp.id}"></td>
			    <td th:text="${emp.name}"></td>
			    <td th:text="${emp.email}"></td>
			</tr>
		</tbody>
	</table>
</div>

<form th:action="@{/detail}" th:object="${employeeForm.employee}" method="post">
    <p>Id: <input required type="text" th:field="*{id}" />
       <em th:if="${#fields.hasErrors('id')}" th:errors="*{id}">Name Error</em></p>
    <p>Name: <input required type="text" th:field="*{name}" />
       <em th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Name Error</em></p>
    <p>Email: <input required type="email" th:field="*{email}" />
       <em th:if="${#fields.hasErrors('email')}" th:errors="*{email}">Email Error</em></p>
    <p><input type="submit" value="Submit" /></p>

</form>

<div th:replace="common/footer :: common_footer"></div>  <!-- 追加 -->

</body>
</html>
```

## contents/employee.html
``` html:contents/employee.html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
 <head th:replace="common/base :: common_header(~{::title},~{::link})">  <!-- 追加 -->
  <title>従業員詳細</title>
  <link rel="stylesheet" th:href="@{/css/mycss.css}">
</head>
<body>

<div th:replace="common/header :: common_header"></div>  <!-- 追加 -->

<h1>Hello, Spring Boot!</h1>


<form th:action="@{/detail}" th:object="${employeeForm.employee}" method="post">
    <p>Id: <input required type="text" th:field="*{id}" />
       <em th:if="${#fields.hasErrors('id')}" th:errors="*{id}">Name Error</em></p>
    <p>Name: <input required type="text" th:field="*{name}" />
       <em th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Name Error</em></p>
    <p>Email: <input required type="email" th:field="*{email}" />
       <em th:if="${#fields.hasErrors('email')}" th:errors="*{email}">Email Error</em></p>
    <p><input type="submit" value="Submit" /></p>

</form>

<div th:replace="common/footer :: common_footer"></div>  <!-- 追加 -->

</body>
</html>
```

## 動作確認
![image.png](https://qiita-image-store.s3.amazonaws.com/0/214982/375d685b-7fe9-be0c-4b04-32fa2e39f374.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/214982/dfe80eab-e31f-231d-6a20-24681a35b479.png)