Spring Bootで作るWebアプリケーション〜Hello World編〜

# はじめに

Spring Boot + Thymeleaf を使用して，インテグレーションしながらWebアプリケーションを作りたいと思います．

本投稿では以下のような画面を表示することがゴールです．

<img width="660" alt="スクリーンショット 2020-06-17 21.23.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111511/f3cad69e-2b6a-d052-2304-7ac14c8490bf.png">


## 今回の材料

- Eclipse
- Gradle
- Spring Boot
- Thymeleaf

完成したソースは[こちら](https://github.com/HayashiTakaki/SpringBootNeko/releases/tag/1.1
)から参照可能です．

# 環境構築

[Eclipse](https://mergedoc.osdn.jp)の Java Standard Edition 64bit をインストールします．
※ 詳細は割愛

まずはプロジェクトを作成していきましょう．
<img width="552" alt="スクリーンショット 2020-06-14 12.40.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111511/363b17f1-9c0c-2abc-e3b0-edd0feca81df.png">
Eclipse で新規作成から「Spring スタータープロジェクト」を選択します．

<img width="553" alt="スクリーンショット 2020-06-14 12.41.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111511/971ab5de-5b19-d03c-7eaf-6619b1210486.png">

名前や Java のバージョンを指定します．
今回は Gradle を選択し，名前を「neko」としておきます．

<img width="553" alt="スクリーンショット 2020-06-14 16.56.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111511/8ccee40b-45cb-9e1d-4156-1b451ebf5e03.png">

依存関係に以下を追加します．

| 追加するもの               | 概要                                                      |
| -------------------------- | --------------------------------------------------------- |
| Spring Boot DevTools       | 開発用の便利ツール．とりあえず入れとけ．                  |
| Spring Web                 | Web アプリケーションで必要な Spring MVC と Apache, Tomcat |
| Thymeleaf TEMPLATE ENGINES | テンプレートエンジン Thymeleaf                            |
| Lombok                     | getter, setter を自動生成してくれる神                     |

初期設定直後にエラーが出る場合は Gradle のプロキシなど確認しましょう．

# Thymeleaf の HelloWorld

## Thymeleaf の作成

まずは`src/main/resources/templates/hello.html`を作成します．

```html:hello.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
  <head>
    <title>Hello</title>
    <meta charset="utf-8" />
  </head>
  <!-- 通常のコメント ブラウザでも表示されます． -->
  <!--/* Thymeleafのコメント ブラウザには表示されません */-->
  <body>
    <h1>Spring boot</h1>
    <p>
      <span th:text="${message}">このメッセージは置換されます．</span>
    </p>
  </body>
</html>
```

Thymeleaf では templates 配下に HTML ファイルを配置していきます．
通常の HTML に`th:`で始まる属性が追加されたような感じです．そのため，ファイルを直接ブラウザで表示することも可能です．(JSP にはないメリット)
`th:text`の場合は設定されている値で text を置き換えます．

## Controller の作成

`src/main/java/com/example/demo/controller/HelloController`を作成します．

```java:HelloController.java
package com.example.demo.controller;

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

@Controller
public class HelloController {
	@GetMapping("helloWorld") // helloWorldへのアクセスを制御する
	public String hello(Model model) {
		model.addAttribute("message", "にゃー"); // 変数messageに値をセットする．この値をThymeleafで表示できる
		return "hello"; // hello.htmlをクライアントに返す
	}
}
```

GET で`/helloWorld`が呼び出されたときに，messege に値をセットして，先ほど作成した`hello.html`を返す設定です．

## 起動

<img width="584" alt="スクリーンショット 2020-06-14 12.52.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111511/8c3b5b15-f120-1fd0-716d-6861aa5cbd9d.png">

Eclipse 上でプロジェクトを右クリックして，「実行」→「Spring Boot アプリケーション」で起動できます．
※ Gradle コマンドの場合は`./gradlew bootRun`で起動します．

起動するとコンソールに以下が出力されます．

```

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.3.1.RELEASE)
```

## 動作確認

http://localhost:8080/helloWorld
にアクセスして以下の画面が表示されれば OK です．

<img width="253" alt="スクリーンショット 2020-06-14 12.57.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111511/146446fb-593f-7665-fa10-a1ef6542a0bf.png">

# Thymeleaf の出力する値を変更する

さらに進んで以下の構成にしましょう．

view : thymeleaf
controller : リクエストを処理する
service : データの取得/更新
domain : データオブジェクト

### domain

```java:neko.java
package com.example.demo.domain;
import lombok.Data;
@Data
public class Neko {
	public Neko(String name, int age) {
		this.name = name;
		this.age = age;
	}

	private String name;
	private int age;
}
```

データオブジェクトです．getter/setter は lombok 様が付与してくださいます．
これといって説明することはありません．

### service

```java:NekoService.java
package com.example.demo.service;
import java.util.ArrayList;
import org.springframework.stereotype.Service;
import com.example.demo.domain.Neko;

@Service
public class NekoService {
	/**
	 * ねこの一覧を取得する
	 * @return　一覧
	 */
	public ArrayList<Neko> getNekoList() {
		ArrayList<Neko> list = new ArrayList<Neko>();
		list.add(new Neko("たま", 3));
		list.add(new Neko("みけ", 1));
		return list;
	}
}
```

ねこの一覧を取得するだけです．
今後の投稿で DB から取得するようになるかもしれません．

### controller

```java:NekoController.java
package com.example.demo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import com.example.demo.service.NekoService;
import lombok.RequiredArgsConstructor;

@Controller
@RequiredArgsConstructor
public class NekoController {
	@Autowired
	private final NekoService service;

	@GetMapping("neko") // nekoへのアクセスを制御する
	public String hello(Model model) {
		model.addAttribute("nekoList", service.getNekoList()); // nekoListにねこを詰め込む
		return "neko"; // neko.htmlをクライアントに返す
	}
}
```

`model.addAttribute`で Thymeleaf に渡す値を設定可能です．
今回は service から取得した一覧を`nekoList`として値を渡しておきます．

### view

```html:neko.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
  <head>
    <title>にゃー</title>
    <meta charset="utf-8" />
    <link
      rel="stylesheet"
      href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
      integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
      crossorigin="anonymous"
    />
  </head>
  <body>
    <h2>ネコチャン</h2>
    <table class="table table-striped">
      <thead>
        <tr>
          <th>#</th>
          <th>名前</th>
          <th>年齢</th>
        </tr>
      </thead>
      <tbody>
        <!-- nekoListの数だけループ -->
        <tr th:each="neko, status : ${nekoList}" th:object="${neko}">
          <!-- countは1スタートでカウント可能 -->
          <td th:text="${status.count}"></td>
          <!-- オブジェクトの値を参照 -->
          <td th:text="${neko.name}"></td>
          <!-- th:objectで指定した場合は*で参照可能 -->
          <td th:text="*{age}"></td>
        </tr>
      </tbody>
    </table>
  </body>
</html>
```

`nekoList`を使ってして受け取った値を表示します．
いろいろ使っていますが，以下のように利用可能です．

- `${nekoList}`で Controller で設定した値を参照可能
- `th:each`で配列の長さ分ループする.1 つめの変数`neko`に値が入り，2 つめの変数`status`にインデックスなどの情報が入る(省略可)
- `th:object`で指定したオブジェクトは子要素で参照するときに省略して書ける
- `${status.count}`で 1 始まりのインデックスを取得する．`index`だと 0 始まり．
- `${neko.name}`で値を参照
- `*{age}`で`th:object`の中を参照する

# メッセージをプロパティ化する

ラベルを外部ファイルに記載することも多いと思いますので，メッセージをプロパティファイルに記載します．

まずは，`src/main/resources/application.properties`に以下を記載します．

```properties:application.properties
# プロパティの名前(拡張子なし)
spring.messages.basename=messages
# キャッシュ時間指定なし
spring.messages.cache-seconds=-1
# 文字コード
spring.messages.encoding=UTF-8
```

そして同じディレクトリにmessages.propertiesを作成して以下のように定義します．

```properties:messages.properties
title.neko=ネコチャン!!
label.name=名前
label.age=年齢
```

最後にHTMLに`#{xxx}`の形式で記載するとプロパティに記載したメッセージが表示されます．

```html
<h2 th:text="#{title.neko}">Neko CHAN</h2>
```

# まとめ

SpringBoot + Thymeleafを使ってHello world的なアプリケーションを作成できました．
次回はDBアクセスについても作成したいと思います．