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

#目的

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

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

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


[QuickstartGuideのおさらいはこちらから](https://qiita.com/morioheisei/items/59384f015e9e3801c4a7)
[Building a RESTful Web Service編のおさらいはこちらから](https://qiita.com/morioheisei/items/03106a823063677fe2f7)


#1.SpringBoot projectを始めよう！

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

1.ADD DEPENDENCIESボタンをクリックして、`Spring Web`を追加。
2.Artifact, Nameは、`consumingrest`に変更。
3.Javaを11に変更。

そして`GENERATE`ボタンをクリックしてZipファイルをダウンロードします。

![スクリーンショット 2020-07-02 14.08.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555244/30111453-a471-e7a1-b6e6-5610b87b1309.png)

ダウンロードしたZipファイルを展開したら準備完了です。

#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)

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

src/main/java/com/example/consumingrest/にQuote.javaファイルを作成します。

![スクリーンショット 2020-07-02 14.35.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555244/bbc0453a-afec-aca1-3894-b2133f763722.png)

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

```java:Quote.java
package com.example.consumingrest;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public class Quote {

  private String type;
  private Value value;

  public Quote() {
  }

  public String getType() {
    return type;
  }
  public void setType(String type) {
    this.type = type;
  }

  public Value getValue() {
    return value;
  }
  public void setValue(Value value) {
    this.value = value;
  }

  @Override
  public String toString() {
    return "Quote{" +
        "type='" + type + '\'' +
        ", value=" + value +
        '}';
  }
}
```

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

###①`@JsonIgnoreProperties`

JavaのオブジェクトをJSONに変換したり、JSONの文字列を受け取ってJavaオブジェクトに変換する際に、
複数のフィールドを変換対象外としてくれるアノテーションです。

`ignoreUnknown = true`と設定することで、未定義の（余計な）プロパティを変換しようとした時に例外が出るのを防いで、あくまでtypeとvalueだけを変換してくれるようになります。

###②変数の宣言

```java:
private String type;
private Value value;
```
string型のtypeとValue型のvalue変数を宣言しています。

アクセス修飾子は`private`ですので、**同一クラス内からしかアクセス出来ません**。

###③コンストラクタ、ゲッター/セッターメソッドの定義

```java:
// コンストラクタ
public Quote() {
}

// typeのゲッター/セッターメソッド
public String getType() {
  return type;
}
public void setType(String type) {
  this.type = type;
}

// valueのゲッター/セッターメソッド
public Value getValue() {
  return value;
}
public void setValue(Value value) {
  this.value = value;
}
```

引数なしのコンストラクタを定義しています。

type、valueの値を取得するゲッターメソッド、値をセットするセッターメソッドを定義しています。

###④`@Override`

```java:
@Override
public String toString() {
  return "Quote{" +
      "type='" + type + '\'' +
      ", value=" + value +
      '}';
}
```

`toStringメソッド`は、java.lang.Objectクラスで定義されている`文字列表現を返すメソッド`です。
`@Override`アノテーションは、`Objectクラスで定義されているtoStringメソッドをこのクラスでオーバーライドしています。`と明示するためのアノテーションです。

正しくオーバーライドされていなければエラーになります。
よって、`toStrign()`のようにタイプミスをしてしまっていると、コンパイル時にエラーが出て教えてくれます。

今回は、typeとvalueを分かりやすいように表示するための文字列を返すようにオーバーライドしています。


Quote.javaはこれで完成です。


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

src/main/java/com/example/consumingrest/にValue.javaファイルを作成します。

![スクリーンショット 2020-07-02 16.55.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555244/c239581c-f62b-3b3d-28f4-1600ce1d414d.png)

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

```java:Value.java
package com.example.consumingrest;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public class Value {

  private Long id;
  private String quote;

  public Value() {
  }

  public Long getId() {
    return this.id;
  }
  public String getQuote() {
    return this.quote;
  }

  public void setId(Long id) {
    this.id = id;
  }
  public void setQuote(String quote) {
    this.quote = quote;
  }

  @Override
  public String toString() {
    return "Value{" +
        "id=" + id +
        ", quote='" + quote + '\'' +
        '}';
  }
}
```

Value.javaはQuote.javaとほぼ同じですね。

##ConsumingrestApplication.javaを編集しよう！

デフォルトの状態は以下のようになっていると思います。

```java:ConsumingrestApplication.java
package com.example.consumingrest;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ConsumingrestApplication {

  public static void main(String[] args) {
    SpringApplication.run(ConsumingrestApplication.class, args);
  }

}
```

公式を参考にしつつコードを追加します。

```java:ConsumingrestApplication.java
package com.example.consumingrest;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

// 追加したコード
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class ConsumingrestApplication {

  // 追加したコード
  private static final Logger log = LoggerFactory.getLogger(ConsumingrestApplication.class);

  public static void main(String[] args) {
    SpringApplication.run(ConsumingrestApplication.class, args);
  }

  // 追加したコード
  @Bean
  public RestTemplate restTemplate(RestTemplateBuilder builder) {
    return builder.build();
  }

  // 追加したコード
  @Bean 
  public CommandLineRunner run(RestTemplate restTemplate) throws Exception {
    return args -> {
      Quote quote = restTemplate.getForObject(
        "https://gturnquist-quoters.cfapps.io/api/random", Quote.class);
      log.info(quote.toString());
  }

}
```

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

###①ログ出力のためのlog

```java:
private static final Logger log = LoggerFactory.getLogger(ConsumingrestApplication.class);
```

ターミナルでログを表示するためにLogger、LoggerFactoryを用いています。
`LoggerFactory.getLogger()`の引数にクラスを指定してログを取得することが出来ます。

###②RestTemplate

```java:
// 追加したコード
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
  return builder.build();
}
```

RestTemplateは、REST API(Web API)を呼び出すためのメソッドを提供するHTTPクライアントクラスです。
今回は、URLにGETリクエストを送り、送信先のレスポンスのコンテンツをQuote.classに格納するために用います。

`@Bean`というアノテーション、`RestTemplateBuilder`を用いて、DIコンテナに登録しています。
Bean登録するには、Springの色々な設定を Java コード上で行えるようにするためのアノテーションである
`@Configuration`を付与しなければいけませんが、`@SpringBootApplication`というアノテーションの中に含まれています。

###③CommandLineRunner

```java:
// 追加したコード
@Bean 
public CommandLineRunner run(RestTemplate restTemplate) throws Exception {
  return args -> {
    Quote quote = restTemplate.getForObject(
      "https://gturnquist-quoters.cfapps.io/api/random", Quote.class);
    log.info(quote.toString());
}
```

`CommandLineRunner`はrunというメソッドをもつ関数型インターフェースです。
よってここでは、runメソッドのオーバーライドをしています。

SpringBootがアプリ実行後に呼び出してくれます。

処理の流れとしては、
Quote型のquote変数に`restTemplate.getForObject()`の結果を代入しています。
第一引数にGETリクエストを送るURLを指定、第二引数に送信先のレスポンスのコンテンツを格納するクラスを指定しています。

その後、①で定義したlogのinfoメソッドを呼び出し、その中で更にQuoteクラスのtoStringメソッドを呼び出しています。

#3.実行してみよう！

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

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

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

しばらくすると、ターミナルに以下の文字が出てきます。

```terminal:ターミナル
Quote{type='success', value=Value{id=12, quote='@springboot with @springframework is pure productivity! Who said in #java one has to write double the code than in other langs? #newFavLib'}}
```

このidとquoteはランダムに表記されるので、アプリケーションを停止して再度ターミナルで実行コマンドを入力すると。

```terminal:ターミナル
Quote{type='success', value=Value{id=4, quote='Previous to Spring Boot, I remember XML hell, confusing set up, and many hours of frustration.'}}
```

先程とは違うidとquoteになっています。

#参考サイト

**[RestTemplate](https://docs.spring.io/spring/docs/5.1.8.RELEASE/javadoc-api/org/springframework/web/client/RestTemplate.html)**
**[CommandLineRunner](https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/CommandLineRunner.html)**
**[jacksonでデシリアライズする際に未知のプロパティを無視する](https://tm8r.hateblo.jp/entry/20130814/1376450418)**
**[DIについて理解する](https://qiita.com/takenakat/items/ec1128371b38e49e88fb)**
**[SpringのDIコンテナの動作イメージ(雰囲気)を掴もう](https://qiita.com/kazuki43zoo/items/7a0e96573e930ac934ed)**
**[Spring Bootで簡単なコマンドラインアプリケーションを作成してみる](https://reasonable-code.com/command-line-runner/)**