【spring-mvc + Thymeleaf】 eclipse で spring プロジェクトを作成する

## はじめに

spring と Thymeleaf を使用する eclipse の`動的 Web プロジェクト`を作成する手順をまとめます。
本記事の要件は以下の通りです。

- `spring-mvc` を使用します
- `spring-boot` は使用しません
- view には `Thymeleaf` を使用します
- `Maven` を使用します

### 環境
- [pleiades-2020-06-ultimate-win-64bit-jre_20200702.zip](https://mergedoc.osdn.jp/)
  - OpenJDK 11
  - Tomcat 9

## 作業手順

### Step 0: 新規 Maven プロジェクト の作成
eclipse のメニュー:`[ファイル]-[新規]-[Maven プロジェクト]` を実行します。

1. プロジェクト名およびロケーションの選択
    -  シンプルなプロジェクトの作成(アーキタイプ選択のスキップ)
        - ONにします
    - 次へ <details><summary>(screenshot-1)</summary><div>![new-maven-project-1.JPG](https://raw.githubusercontent.com/wiki/sugao-anan/hello-spring/1/images/new-maven-project-1.JPG)</div></details>

2. プロジェクトの構成
    - ここでは、以下の通りに設定します。

      名前 | 値
      ------------ | -------------
      グループId | **com.example**
      アーティファクトId | **hello-spring**
      バージョン | 0.0.1-SNAPSHOT
      パッケージング | **war**
    - 完了 <details><summary>(screenshot-2)</summary><div>![new-maven-project-2.JPG](https://raw.githubusercontent.com/wiki/sugao-anan/hello-spring/1/images/new-maven-project-2.JPG)</div></details>

3. Maven プロジェクトの新規作成直後は以下の状態になっています。
    - JRE システム・ライブラリー [**J2SE-1.5**]
    - 動的 Web モジュールのバージョン: **2.5**
    - `Maven Java EE 構成問題`
        - `web.xml is missing and <failOnMissingWebXml> is set to true`
    - screenshot <details><summary>(screenshot-3)</summary><div>![hello-spring-1.JPG](https://raw.githubusercontent.com/wiki/sugao-anan/hello-spring/1/images/hello-spring-1.JPG)</div></details>

### Step 1: Java と動的 Web モジュールの設定
Javaのバージョンと動的 Web モジュールのバージョンを変更します。

#### Javaのバージョンを変更
1. pom.xml に以下のプロパティを設定します。

      名前 | 値
      ------------ | -------------
      java.version | 11
      maven.compiler.source | ${java.version}
      maven.compiler.target| ${java.version}

    <details><summary>pom.xml</summary><div>

    ``` 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.example</groupId>
      <artifactId>hello-spring</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <packaging>war</packaging>

      <!-- プロパティ -->
      <properties>
      	<java.version>11</java.version>
      	<maven.compiler.source>${java.version}</maven.compiler.source>
      	<maven.compiler.target>${java.version}</maven.compiler.target>
      </properties>
    </project>
    ```
    </div></details>
2.  プロジェクトを右クリックし、`[Maven]-[プロジェクトの更新...]` を実行します。
3.  Javaのバージョンを確認します。
    - JRE システム・ライブラリー [**JavaSE11**]

#### 動的 Web モジュールのバージョンを変更
1. プロジェクトのプロパティを開き、プロジェクト・ファセットで以下を設定します。
    - 動的 Web モジュールのバージョン: **4.0**<details><summary>(screenshot-4)</summary><div>![project-facet.JPG](https://raw.githubusercontent.com/wiki/sugao-anan/hello-spring/1/images/project-facet.JPG)</div></details>

2.  一旦、プロジェクトを閉じます(`[プロジェクトを閉じる]` を実行します)。
3.  再度、プロジェクトを開きます(`[プロジェクトを開く]` を実行します)。
4.  デプロイメント記述子で右クリックし、`配備記述子スタブの生成` を実行します。
5.  以下を確認します。
    - 動的 Web モジュールのバージョン: **4.0**
    - `src/main/webapp/WEB-INF/web.xml` が作成され、上記の `Maven Java EE 構成問題` が解消されている事
    - screenshot <details><summary>(screenshot-5)</summary><div>![hello-spring-2.JPG](https://raw.githubusercontent.com/wiki/sugao-anan/hello-spring/1/images/hello-spring-2.JPG)</div></details>

### Step 2: spring-mvc + Thymeleaf の設定
ここから、`spring-mvc` と `Thymeleaf` の為の設定です。
次の3つのファイルを設定します。

- pom.xml
- src/main/webapp/WEB-INF/web.xml
- src/main/webapp/WEB-INF/spring/dispatcher-config.xml

#### pom.xml
ライブラリの依存関係を設定します。

<details><summary>pom.xml</summary><div>

``` 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>hello-spring</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>

  <!-- (1) プロパティ -->
  <properties>
  	<java.version>11</java.version>
  	<maven.compiler.source>${java.version}</maven.compiler.source>
  	<maven.compiler.target>${java.version}</maven.compiler.target>
  	<org.springframework.version>5.2.8.RELEASE</org.springframework.version>
  	<org.thymeleaf.version>3.0.11.RELEASE</org.thymeleaf.version>
  </properties>

  <!-- (2) 依存関係 -->
  <dependencies>
  	<!-- #1 -->
  	<dependency>
  		<groupId>org.springframework</groupId>
  		<artifactId>spring-webmvc</artifactId>
  		<version>${org.springframework.version}</version>
  	</dependency>
  	<!-- #2 -->
  	<dependency>
  		<groupId>org.thymeleaf</groupId>
  		<artifactId>thymeleaf-spring5</artifactId>
  		<version>${org.thymeleaf.version}</version>
  	</dependency>
  	<!-- #3 -->
  	<dependency>
  		<groupId>org.slf4j</groupId>
  		<artifactId>slf4j-simple</artifactId>
  		<version>1.7.25</version>
  	</dependency>
  </dependencies>
</project>
```
</div></details>

1. プロパティ

    名前 | 値
    ------------ | -------------
    org.springframework.version | 5.2.8.RELEASE
    org.thymeleaf.version | 3.0.11.RELEASE

2. 依存関係

     No. | groupId | artifactId | version| scope
    ----:|------------ | ------------- | ------------- | -------------
    1 | org.springframework | [spring-webmvc](https://mvnrepository.com/artifact/org.springframework/spring-webmvc) | ${org.springframework.version} | (compile)
    2 | org.thymeleaf | [thymeleaf-spring5](https://mvnrepository.com/artifact/org.thymeleaf/thymeleaf-spring5) | ${org.thymeleaf.version} | (compile)
    3 | org.slf4j | [slf4j-simple](https://mvnrepository.com/artifact/org.slf4j/slf4j-simple) | 1.7.25 | (compile)

#### web.xml

<details><summary>web.xml</summary><div>

``` xml:src/main/webapp/WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">
  <display-name>hello-spring</display-name>

  <!-- (1) リスナーの設定 -->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <!-- (2) コンテキスト構成の定義ファイルの場所 -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value></param-value>
  </context-param>

  <!-- (3) DispatcherServlet の設定 -->
  <servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/spring/dispatcher-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

</web-app>
```
</div></details>

1. リスナーの設定
2. contextConfigLocation パラメーターを使用して、コンテキスト構成の定義ファイルの場所を指定できます。
    -  この設定を省略した場合、`/WEB-INF/applicationContext.xml` を用意する必要があります。
    -  空を指定した場合、定義ファイルを用意する必要はありません。
3. DispatcherServlet の設定

#### dispatcher-config.xml

<details><summary>dispatcher-config.xml</summary><div>

``` xml:src/main/webapp/WEB-INF/spring/dispatcher-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:mvc="http://www.springframework.org/schema/mvc"
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

  <!-- (1) コンポーネントスキャン -->
  <context:component-scan base-package="com.example.demo.app" />

  <!-- (2) -->
  <mvc:annotation-driven />

  <!-- (3) -->
  <bean id="templateResolver"
    class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
    <property name="prefix" value="/WEB-INF/views/" />
    <property name="suffix" value=".html" />
    <property name="templateMode" value="HTML" />
    <property name="characterEncoding" value="UTF-8" />
  </bean>
  <bean id="templateEngine"
    class="org.thymeleaf.spring5.SpringTemplateEngine">
    <property name="templateResolver" ref="templateResolver" />
  </bean>
  <mvc:view-resolvers>
    <bean class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
      <property name="templateEngine" ref="templateEngine" />
      <property name="characterEncoding" value="UTF-8" />
      <property name="forceContentType" value="true" />
      <property name="contentType" value="text/html;charset=UTF-8" />
    </bean>
  </mvc:view-resolvers>

</beans>
```
</div></details>

1. コンポーネントスキャン
    - `base-package` で指定されたパッケージ以下で `@Component` 等のアノテーションが付与されたクラスがスキャンされます。
    - ここでは、後述の `@Controller` が付与された `com.example.demo.HomeController` クラスがスキャンされます。
2. mvc:annotation-driven
    - この要素を定義する事により、Spring MVCのデフォルト設定が行われます。
3. mvc:view-resolvers
    - thymeleaf用のViewResolverを指定し、thymeleafファイルの配置場所を定義します。

### Step 3: サンプルコードを追加
サンプルの controller と view のコードを追加します。

<details><summary>controller: src/main/java/com/example/demo/app/welcome/HomeController.java</summary><div>

``` java:src/main/java/com/example/demo/app/welcome/HomeController.java
package com.example.demo.app.welcome;

import java.util.Date;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HomeController {

	@GetMapping(value="/")
	private String home(Model model) {
		model.addAttribute("message", "hello springframework."+"[こんにちは春]");
		model.addAttribute("time", new Date());
		return "welcome/home";
	}
}
```
</div></details>

<details><summary>view: src/main/webapp/WEB-INF/views/welcome/home.html</summary><div>

``` html:src/main/webapp/WEB-INF/views/welcome/home.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1 th:text="${message}"></h1>
	<p th:text="${time}"></p>
	<p>あいうえお</p>
</body>
</html>
```
</div></details>

## 動作確認

1. 新規にサーバー: `Tomcat v9.0 サーバー` を作成します。<details><summary>手順：新規サーバーの定義</summary><div>![new-server-1.JPG](https://raw.githubusercontent.com/wiki/sugao-anan/hello-spring/1/images/new-server-1.JPG)</div></details>

2. 作成した Tomcat サーバーに今回作成した `hello-spring` プロジェクトを追加します。<details><summary>手順：サーバー上に構成済みのリソースを追加</summary><div>![new-server-2.JPG](https://raw.githubusercontent.com/wiki/sugao-anan/hello-spring/1/images/new-server-2.JPG)</div></details>

3. Tomcat サーバーを起動します。<details><summary>手順：サーバーの開始</summary><div>![new-server-3.JPG](https://raw.githubusercontent.com/wiki/sugao-anan/hello-spring/1/images/new-server-3.JPG)</div></details>

4. ブラウザからに [http://localhost:8080/hello-spring/](http://localhost:8080/hello-spring/) にアクセスします。<details><summary>手順：ブラウザから動作確認</summary><div>![new-server-4.JPG](https://raw.githubusercontent.com/wiki/sugao-anan/hello-spring/1/images/new-server-4.JPG)</div></details>

## ソース一式
ソース一式は以下の場所にあります。

- [https://github.com/sugao-anan/hello-spring/releases/tag/v0.1.0.1](https://github.com/sugao-anan/hello-spring/releases/tag/v0.1.0.1)

## 参考にしたサイト

- [Spring Web MVCを利用するプロジェクトのひな型を作成する手順 - Qiita](https://qiita.com/rubytomato@github/items/1d48ef0368e7297a1c5c)
- [Spring MVC - soracane](https://sites.google.com/site/soracane/home/springnitsuite/spring-mvc)
- [Spring5入門\[STS(Spring Tool Suite)の環境作成と簡単なWebアプリの作成\] - Small Java world](https://javaworld.helpfulness.jp/post-296/)


以上