Help us understand the problem. What is going on with this article?

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

目的

Spring Quickstart Guideを取り組み終えた方、SpringBootを学び始めた方、復習をしたい方に向けて、

公式が人気ガイドだからやってみて!と勧めてくれている、Building a RESTful Web Serviceを実際に取り組み学んだことを共有します。

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

前回のおさらいはこちらから

1.SpringBoot projectを始めよう!

まずは、spring initializrにアクセスします。

ADD DEPENDENCIESボタンをクリックします。
スクリーンショット_2020-06-29_13_14_12.png

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

スクリーンショット 2020-06-29 13.30.24.png

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

スクリーンショット_2020-07-01_14_56_49.png

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

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

スクリーンショット 2020-07-01 15.09.25.png

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

スクリーンショット 2020-07-01 15.10.29.png

準備完了です。

2.コードを追加しよう!

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

スクリーンショット 2020-06-30 10.08.25.png

Greeting.javaを作成しよう!

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

スクリーンショット 2020-07-01 15.30.40.png

Greeting.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ファイルに追加したコードを深掘りしていきます。

①定数の宣言

private final long id;
private final String content;

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

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

②コンストラクタの定義

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

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

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

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

GreetingController.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

@RestController
public class GreetingController {
}

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

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

②定数の宣言

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メソッドの定義

@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の部分を深掘りします。

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してください。

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

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

スクリーンショット 2020-07-02 11.33.39.png

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

スクリーンショット 2020-07-02 11.35.10.png

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

スクリーンショット 2020-07-02 11.35.31.png

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

参考サイト

SpringBoot入門ガイド
OracleのAtomicLong
アトミックであるとはどういうことか
マルチスレッド
Java並行処理の基本

morioheisei
ふざけた名前ですが常に本気です。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away