ゼロから始めるSpring Boot　その３

##目標
複数回に分けて実施予定です。
<font color="tomato">**また、以降の記事ではエスケープのため、各項目の@を全角にしています。（コード内は半角なのでご安心ください）**</font>
（今まで`@`とすることでエスケープさせていましたが、見づらい気がしたので...）

1. SpringBootとは何かをざっくり知る
1. 環境構築＆Hello World!を表示させる
1. パラメータやオブジェクトの受け渡しをする
1. **他の機能にも触れてみる**<font color="red">　←今回やること</font>

他の機能・・・ちょっとフワっとしてますね。改めて具体的に書きます。

##目標（他の機能について）

1. [ ] 　**DBを操作してみよう（JPA編）**<font color="red">　←今回やること</font>
2. [ ] 　DBを操作してみよう（MySQL編）
3. [ ] 　バリデーション（入力チェック）を導入しよう
4. [ ] 　プロパティファイルを読み込もう
5. [ ] 　actuatorに触れてみよう（おまけ）
6. [ ] 　自作のタグプレフィックスを作ろう（おまけ）

#DBを操作してみよう（JPA編）
プロジェクトは前回のものを使いまわします。
作り直してもいいのですが、`プロジェクトの作成後にmavenの依存関係を追加する`という工程を入れたいと思ったためです。

####依存関係の追加
今回はDB操作ということで**<font color="RoyalBlue">H2database</font>**と**<font color="RoyalBlue">Spring Data JPA</font>**を追加します。

- **<font color="RoyalBlue">H2database</font>**<br>
javaのメモリ上で展開することのできるデータベースです。これにより`SQL Server`や`MySQL`といったソフトウェアを用意することなく、サクッとデータベースの機能を使うことができます。
- **<font color="RoyalBlue">Spring Data JPA</font>**<br>
javaで`O/Rマッピング`を行うための機能です。ただ、`JPA(Java Persistence API)`はこの機能の概念であり、実装は`Hibernate`と呼ばれるライブラリが担っています。
<details>
<summary>O/Rマッピングって？</summary><div>
正式名称は`Object-Relational Mapping`で、プログラミング言語とデータベースを繋ぐ仕組みのことです。これを利用することで、直感的に書いたソースコードでSQLの操作が可能になります。javaの場合だと`JPA`のほかに`Mybatis`等のフレームワークがあります。
</div>
</details>

依存関係を後から追加する方法を幾つか紹介します。
１以外は見なくても特に影響ありません。

---

<details>
<summary>**１．pom.xmlにコピペ**</summary>
<div>pom.xmlに以下のコードをコピペします。

```xml:pom.xml
<dependency>
	<groupId>com.h2database</groupId>
	<artifactId>h2</artifactId>
	<scope>runtime</scope>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
```
終わり！これが一番手っ取り早いかもしれませんね。
こういったテンプレートコードはググったり、Mavenのセントラルリポジトリから持ってきます。
・[Maven リポジトリ検索](https://search.maven.org/)

<details>
<summary>しれっと出てきた\<scope>って何？</summary><div>
依存関係を追加するタイミングを指定するオプションになります。
自分も`runtime`と`test`ぐらいしか知らないので、全て載っているサイトを引用させてもらいます。
>
|名称|機能|
|:-:|:-:|
|compile|scope の指定を省略した場合のデフォルト値です。全ての状況でクラスパスに追加されます。|
|provided|ライブラリが JDK やコンテナによって提供される場合に指定します。コンパイル時のみクラスパスに追加されます。|
|runtime|実行時のみに必要な場合に指定します。テストの実行および通常の実行のときにクラスパスに追加されます。|
|test|テストのときのみ必要な場合に指定します。テストのコンパイルと実行のときにクラスパスに追加されます。|
|system|明示的にクラスパスに追加する場合に指定します。このスコープのライブラリは常に有効であるとみなされ、リポジトリの検索は行われません。|
引用元：[TECHSCORE　依存性の指定とスコープ]
(https://www.techscore.com/tech/Java/ApacheJakarta/Maven/3/#maven-3-1-1)
</div></details>
</div></details>

---

<details>
<summary>**２．Mavenの機能で追加**</summary>
<div>プロジェクト上、もしくはpom.xml上で`右クリック＞Maven＞依存関係の追加`の順にクリック。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624514/a8a7fc04-14ff-6c41-ab7c-a7657b40cc2f.png" width="70%">

グループId＝`com.h2database`
アーティファクトId＝`h2`
スコープ＝`runtime`※
を指定してOKをクリック。
※ スコープって何？については**１．pom.xmlにコピペ**を参照してください。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624514/66c89f66-104e-7b7e-de22-43bf62af4af7.png" width="60%">
もう一回この画面を開いて
グループId＝`org.springframework.boot`
アーティファクトId＝`spring-boot-starter-data-jpa`
スコープ＝`compile`（おそらくデフォルトで選択済み）
を指定してOKをクリック。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624514/59877e59-fb72-435b-7061-c2bb7a00be47.png" width="60%">
終わり！ぶっちゃけ`<dependency>`とかのタグを自動で記述してくれるぐらいのメリットしかありません。
</div>
</details>

---

<details>
<summary>**３．Mavenの機能で追加（検索利用）**</summary>
<div><font color="tomato">**この方法は上手くいかない場合、数分～数十分かかる可能性があります。**</font>そのためあまりお勧めはしません。

プロジェクト上、もしくはpom.xml上で`右クリック＞Maven＞依存関係の追加`の順にクリック。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624514/a8a7fc04-14ff-6c41-ab7c-a7657b40cc2f.png" width="70%">
グループID、アーティファクトID、または・・・に`h2d`を入力
検索結果に表示された`com.h2database`を選択※1
スコープは`runtime`を選択※2
最後にOKをクリックすると追加されます。
※1 [**何も表示されない場合はこちら**](#何も表示されない場合)
※2 スコープって何？については**１．pom.xmlにコピペ**を参照してください。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624514/aa0dadc3-7681-2386-e589-5691e110f5ce.png" width="60%">
もう一度画面を開いて、
グループID、アーティファクトID、または・・・に`data-jpa`を入力
検索結果に表示された`spring-boot-data-jpa`を選択
スコープは`complie`のまま（デフォルトで選択状態のはず）
最後にOKをクリックすると追加されます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624514/47cd011b-6aeb-204b-766a-7f33604bd74d.png" width="60%">
終わり！
**２．Mavenの機能で追加**にないメリットとしては`アーティファクトIDをフルで覚える必要がない`ぐらいです。
また、出来た方は下の`何も表示されない場合`は飛ばしてください。
######何も表示されない場合
原因は色々あるので特定するのは難しいです。
`検索欄に3文字以上入力しないと表示されない`のは仕様っぽいですが、以下の画像のように:warning:`インデックスのダウンロードが・・・`と出ているとたまに機能しなくなります。この場合、今から説明する方法で半数の人は直るかと思います。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624514/6d224e59-ef1f-fe12-3ec9-d1e6fc4ea95b.png" width="60%">
`ウィンドウ＞設定＞Maven`の順にクリック。
`起動時にリポジトリー・インデックス更新をダウンロード`をチェックして`適用して閉じる`をクリック。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624514/e4b66b63-a3a4-173f-ba11-9fc8018f0ae7.png" width="70%">
`ファイル＞再開`の順にクリックしてSTSを再起動します（普通に×閉じ再起動でも大丈夫です）。そのあと、STSの右下に`インデックスの更新中`が表示されていればOKです。（完了には数分～数十分かかります）
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624514/8537f2c5-ce76-f89c-2a81-019e5d6fc349.png" width="70%">
これが完了すると検索できるようになるかもしれません。</div>
</details>

---

pom.xmlに追加した依存関係がプロジェクトに取り込めていない時もあるのでプロジェクトを更新します。`Maven＞プロジェクトの更新`の順にクリック。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624514/1cbc8878-9cf9-6f2c-870b-9aba651ec578.png" width="75%">
プロジェクト`demo`にチェックし、OKをクリック。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624514/109f27f7-1323-3a9b-e6cf-0efecae18297.png" width="75%">
更新完了です！

---

####テーブル用クラスの作成
依存関係の追加が終わったら、まず初めにテーブル用クラスを作成しましょう。
`com.example.demo`内に`UserEntity`を作成し、以下のコードを書きます。

```java:UserEntity.java
package com.example.demo;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="user")
public class UserEntity {
	@Id
	@Column
	@GeneratedValue(strategy = GenerationType.AUTO)
	private int id;
	@Column
	private String name;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}
```
アノテーション祭りですね。順に解説します。

- **<font color="RoyalBlue">＠Entity</font>**<br>
記述したクラスをエンティティクラス（DBの機能を持ったクラス）として認識させます。
- **<font color="RoyalBlue">＠Table</font>**<br>
`name` : テーブル名を設定します。
- **<font color="RoyalBlue">＠Id</font>**<br>
記述したプロパティを主キー（レコードを一意に特定するためのカラム）として認識させます。
- **<font color="RoyalBlue">＠Column</font>**<br>
記述したプロパティをカラムとして認識させます。<br>
`name` : カラム名を設定します。<br>
`length` : カラム長を設定します。<br>
`nullable` : NULLを許容するか設定します。<br>

```java:記述例
@Column(name="name",length=10,nullable=false)
private String name;
```
- **<font color="RoyalBlue">＠GeneratedValue</font>**<br>
`strategy` : 主キーの採番方法を指定します。`GenerationType.AUTO`の場合、利用するDBに合わせて最適な自動採番（オブジェクトが生成されるごとに1,2,3...と増えていく）が行われるようになります。

####リポジトリの作成
続いて`UserRepository`という名前でインターフェースを作成し、以下のコードを追加してください。

```java:UserRepository.java
package com.example.demo;

import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<UserEntity, Long> {
	public UserEntity findById(int id);
}
```
- **<font color="RoyalBlue">JpaRepository</font>**<br>
[依存関係の追加](#依存関係の追加)で触れたJPAの機能を使うために記述します。総称型となっており、`<使用するエンティティクラス, Long>`を指定します。
- **<font color="RoyalBlue">JpaRepository#findById</font>**<br>
SQL文の代わりを果たすメソッドになります。`本来インターフェースは実装（継承した具象クラスを作ること）しなければ意味がありません`が、このように`命名規則に従ってメソッド名や引数を定義してあげると、JpaRepositoryがそれに応じた機能を自動で作成`してくれます。<br>

要はこんなことをやってくれるわけです。
![名称未設定ファイル (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624514/e7158535-9eae-8d4b-26ae-7c5a05d79a29.png)

他にも沢山の命名規則があるので、気になった方は公式ドキュメントも読んでみてください。
・[Spring公式ドキュメント 6.3.2.クエリ作成](https://spring.pleiades.io/spring-data/jpa/docs/current/reference/html/#jpa.repositories)

####コントローラの作成
既に作成してある`DemoController.java`を以下のように書き換えます。

```java:DemoController.java
package com.example.demo;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class DemoController {
	
	@Autowired
	private UserRepository repository;
	
	@PostConstruct
	@Transactional
	public void init() {
		UserEntity entity = new UserEntity();
		entity.setName("hatopo");
		repository.saveAndFlush(entity);
	}
	
	// このメソッドは特に変更なし
	@RequestMapping(value="/",method=RequestMethod.GET)
	public ModelAndView index() {
		ModelAndView mav=new ModelAndView();
		mav.setViewName("/index");
		return mav;
	}
	
	@GetMapping("/hello")
	public ModelAndView hello(@RequestParam int id,ModelAndView mav) {
		UserEntity entity = repository.findById(id);
		mav.addObject("name",entity.getName());
		mav.setViewName("/hello");
		return mav;
	}
}
```

- **<font color="RoyalBlue">＠Autowired</font>**<br>
これをオブジェクトに付けると、Springが自動でオブジェクトの生成をしてくれるようになります。`DI（依存性注入）を行ってくれる`とも言います。
<details>
<summary>DI（依存性注入）とは？</summary><div>
一言でいうと`依存性を注入すること`です。<br>
**<font color="RoyalBlue">依存</font>**・・・Aクラスが内部でBクラスを利用している時、`AはBに依存している`といいます。<br>
**<font color="RoyalBlue">注入</font>**・・・`外部から与える`という意味です。
すなわち、`クラス内で利用する予定の別クラスを外部から渡してあげること`です。
</div></details>
- **<font color="RoyalBlue">＠PostConstruct</font>**<br>
これを付けたメソッドは、SpringBootの起動直後に一度だけ呼び出されるようになります。
- **<font color="RoyalBlue">＠PreDestroy（今回は使用しません）</font>**<br>
PostConstructと対になっているので紹介。こちらはSpringBootの終了直前に一度だけ呼び出されるようになります。
- **<font color="RoyalBlue">＠Transactional</font>**<br>
これを付けたメソッドもしくはクラスは、トランザクション処理（エラーが発生したら巻き戻せる機能）を行えるようになります。<br>
`readOnly` : DBを読み取り専用にするか指定します。デフォルトはfalseです。<br>
`timeout` : タイムアウトの時間を秒数指定できます。<br>
`rollbackFor` : デフォルトの巻き戻し対象であるRuntimeExceptionやSQLException以外のエラーも対象にしたい場合に記述します。

```java:記述例
@Transactional(readOnly=true,timeout=100,rollbackFor=IllegalArgumentException.class)
```
- **<font color="RoyalBlue">＠JpaRepository#saveAndFlush</font>**<br>
引数のオブジェクトをメモリ上のDBに反映させます。

####ビューの作成

`index.html`と`hello.html`の\<body>内も書き換えます。

```html:index.html
<body>
<form action="/hello" method="get">
IDを入力してください<input type="text" name="id"><br>
<input type="submit" value="送信">
</form>
</body>
```

```html:hello.html
<body>
<span th:text="${name}"></span>さん、おはようございます！
</body>
```

####実行

それでは`http://localhost:8080`にアクセスします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624514/ed12d6f8-ee95-11af-67dc-d0b0b86e9b36.png" width="70%">

入力欄に`1`を入れて次へ進むと・・・
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624514/cd6ed2a8-7b1d-24b6-69cc-3cfeeff6aa42.png" width="70%">
メモリ上に展開したDBからid検索を行い、一致したレコードのname（`hatopo`）を表示することができました！

今回、特に入力チェックなどは書いていないため、文字列を入れたり存在しないIDを入れたりするとエラーになるのでご了承ください。

#おさらい
- H2databaseを使ってメモリ上でDBを展開
- JPAを使ってjavaのコードでSQLを操作
- ＠Entity、＠Tableでエンティティの定義
- ＠Id、＠Column、＠GeneratedValeでカラムの定義

次回はMySQLを操作していきましょう。お疲れさまでした。