spring boot で web api サーバを作る

# 概要

- spring boot で文字列を返すだけの web api を作ります

# 環境

- macOS Mojave 10.14.6
- Java openjdk 12.0.1
- Spring Boot 2.1.7
- Intellij IDEA CE 2019.1

# 手順

## spring initializr で雛形を作成

- spring initializr で spring boot の雛形を簡単に作ることができます

1. https://start.spring.io にアクセス
1. 以下のように選択
   ![spring-initializr.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425805/bad24731-1085-dfd8-93cd-b8ba40000655.png)
   - Project : Gradle Project
   - Language : Java
   - Spring Boot : 2.1.7
   - Project Metadata :
     - Group : ルートパッケージ名。今回は `com.example`
     - Artifact : プロジェクト名。今回は `api`
     - Options : ノータッチ
   - Dependencies : 依存するライブラリを `build.gradle` に追加できます  
     今回は以下を追加します
     - Spring Web Starter : web api に必要となる基本パッケージ
     - Lombok : java でよく使う便利機能が詰まったライブラリ  
       参考 : [lombok を触ってみた時のメモ](https://qiita.com/kuro227/items/3f017bc01a478d9cd139)
1. `Generate the Project` を選択し zip をダウンロードします
1. zip を解凍し、フォルダを適当な場所に配置します
   - フォルダ構成はこんな感じ

```
.
├── HELP.md
├── README.md
├── build.gradle
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── example
    │   │           └── api
    │   │               └── ApiApplication.java
    │   └── resources
    │       ├── application.properties
    │       ├── static
    │       └── templates
    └── test
        └── java
            └── com
                └── example
                    └── api
                        └── ApiApplicationTests.java
```

## Intellij IDEA の環境設定

- 先ほど作成した zip を Intellij IDEA で編集できるよう、IDE の設定を行います
  1. Intellij IDEA を起動後、 `import project` を選択し、先ほど解凍したフォルダを選択
  1. `Import project from external model` から `gradle` を選択
  1. `Use auto import` にチェックを入れる
  1. `Gradle JVM` が Java 12 になっていることを確認
  1. Finish を選択
  1. Preference -> Build, Execution, Deployment -> compiler -> annotation processor で  
     `Enable annotation processing` にチェックを入れて保存
  1. `command` + `;`でプロジェクト設定を開き、  
     `Project SDK`と`Project language level`でそれぞれ 12 を選択して保存

## `build.gradle`の確認

- `build.gradle`にプロジェクトの依存関係が定義されています

```groovy:build.gradle
plugins {
	id 'org.springframework.boot' version '2.1.7.RELEASE'
	id 'java'
}

apply plugin: 'io.spring.dependency-management'

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

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
```

- `plugins`, `apply plugin` : プラグインの設定
  - `java` : java ソースコードのコンパイルやユニットテストなどのタスクが実行できるようになる
  - `org.springframework.boot`: bootRun(アプリケーションの起動)などの spring boot のタスクが実行できるようになる
  - `io.spring.dependency-management` : gradle にはない maven の BOM 機能(依存するライブラリのバージョンを解決する機能)を提供してくれる
- `group`, `version` : プロジェクトの設定
- `souceCompatibility` : プロジェクトで使用する JDK のバージョン指定
  - 今回は Java 12 を使用するため`1.8`から`12`に変更しておく
- `repositories` : 依存するライブラリを取得するリポジトリの指定
- `dependencies` : 外部依存関係の定義。initializrで指定した`Spring Web Starter`がここに反映されている
  - `implementation` : コンパイル時と実行時に使われる
  - `testImplementation` : テストの際のコンパイル時、実行時に使われる

## アプリケーションの起動

- `ApiApplication` を右クリックし、実行します
- 以下のようなログが出力され、Spring boot が起動します

```
23:07:15: Executing task 'ApiApplication.main()'...

> Task :compileJava
> Task :processResources
> Task :classes

> Task :ApiApplication.main()

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

2019-08-06 23:07:32.447  INFO 20662 --- [           main] com.example.api.ApiApplication           : Starting ApiApplication on xxxnoMacBook-Air.local with PID 20662 (/Users/xxx/dev/spring-boot-api/build/classes/java/main started by xxx in /Users/xxx/dev/spring-boot-api)
2019-08-06 23:07:32.452  INFO 20662 --- [           main] com.example.api.ApiApplication           : No active profile set, falling back to default profiles: default
2019-08-06 23:07:35.060  INFO 20662 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2019-08-06 23:07:35.118  INFO 20662 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2019-08-06 23:07:35.119  INFO 20662 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.22]
2019-08-06 23:07:35.309  INFO 20662 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2019-08-06 23:07:35.309  INFO 20662 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 2746 ms
2019-08-06 23:07:35.680  INFO 20662 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2019-08-06 23:07:36.278  INFO 20662 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2019-08-06 23:07:36.292  INFO 20662 --- [           main] com.example.api.ApiApplication           : Started ApiApplication in 4.996 seconds (JVM running for 5.699)
```

- ブラウザで `http://localhost:8080` にアクセスし、以下の画面が表示されれば OK です
  <img width="755" alt="whitelabel-error.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425805/7dd5fdc9-e4d1-099a-578a-e546975afd86.png">

## Controller の作成

- `controller`というパッケージを作り、その配下に`HelloWorldController`というクラスを作成しました
  - `/hello`というパスで GET リクエストが来た場合に String で`hello world!`を返すようにしました
  - メソッド名は`getHello`としましたがなんでも良いです

```java:HelloWorldController
package com.example.api.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("hello")
public class HelloWorldController {

    @RequestMapping(method = RequestMethod.GET)
    public String getHello() {
        return "hello world!";
    }
}
```

### `@RestController`

- REST web api のエンドポイントとなる Controller クラスにつけるアノテーション
- 以下二つのアノテーションを付与したのと同一の効果
  - `@Controller` : MVC のコントローラクラスであることを表す
  - `@ResponseBody` : 付与したクラスのメソッドの戻り値がそのままレスポンスボディとなる

### `@RequestMapping()`

- REST web api にアクセスするためのパスを設定するアノテーション
- `method = RequestMethod.XXX (XXX : GET, POST, etc. )` のオプションで HTTP の各メソッドを割り当てられる

## アプリケーションの再起動

- アプリケーションを再起動し、ブラウザで`http://localhost:8080/hello`にアクセスします
- 白い画面に`hello world!`と表示されれば OK!  
![helloworld.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425805/8815a21d-9f86-5a76-984a-2705056412f7.png)