SpringBoot入門ガイドやってみた【Building a RESTful Web Service編】

#目的

[Spring Quickstart Guide](https://spring.io/quickstart)を取り組み終えた方、SpringBootを学び始めた方、復習をしたい方に向けて、

公式が人気ガイドだからやってみて！と勧めてくれている、[Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/)を実際に取り組み学んだことを共有します。

```text:開発環境
OS： macOS Mojave バージョン10.14.6
テキストエディタ： Visual Studio Code（以下VSCode）
Java: 11.0.2
```

[前回のおさらいはこちらから](https://qiita.com/morioheisei/items/59384f015e9e3801c4a7)


#1.SpringBoot projectを始めよう！

まずは、[spring initializr](https://start.spring.io/)にアクセスします。

**ADD DEPENDENCIES**ボタンをクリックします。
![スクリーンショット_2020-06-29_13_14_12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555244/2921a113-d5d0-cedf-deeb-83b23326975f.png)

`web`と入力して、`Spring Web`を選択します。

![スクリーンショット 2020-06-29 13.30.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555244/89d906ff-f347-6e4f-8c6d-737446ab0f30.png)


Artifact, Nameは、**restservice**に変更しました。
Javaのversionは11なので、11を選択します。

![スクリーンショット_2020-07-01_14_56_49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555244/c29cccba-7ed7-0d79-8fa1-b822fcb29e8a.png)



`GENERATE`ボタンをクリックします。

Zipファイルがダウンロードされるので、

![スクリーンショット 2020-07-01 15.09.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555244/e4ee15f0-1522-a8ea-735c-3ea2f45851a1.png)

そのZipファイルを展開してください。

![スクリーンショット 2020-07-01 15.10.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555244/d621b1fc-c605-d50c-7dcf-abbd2895f31c.png)

準備完了です。

#2.コードを追加しよう！

先ほどのフォルダをVSCodeで開きます。
拡張機能のJava Extension Packのインストールの推奨します。と言われるのでインストールしておきましょう。

![スクリーンショット 2020-06-30 10.08.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555244/80331ebc-b6e3-af7b-181a-3c8921288b00.png)

##Greeting.javaを作成しよう！

`src/main/java/com/example/restservice/`にGreeting.javaファイルを作成します。

![スクリーンショット 2020-07-01 15.30.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555244/ae74bb20-effd-17c5-c44d-4346c9fa94fd.png)

Greeting.javaファイル内にコードを追加していきます。

```java:Greeting.java完成形
package com.example.restservice;

public class Greeting {
  private final long id;
  private final String content;

  public Greeting(long id, String content) {
    this.id = id;
    this.content = content;
  }

  public long getId() {
    return id;
  }
  public String getContent() {
    return content;
  }
}
```

Greeting.javaファイルに追加したコードを深掘りしていきます。

###①定数の宣言

```java:
private final long id;
private final String content;
```

long型のid、string型のcontentという定数をそれぞれ宣言しています。

`アクセス修飾子はprivate`、そして、`final修飾子を用いている`ので、**同一クラス内からしかアクセス出来ない定数**となります。
定数なので、値の再代入は不可能となります。


###②コンストラクタの定義

```java
public Greeting(long id, String content) {
  this.id = id;
  this.content = content;
}
```

`インスタンス化された時に同時に行っておきたい処理`を記述しておきます。
今回は、インスタンス定数であるid、contentに初期値を代入しています。

###③ゲッターメソッドの定義

```java:
public long getId() {
  return id;
}
public String getContent() {
  return content;
}
```

id、contentの値を呼び出すためのメソッドです。

Greeting.javaはこれで完成です！


##GreetingController.javaを作成しよう！

`src/main/java/com/example/restservice/`にGreetingController.javaファイルを作成します。

![スクリーンショット 2020-07-01 16.36.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555244/65a8ea96-eb2a-309b-2fb5-72de2a529026.png)

GreetingController.javaファイル内にコードを追加していきます。

```java:GreetingController.java完成形
package com.example.restservice;

import java.util.concurrent.atomic.AtomicLong;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GreetingController {
  private static final String template = "Hello, %s!";
  private final AtomicLong counter = new AtomicLong();

  @GetMapping("/greeting")
  public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
    return new Greeting(counter.incrementAndGet(), String.format(template, name));
  }
}
```

GreetingController.javaファイルに追加したコードを深掘りしていきます。

###①@RestController

```java:
@RestController
public class GreetingController {
}
```

このアノテーションを記述する事により、SpringBootはControllerとして認識してくれます。Viewには遷移せずにメソッドの戻り値がそのままレスポンスのコンテンツとなります。

後述のgreetingメソッドはGreetingオブジェクトを戻り値にしていますが、SpringBootがJSONに自動変換してくれているのでJSONが画面に表示される事になります。



###②定数の宣言

```java:
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
```

string型のtemplate、long型のcounterという定数をそれぞれ宣言しています。

`アクセス修飾子はprivate`、そして、`final修飾子を用いている`ので、**同一クラス内からしかアクセス出来ない定数**となります。
定数なので、値の再代入は不可能となります。

**template**の方は、static修飾子を用いているので、クラスに対して1つしか存在しない定数となります。
そして`%s`は、String.formatというメソッドを使用する際に、第一引数に決められた書式を指定しなければいけないため、記載されています。

**counter**の方は、AtomicLongクラスを用いています。
なぜこのクラスを用いているのかは後ほど記述します。

###③greetingメソッドの定義

```java:
@GetMapping("/greeting")
public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
  return new Greeting(counter.incrementAndGet(), String.format(template, name));
}
```

`@GetMapping("/greeting")`は、URLで`〇〇/greeting`とアクセスされた時(GETリクエストがあった時)、greetingメソッドの処理が行われるためのアノテーションです。
http://localhost8080/greeting とアクセスがあった時にgreetingメソッドが呼ばれるという事です。

greetingメソッドの引数の`@RequestParam`は、URLのクエリパラメータを受け取る事が出来ます。
**String name**にどのような値を格納するのかを指定しており、

http://localhost8080/greeting とアクセスがあった場合は、`nameにはWorldが格納され`、
http://localhost8080/greeting?name=tanaka とアクセスがあった場合は、`nameにはtanakaが格納されます`。

最後にreturnの部分を深掘りします。

```java:
return new Greeting(counter.incrementAndGet(), String.format(template, name));
```

http://localhost8080/greeting とアクセスされる毎にGreetingクラスをインスタンス化したJavaオブジェクトを返しています。
new Greetingのコンストラクタの第一引数に`counter.incrementAndGet()`、第二引数に `String.format(template, name)`を渡しています。

Greetingクラスのインスタンス化、counterのインクリメント、書式を指定して文字列を返す、と複数処理を同時に行っています。


インクリメントは`counter++;`と記述も出来ますが、複数の処理が実行された場合に正しく処理されない場合があるため、

上述のAtomicLongクラスでcounterを定義して、同クラスのメソッドである`incrementAndGet()`を使用し、現在の値(counter)をインクリメントして、インクリメントした値を返しています。

アトミックは不可分操作と言われており、加算が終わるまで他の処理の割り込みをさせないためにAtomicLongクラスを用いてcounterを定義した、と解釈しました。

#3.実行してみよう！

アプリケーション実行の準備が出来たので確認しましょう。

ターミナルで以下のコマンドを入力してEnterしてください。

```terminal:ターミナル
$ ./mvnw spring-boot:run
```

2秒ぐらい待った後、http://localhost:8080/greeting にアクセスすると、

![スクリーンショット 2020-07-02 11.33.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555244/bd91fa6c-9825-2248-1ac6-d5b6cefdce67.png)

次に、http://localhost:8080/greeting?name=tanaka でアクセスすると、

![スクリーンショット 2020-07-02 11.35.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555244/8d8b6e23-fd21-e3f0-13b2-e65abda15da9.png)

次に、http://localhost:8080/greeting?name=suzuki でアクセスすると、

![スクリーンショット 2020-07-02 11.35.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555244/cbae67ff-9038-f782-6d9f-9abb7a751457.png)

アクセスする毎にidが増えていき、`/greeting?name=任意の文字列`でアクセスすると入力した値が表示されていますね！

#参考サイト

**[SpringBoot入門ガイド](https://spring.io/guides/gs/rest-service/)**
**[OracleのAtomicLong](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/atomic/AtomicLong.html)**
**[アトミックであるとはどういうことか](https://kumikomiya.com/what-does-it-mean-to-be-atomic/)**
**[マルチスレッド](https://relearn-java.com/multithread/#i-14)**
**[Java並行処理の基本](https://qiita.com/stk_odoroki/items/bddaeec8775406c63258#%E3%82%A2%E3%83%88%E3%83%9F%E3%83%83%E3%82%AF%E6%80%A7)**