【Eclipse】SpringBootのviewを作成する

# はじめに
MVCモデルの内、ビューを作成する手順を学習したのでアウトプットします。
Controllerから送信された指示に沿って、ブラウザに提供するためのHTMLを動的に構築するテンプレートを使用できます。

## テンプレートエンジンを使う

HTMLのひな形（テンプレート）に変数や繰り返し処理などのプログラムを記述し、画面に出力するためのライブラリをテンプレートエンジンと呼びます。

SpringBootはテンプレートエンジンを使用することでサーバーサイドが用意した変数や処理をHTMLに付与することができるため、使用するアマゾンや楽天などのようなショッピングサイトや商品管理システムなど使用するユーザーに応じて可変する動的なサイトを構築できます

### テンプレートエンジンは複数存在する

使用されるテンプレートエンジンは使用する言語により様々存在しますが、Spring Bootで最も一般的に使用されるテンプレートエンジンは`Thymeleaf(タイムリーフ)`と呼ばれるテンプレートエンジンなので、この記事ではタイムリーフを使った操作方法を紹介しています。

## テンプレートを利用するための初期設定

Eclipse（エクリプス）にはThymeleaf（タイムリーフ）が最初から組み込まれているわけではありませんので、新しく追加する必要があります。

Eclipseは依存関係管理のための機能を提供しており、つまり追加機能を紐付けするための`コードを手動で記述する`ことで、ライブラリやモジュールが追加されて使用することができます。以下は、ThymeleafをEclipseプロジェクトで使用可能にするための手順です。

### ①依存関係の追加(コードを書き足す）

テンプレートエンジンを使用するためには作成したプロジェクトファイルのコードを編集する必要があります。

#### build.gradleファイル
`Springスターター・プロジェクト`で作成したプロジェクトディレクトリの
ルート直下にあります

新しく作成したプロジェクト名が`spring_boot_introduction`の場合
```java:プロジェクトのデフォルト保存先
/Applications/Eclipse_2023-06.app/Contents/workspace/spring_boot_introduction
```
![スクリーンショット 2023-06-23 13.52.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2765288/c3926004-1a8e-5de1-6c18-9c3eb07cac58.png)
#### build.gradleファイルを編集する
build.gradleというファイルを開くと`dependencies`という項目（ブロック）が存在するため以下のコードを追記します
```css
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'

/* 追記して上書き保存します */
```


```css:build.gradle
plugins {
	id 'java'
	id 'org.springframework.boot' version '2.7.12'
	id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'

java {
	sourceCompatibility = '1.8'
}

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	//　次のように貼り付けする
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	
}

tasks.named('test') {
	useJUnitPlatform()
}

```
もしもbuild.gradleファイルが見つからない場合は作成したプロジェクトディレクトリからファイル名`build.gradle`を検索してください

### 編集した依存関係を反映させる

`Gradle プロジェクトのリフレッシュ`を実行します

プロジェクトを選択し右クリック→【Gradle】→【Gradle プロジェクトのリフレッシュ】

![スクリーンショット 2023-06-24 8.46.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2765288/a99ed26e-c0d3-99bb-105a-a9718a65800c.png)


Gradle(グレイドル）は、ソースコード（人間が書いたコード）を実行可能なソフトウェアに変換するためのツールの一つです(例えば、Javaの場合は.jarファイルや.warファイル)

build.gradleに記述したThymeleaf（タイムリーフ）を使用するための依存関係を示すコードはまだ反映されていないためプロジェクトの設定ファイルをリフレッシュすることで反映させます

#### どうしてもThymeleafが追加できない場合
新しくプロジェクトを作成する際に、`Springスターター・プロジェクト`のウィザードの途中でThymeleafを導入する選択肢が存在するので、選択すれば最初からThymeleafを使用できます

![スクリーンショット 2023-06-22 15.19.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2765288/aa79e50c-0fe2-658a-0cdb-3e978c36d2e4.png)

## テンプレートを作成する

これから動的なHTMLを作成するために新しいテンプレートを作成します

テンプレートは次の条件に沿って作成します
- 作成場所：`src\main\resources\templates`
- ファイル拡張子:`html` 
- ファイル名：メソッド名とファイル名を同じにする（必須ではなく推奨）

Eclipseで操作する場合、パッケージ・エクスプローラーから作成操作ができます
`templates`というディレクトリがあるため右クリックでテンプレートを作成しましょう
![スクリーンショット 2023-06-23 14.50.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2765288/0fd9383e-1af7-e243-4a7f-10fc593e41c5.png)
![スクリーンショット 2023-06-23 14.54.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2765288/1606d863-f6e8-51a2-5b4f-778100a795e6.png)
![スクリーンショット 2023-06-23 14.55.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2765288/aac64f14-52cb-4820-4688-4e1ec618aba1.png)
![スクリーンショット 2023-06-23 14.57.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2765288/40b7ccf7-6692-36f5-12e1-fae986a13b64.png)

## テンプレートファイルを編集する

はじめに、`Thymeleaf(タイムリーフ）の機能を使用する場合`は、必ずHTMLタグ内でThymeleafの`名前空間を定義する必要`があります。以下のようになります。

以下のように名前空間を定義しない場合Thymeleafの特定の属性や構文（th:で始まるもの）を使用しようとするとエラーが発生します。

```html:index.html
<!DOCTYPE html>
<!-- htmlタグに名前空間を定義する -->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <h1>Hello world!!</h1>
</body>
</html>

```

## 検索されたURLから表示するテンプレートを設定する

ブラウザから検索されたURLと作成したthmlを紐付けするためには
Controllerのコードを編集し、表示するテンプレートを指定します

https://qiita.com/EasyCoder/items/f3059372bb61dcfad137

![スクリーンショット 2023-06-23 15.31.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2765288/60087f08-2639-52ed-e4e8-8e5c094a5f21.png)

```java:LessonController.java
package com.example.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/lesson")
public class LessonController {
    @GetMapping("/sample")
    // HTMLをレスポンスにする場合は、@ResponseBodyを削除する
    // @ResponseBody
    public String sample() {
        return "index";
    }
}
```
## アプリケーションを実行する
プロジェクト内のプログラムを動かすためにはアプリケーションの実行をする必要があります

アプリケーションを実行することによりWebサーバーが起動し、リクエストに応じたプログラムが動くようになります。

今回作成した対象のプロジェクトを右クリックで選択し、
`実行`→`Spring Boot アプリケーション` を選択します

![スクリーンショット 2023-06-23 9.54.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2765288/287aa584-ea43-798d-92d1-33b8d953450a.png)

実行することでコンソールに次の表示が出ていれば起動が完了しています

![スクリーンショット 2023-06-23 9.56.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2765288/39fd6205-ca88-bcce-ba30-2fc7023cdf71.png)

ポート番号も`8080`という番号が表示されています。

```http:/localhost:8080/lesson/sample 
Hello World
```
### もしもエラーでHTMLが表示されない場合

サーバーを停止してからもう一度起動し、ブラウザを更新してください
#### サーバーを停止するボタン
![スクリーンショット 2023-06-23 16.49.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2765288/c3a2322f-4e03-55ba-5af3-52efc7c9df49.png)

## HTMLで変数を使う

Controllerの中で設定された変数や、URLから受け取った引数をテンプレートで扱うにはModel属性に値を保存する必要があります（DBを操作するためのモデルとは異なります）

```java:Model属性を扱うための基本構文
// Model属性を利用するためのimportを追加します
import org.springframework.ui.Model;

/* 省略 */

// Model型の仮引数を持ちます
public String メソッド名(Model model) {
    // 指定した「属性名」をHTML内で変数のように扱います
    model.addAttribute("属性名", 値);
    /* 後続処理 */
}

```
Model型の仮引数の名前を`model`としていますが、仮引数は任意の名前を設定できます
しかし一般的に`model`とすることで可読性を高めることができます

```java:実際の使い方
@Controller
@RequestMapping("/lesson")
public class LessonController {

    @GetMapping("/sample")
    // Model型の値を必ず仮引数に持つ
    public String sample(Model model) {
        // 変数を定義する
        String text = "今日はいいお天気ですね";
        // messageという属性名に、今日はいいお天気ですね という値を追加します
        model.addAttribute("message", text);
        return "index";
    }
}
```
コントローラーの上部分で宣言するimport文はEclipseでコーディングすると、自動で補完されます
上書き保存する際にも自動で補完されるので、`Cmdキー`＋`sキー`で補完しましょう

## テンプレート（HTML）で変数を使う

Thymeleaf(タイムリーフ）ではth:から始まる属性が用意されており、phpのようなプログラム機能を実現することが出来ます。

コントローラーのmodel.addAttribute()によってセットされたModel属性を利用するには通常のHTMLタグの属性にth:text属性を付与します。

```html:th属性の使い方
<p th:text="${変数名}"></p>
```
```html:index.html
<!DOCTYPE html>
<!--HTMLファイルの中でThymeleafの特定の構文や属性を使用できるようになります。-->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Hello Spring Boot</title>
</head>
<body>
    <!-- Model属性に追加したmessageを出力します -->
    <h1 th:text="${message}">ご機嫌いかがですか？</h1>
</body>
</html>
```
http://localhost:8080/lesson/sample
```java:出力結果
いいお天気ですね
// th属性の値に上書きされる
```

## テンプレートファイルの置き場所

今作成したHTMLのテンプレートはページの数だけファイルが必要になります。
それらのテンプレートは全て`templatesディレクトリ`に保存することになります

そのためもしもファイル数が100を超える大規模なプロジェクトだった場合、ファイルの管理が困難になるため`templatesディレクトリ`の下層にさらに`ディレクトリ`を作成することができます。

```css:商品管理システム ディレクトリ構造の例
product-management-system/
├─ src/
│  ├─ main/
│  │  ├─ java/
│  │  │  ├─ com/
│  │  │  │  ├─ yourcompany/
│  │  │  │  │  ├─ productmanagementsystem/
│  │  │  │  │  │  ├─ controller/
│  │  │  │  │  │  │  ├─ ProductController.java
│  │  │  │  │  │  │  ├─ CategoryController.java
│  │  │  │  │  │  ├─ service/
│  │  │  │  │  │  │  ├─ ProductService.java
│  │  │  │  │  │  │  ├─ CategoryService.java
│  │  │  │  │  │  ├─ repository/
│  │  │  │  │  │  │  ├─ ProductRepository.java
│  │  │  │  │  │  │  ├─ CategoryRepository.java
│  │  │  │  │  │  ├─ model/
│  │  │  │  │  │  │  ├─ Product.java
│  │  │  │  │  │  │  ├─ Category.java
│  │  │  │  │  │  ├─ ProductManagementSystemApplication.java
│  │  ├─ resources/
│  │  │  ├─ templates/
│  │  │  │  ├─ product/
│  │  │  │  │  ├─ list.html
│  │  │  │  │  ├─ detail.html
│  │  │  │  ├─ category/
│  │  │  │  │  ├─ list.html
│  │  │  │  │  ├─ detail.html
│  │  │  ├─ application.properties
│  ├─ test/
│  │  ├─ java/
│  │  │  ├─ com/
│  │  │  │  ├─ yourcompany/
│  │  │  │  │  ├─ productmanagementsystem/
│  │  │  │  │  │  ├─ controller/
│  │  │  │  │  │  │  ├─ ProductControllerTest.java
│  │  │  │  │  │  │  ├─ CategoryControllerTest.java
│  │  │  │  │  │  ├─ service/
│  │  │  │  │  │  │  ├─ ProductServiceTest.java
│  │  │  │  │  │  │  ├─ CategoryServiceTest.java
├─ .gitignore
├─ pom.xml
├─ README.md

```

### ディレクトリを挟んでパスを指定する場合
```css:Controllerの例 
    return "ディレクトリ名/ファイル名";
```
```java:商品管理システムの参照をする場合
    @Controller
@RequestMapping("/item")
public class ItemController {
    @GetMapping("/product")
    public String list(Model model) {
        return "product/list"; // templates¥product¥list.html を指している
    }

    @GetMapping("/category")
    public String create(Model model) {
        return "category/list"; // templates¥category¥list.html を指している
    }
    
}

```
### 階層が複数ある場合

次のように階層が複数存在する場合は`/`で繋いで記述します

```css

return "list/detail/create/update/delete/file";

product/
├─ list/
│  ├─ detail/
│  │  ├─ create/
│  │  │  ├─ update/
│  │  │  │  ├─ delete/
```