Spring BootのWebアプリケーションの基本② 〜MVCモデルとEntityとlombok~

<a href="https://qiita.com/homes31285/items/1ade4d469cad6170062d">前回の記事</a>では、IntelliJの簡単な使い方やMVCモデルについて説明をしてきました。

今回からは実際にWebアプリケーションの開発をしていきます。

今回のファイル構成は、以下になります。
<details>
<summary>ファイル構成(クリックして展開)</summary>
<pre>
<code>
.
├── .gradle
├── .idea
├── build
├── gradle
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── example
    │   │           └── practice 
    │   │               └── PracticeApplication.java
    │   │               ├── web 
    │   │               │   ├── order
    │   │               │   │   └── OrderController.java
    │   │               │   └── indexController.java
    │   │               └── domain
    │   │                   └── order 
    │   │                       └── OrderEntity.java
    │   └── resources
    │       ├── static
    │       ├── templates
    │       │   ├── order
    │       │   └── list.html
    │       └── index.html
    │       └── application.properties
    └── test
.gitignore
build.gradle
gradlew.bat
HELP.md
settings.gradle
</code>
</pre>
</details>

では、今回はMVCモデルに従って、Webアプリケーションを作成していきたいと思います。

<h2>Modelの作成(Entity)</h2>
最初に作成するのは、Entityです。
<b>Entity</b>はデータベースのテーブル構造を表したオブジェクトを言います。


<b>Entity</b>データベース内の特定のテーブルに関するデータや振る舞いをオブジェクト指向のアプローチで捉え、プログラム内で扱いやすい形にすることを目的としています。

一方で、「Model」は、アプリケーション内のビジネスロジックやデータ処理を担当する部分を指します。MVCモデルでは、「Model」がデータの管理とビジネスロジックの実装を担当し、データベースの「Entity」もその一部として含まれます。

オブジェクトの説明をする前にクラスの説明をしたいと思います。

今回は、以下のようにOrderEntityのクラスを作成しますが、以下の状態では、実際の機能として動かすには、まだ実体を持っていないため、動かすことはできません。

クラスは、あくまで、実体を作るための設計図です。
クラスの中には、実体を持つであろうものの属性(フィールド)や機能(メソッド)が書かれています。
クラスでは、様々なフィールドやメソッドを持っており、それらをひとまとめにして、ひとつの型として捉えたものが<b>オブジェクト</b>です。

今回の例で言えば、下のコードのように記述する。

```Java:OrderEntity
package com.example.practice.domain.practice;

public class OrderEntity {
     //ここにフィールドやメソッドなどを記述する
}
```

<h3>フィールド</h3>

フィールドは、クラスの中でデータの値を保管するためものです。
フィールドを定義する場合は、次のように行います。


```Java:
class  クラス名 {
  データ型 フィールド名;
}
```

今回のOrderEntity.javaでは、以下のように記載します。

OrderEntityはドメインに属するクラスなので、domainの配下に作成します。

ちなみに、ドメイン層は、 アプリケーション層に提供する業務ロジックを実装するための階層です。

ドメイン層は、主に、データを保持するためのクラスであるEntityの実装とデータを操作するためのメソッドであるRepositoryの実装、業務ロジックを実行し、アプリケーション層に提供するServiceの実装の3つに分かれます。

```Java:src/main/java/com/example/practice/domain/OrderEntity.java

package com.example.practice.domain.order;

public class OrderEntity {
    /*
    フィールド(メンバ変数)
    */
    //注文番号
    private int orderId;
    //日付
    private String orderDate;
    //会社番号
    private int companyNo;
    //会社名
    private String companyName;
    //品物番号
    private int ItemNo;
    //品物
    private String Item;
    //数量
    private int quantity;
    //単価
    private int unitPrice;
    //金額
    private int price;
}
```

<h3>メソッド</h3>

次は、メソッドは、内容がまとまっている処理や反復する処理など、プログラムの処理を一つにまとめたものです。

次は、コンストラクタを設定していきます。

コンストラクタとは、クラスからオブジェクトを作成した際に、自動的に実行されるメソッドで、<b>クラス名と同名のメソッド名</b>にする必要があります。

以下は、自動的に実行されるメソッドで、orderIdの引数で渡された値をthis.orderIdに渡すようにしています。

```Java:src/main/java/com/example/practice/domain/OrderEntity.java
package com.example.practice.domain.order;
public class OrderEntity {
    /*
    フィールド(メンバ変数)
    */
    //注文番号
    private int orderId;
    /*
    同じコードのため、省略
    */
    //金額
    private int price;
    /*
    コンストラクタを定義する
    */
    public orderEntity(
            int orderId,
            String orderDate,
            int companyNo,
            String companyName,
            int itemNo,
            String item,
            int quantity,
            int unitPrice,
            int price
    ) {
        this.orderId = orderId;
        this.orderDate = orderDate;
        this.companyNo = companyNo;
        this.companyName = companyName;
        this.item = item;
        this.itemNo = itemNo;
        this.quantity = quantity;
        this.unitPrice = unitPrice;
        this.price = price;
    }
}
```

<h3>getterとsetterとは</h3>

次に、getterとsetterを設定する。

getterとは、setterでセットしたフィールドの値を取得して、returnで呼び出した元に値を返すメソッドのこと。

getterの基本的な書き方は以下の通りです。

```Java:
private String getSample() {
    return sample;
}
```

setterは呼び出し元のメソッドから値を引数で受け取り、引数の値をthisを使ってフィールドにセットしている。

```Java:
public void setSample(String sample) {
    this.sample = sample;
  }
```

以下がgetterとsetterの処理を追加したorderEntity.javaのコードになる。


```Java:src/main/java/com/example/practice/domain/OrderEntity.java
package com.example.practice.domain.order;

public class OrderEntity {
    /*
    フィールド(メンバ変数)
    */
    //注文番号
    private int orderId;
    //日付
    private String orderDate;
    //会社番号
    private int companyNo;
    //会社名
    private String companyName;
    //品物番号
    private int itemNo;
    //品物
    private String item;
    //数量
    private int quantity;
    //単価
    private int unitPrice;
    //金額
    private int price;
    /*
    コンストラクタを定義する
    */
    public OrderEntity(
            int orderId,
            String orderDate,
            int companyNo,
            String companyName,
            int itemNo,
            String item,
            int quantity,
            int unitPrice,
            int price
    ) {
        this.orderId = orderId;
        this.orderDate = orderDate;
        this.companyNo = companyNo;
        this.companyName = companyName;
        this.item = item;
        this.itemNo = itemNo;
        this.quantity = quantity;
        this.unitPrice = unitPrice;
        this.price = price;
    }
    /*
    getterとsetterを定義する
    */
    public int getOrderId() {
        return orderId;
    }

    public void setOrderId(int orderId) {
        this.orderId = orderId;
    }
    public String getOrderDate() {
        return orderDate;
    }

    public void setOrderId(String orderDate) {
        this.orderDate = orderDate;
    }
    public int getCompanyNo() {
        return companyNo;
    }

    public void setCompanyNo(int companyNo) {
        this.companyNo = companyNo;
    }
    public String getCompanyName() {
        return companyName;
    }

    public void setCompanyName(String companyName) {
        this.companyName = companyName;
    }
    public String getItem() {
        return item;
    }

    public void setItem(String item) {
        this.item = item;
    }
    public int getItemNo() {
        return itemNo;
    }

    public void setItem(int itemNo) {
        this.itemNo = itemNo;
    }
    public int getQuantity() {
        return quantity;
    }

    public void setQuantity(int quantity) {
        this.quantity = quantity;
    }
    public int getUnitPrice() {
        return unitPrice;
    }

    public void setUnitPrice(int unitPrice) {
        this.unitPrice = unitPrice;
    }
    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }
}
}
```

<h2>Viewの作成</h2>
Viewは、ウェブアプリケーションの外部からの入力や表示を行う部分です。
ここでは、Thymeleafというテンプレートエンジンを使用して、HTML内に動的なデータを埋め込むやり方で、list.htmlを作成します。

```html:src/resources/templates/order/list.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>注文リスト</title>
</head>
<body>
<h1>注文リスト</h1>
<table>
    <tr>
        <th>注文番号</th>
        <th>日付</th>
        <th>会社番号</th>
        <th>会社名</th>
        <th>品物番号</th>
        <th>品物</th>
        <th>数量</th>
        <th>単価</th>
        <th>金額</th>
    </tr>
    <!-- orderList の内容をループして表示 -->
    <tr th:each="order : ${orderList}">
        <td th:text="${order.orderId}"></td>
        <td th:text="${order.orderDate}"></td>
        <td th:text="${order.companyNo}"></td>
        <td th:text="${order.companyName}"></td>
        <td th:text="${order.itemNo}"></td>
        <td th:text="${order.item}"></td>
        <td th:text="${order.quantity}"></td>
        <td th:text="${order.unitPrice}"></td>
        <td th:text="${order.price}"></td>
    </tr>
</table>
</body>
</html>
```


th:text="${order.orderId}" の部分は、order という名前のオブジェクトから orderId フィールドの値を取り出し、その値をセル内に表示するためのコードです。同様に、他のフィールドも動的に埋め込まれます。

こうしたテンプレートの利用により、サーバー側で取得したデータを動的にHTMLに組み込むことができ、ユーザーに最終的な表示を提供することができます。

<h2>Controllerの作成</h2>

次に、OrderControllerを作っていきます。
ControllerはModelとViewのそれぞれの処理をアプリとして連携させるために、司令塔や橋渡し役という役割を担います。
ユーザーのリクエストを受け取り、適切なモデルを操作して結果をビューに渡します。

今回は、あらかじめ、モデルにデータをセットし、データがビューで表示されるようにしていきたいと思います。

以下のコードがモデルにデータをセットし、データがビューで表示されるコードです。

```Java:src/main/java/com/example/practice/web/order/OrderController.java

package com.example.practice.web.order;

import com.example.practice.domain.order.OrderEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.List;

@Controller
public class OrderController {

    // GETリクエストを受け取り、オーダーリストを作成し、ビューに渡すメソッド
    @GetMapping("/orders")
    public String showList(Model model) {
        // OrderEntityクラスのオブジェクトを作成し、リストに追加
        var orderList = List.of(
                new OrderEntity(1000, "20230801", 1000,
                        "株式会社あいうえお", 1000, "パソコン", 1, 100000,
                        100000),
                new OrderEntity(1001, "20230802", 1001,
                        "株式会社ABCD", 1001, "デスクトップ", 2, 60000,
                        120000)
        );

        // OrderListをThymeleafのビューで利用できるようにモデルに追加
        model.addAttribute("orderList", orderList);

        // "order/list"という名前のThymeleafビューを表示する
        return "order/list";
    }
}
```

Spring Bootアプリケーションのコントローラクラスで、GETリクエストが /orders エンドポイントに送信されると、showListメソッドが実行されます。

このメソッドでは、orderEntityクラスのオブジェクトを作成して、それをリストに追加します。そして、作成したリストをThymeleafのビューで利用できるように```model.addAttribute("orderList", orderList);```を使ってモデルに追加します。最後に```return "order/list"; ```によって、Thymeleafのテンプレートエンジンにより、名前が "orders/list" のビューが表示されます。このビューには、orderListの内容を動的に表示することができます。




その後に、「<a>http://localhost:8080/orders</a>」このURLをクリックすると、OrderControllerで登録した値が表示されます。

![スクリーンショット 2023-08-07 7.55.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782718/6397243a-858d-d535-ec09-5ec2b9552f05.png)

<h2>lombok</h2>
ここでは、コンストラクターやgetterとsetterのコードを自動生成する<a href="https://projectlombok.org/">Lombok</a>を紹介します。

build.gradleに以下を追加します。

```gradle:build.gradle
configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}
configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}
dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	compileOnly 'org.projectlombok:lombok'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
```

その次に、「IntelliJ IDEA」→Setting→pluginを押し、「Lombok」を追加する。

![スクリーンショット 2023-08-16 11.06.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782718/47a8bea9-bca9-4ffc-e042-5aa58f5aa41c.png)




OrderEntityは簡略化されるので、活用してみてくださいね。

```Java:src/main/java/com/example/practice/domain/OrderEntity.java
package com.example.practice.domain.order;

import lombok.AllArgsConstructor;
import lombok.Data;

@AllArgsConstructor
@Data
public class OrderEntity {
    /*
    フィールド(メンバ変数)
    */
    //注文番号
    private int orderId;
    //日付
    private String orderDate;
    //会社番号
    private int companyNo;
    //会社名
    private String companyName;
    //品物番号
    private int itemNo;
    //品物
    private String item;
    //数量
    private int quantity;
    //単価
    private int unitPrice;
    //金額
    private int price;
}
```

<h2>まとめ</h2>
この記事では、MVCモデルに従ったWebアプリケーションの開発手順を詳しく説明しました。最初にModelの作成を行い、Entityクラスを定義し、データベースのテーブル構造をオブジェクト指向で表現しました。クラス内には、属性やコンストラクタ、getterとsetterを記述し、オブジェクトの設計図としての役割を説明しました。

その後、Viewの作成を行い、Thymeleafテンプレートエンジンを用いてHTML内に動的なデータを埋め込む方法を示しました。コード例を通じて、orderListの内容をループして表示する方法や、データの動的な表示を実現する手法について説明しました。

また、Controllerの作成についても解説しました。ControllerはModelとViewを連携させる役割を果たし、ユーザーのリクエストを受け取り、適切なモデルを操作して結果をビューに渡すプロセスを説明しました。具体的には、GETリクエストを受け取り、orderEntityオブジェクトを作成し、それをリストに追加してビューに渡す手順を示しました。

さらに、Lombokという便利なライブラリを紹介し、コードを簡略化する方法を提案しました。Lombokを使用することで、コンストラクタやgetterとsetterのコードを自動生成し、効率的なプログラミングを実現できることを説明しました。

この記事を通じて、MVCモデルを活用したWebアプリケーションの開発手法や、Entityの設計、Thymeleafの利用方法、Controllerの役割、さらにはLombokの活用法について理解を深めることができたと思います。