目的
学習目的で使用したサイト。
英語サイトの為、理解に苦しみました。
日本語での手順を簡単にまとめるかつ、入力した内容を簡単にまとめる
後で振り返った時用
Spring bootってどういうものかJavaはどういうものか、開発していって流れを掴む目的
開発環境
- java version 21
- エディタ: IntelliJ IDEA Community版(30日間無料)
- https://www.jetbrains.com/ja-jp/idea/download/?section=mac
- (上記スクロールしてでてきます)
Spring boot
- Spring boot version: 3.4.1(近いものを使用)
- Gradle使用
- packaging: jar
Building a RESTful Web Service
「What You Will Build」セクション
「このチュートリアルを終えたときに、あなたはこういう動くものを作れるようになりますよ!」というゴールのイメージを伝えてくれる部分なので、この段階でコードを書く必要はない。
ここで述べられている内容は下記になります
今回作るものは、「こんにちは!」と言ってくれる小規模ウェブサービスです
アクセス先は
http://localhost:8080/greeting
返ってくるものは{"id":1,"content":"Hello, World!"}
http://localhost:8080/greeting?name=User名前付きでアクセスした場合返ってくるものは{"id":1,"content":"Hello, User!"}
「What You Need」〜「Starting with Spring Initializr」まで
この項目では、Spring Bootの開発環境を自分で最初から用意する方法を説明している部分です。
⚠️使用しているエディタ、パソコンは各々ことなるのでこちらのインストールするものなどはあくまで参考程度にして下さい
具体的に
- What You Need:プロジェクトを始めるために必要なもの(時間・ツール・Javaバージョンなど)を説明
- How to complete this guide:1から作ってもいいし、GitHubから完成コードをダウンロードして始めてもいいよ、という選択肢を提示
- Starting with Spring Initializr:Spring Initializr
https://start.spring.ioを使って、必要なライブラリや設定を選んでプロジェクトを自動生成する方法を説明
まずはIDEAのダウンロード
こちらも各々で異なってくると思いますが、あくまで私が行った環境構築?を掲載させていただきます。あくまで参考までに。
まずはこちらのサイトからエディタをDL(私が使用していたMacがIntelだったので「dmg.Intel」をダウンロードしました。Windouwは「.exe (Windows)」をダウンロードしました)
インストール時の設定について(Windows)
| 設定項目 | チェックするべき? | 理由 |
|---|---|---|
.java |
✅ はい | Javaファイルをダブルクリックで開けるようにする |
.gradle |
✅ はい | 今回Gradleを使うので |
.groovy |
◯ あってもいい | Gradleで内部的に使われることも |
.kt, .kts
|
❌ 不要 | Kotlinは今回使わない |
.pom |
❌ 不要 | Mavenは今回使わない |
| PATHの追加 | ◯ お好みで | コマンドラインから起動したいならチェック |
上記項目でインストールしたら「再起動」するようメッセージが表示されるので、後でもできますが再起動を行います。
初期化済みのプロジェクトをダウンロードする
次に「Spring Initializr から始める」項目から、初期化済みのプロジェクトをDLします
- リンク先に遷移
- Project:Gradle-Groovy
- Language:Java
- Spring Boot:3.4.7
- Java:21
- Packaging:Jar
- あとは既定のものでダウンロードを開始
DL完了後、解凍してIDEAで開きます
Create a Resource Representation Class(リソース表現クラスを作成)
サービスはGETのリクエストを処理する。
/greetingオプションでnameクエリ文字列にパラメータを指定できる。
リクエストは、挨拶を表すJSON形式のボディを含むレスポンスGETを返す。
出力は次のようになる。200OK
{
"id": 1,
"content": "Hello, World!"
}
挨拶表現をモデル化するには、リソース表現クラスの作成が必要。そのため、idとデータに対応するJavaレコードクラスを用意する。
contentsrc/main/java/com/example/restservice/Greeting.java
// パッケージ宣言。namespaceに似ている。
package com.example.restservice;
// この一行だけでHTTPレスポンスのJSON を返すためのデータ構造が自動生成される
public record Greeting(long id, String content) { }
Java14?以前のものだと下記のようなコードになる。
public class Greeting {
private long id;
private String content;
public Greeting(long id, String content) {
this.id = id;
this.content = content;
}
public long getId() { return id; }
public String getContent() { return content; }
}
Create a Resource Controller(リソースコントローラーを作成)
Springでは、Webサービスのリクエスト(アクセス)をコントローラーという部品が処理する。このコントローラーは、
@RestControllerという目印をつけて作る。
たとえば、GreetingControllerというクラスを作って、/greetingというURLにアクセスがあったときに、Greetingというデータを返すようにできている。
src/main/java/com/example/restservice/GreetingController.java)ファイルを作成して記述
package com.example.rest_service;
// import:他の場所にある機能をを使うよ宣言
// org.springflamework:Springフレームワークが提供するライブラリ
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.atomic.AtomicLong;
@RestController
public class GreetingController {
private static final String template = "Hello, %s!";
// AtmicLongというクラス(型)の変数counterを作り、new AtomicLong()で新インスタンス(オブジェクト)を作成
// このコントローラの中では、ずっと同じ AtomicLong を使い続けますよ。と言っている
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は、見た目はシンプルですが、裏ではいろいろなことが行われています。これを順番に見ていきます
@GetMapping("/greeting")
- これは、「ブラウザなどから /greeting にGETリクエストが来たら、このメソッドを使って処理する」という意味です。
- GETは、データを取得したいときによく使われるリクエストの種類です。
✅ 他にも @PostMapping(POST用)などもあります。全部をまとめたのが @RequestMapping というものです。
@RequestParam の役割
public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name)
- これは、URLに?name=〇〇と書かれていたら、その「〇〇」をnameという変数に入れます。
- もし「name」が指定されていなかったら、「World」という文字を使う、という意味です。
🔎 例:
/greeting?name=太郎 → name = "太郎"
/greeting → name = "World"
Greeting オブジェクトの生成
メソッドの中で、Greetingというクラスのインスタンス(=新しいオブジェクト)を作って返しています。たとえば:new Greeting(1, "Hello, 太郎!")
- idはカウンター(数字が1つずつ増える)で管理。
contentは、「Hello, [名前]」のようなメッセージ。
MVCとの違い(HTMLではなくJSON)
従来の「MVCコントローラー」は、サーバー側でHTMLを作って画面に表示します(いわゆるホームページを作る感じ)。
一方、このRESTコントローラーは、HTMLを返すのではなく、データ(JSON形式)を返します。
✅ JSONは、アプリやフロントエンドと連携しやすいデータ形式です。
@RestController の意味
@RestControllerは、@Controllerと@ResponseBodyのセットです。
これによって、メソッドの戻り値が自動的にHTTPのレスポンスとしてJSONで返されるようになります。
JSONへの変換は自動でやってくれる
Springには「メッセージコンバーター」という仕組みがあります。
Greetingオブジェクトは、自動でJSONに変換されてブラウザなどに返されます。
これは「Jackson」というライブラリのおかげで、特別なコードを書かなくても勝手にやってくれます。
✅import部分について
👆importしない例
✅@RestController
@Controllerと@Responsebodyの省略。
RestAPIのコントローラである事をSpringに伝える注釈(アノテーション)。
(つまり下に続くクラスがWebからのリクエストを受けて何かを返すためのRESTAPIのコントローラであることを宣言している)
戻り値はそのままJsonのHTTPレスポンスになる
✅@GetMapping("/greeting")
HTTPのGETメソッド、「/greeting」にアクセス(正確にはhttp://localhost:8080/greeting)があった時このメソッド(greeting)を動かすという意味
✅@RequestParam(...)
クエリパラメータから値を受け取る仕組み
例えば、http://localhost:8080/greeting?name=Alice というようなアクセスをした時、name = "Alice"という値がメソッドの中に渡される。defaultはWorld
✅AtomicLong counter と template
templateは挨拶文のひな形。%sは文字列を後から差し込むマーク。
例:String.format("Hello, %s!", "Alice") → "Hello, Alice!"
counterはアクセスのたびにIDを増やす為の変数。
AtomicLong はスレッド安全に数をカウントできる特別なクラス(AtomicLongは同時アクセスに強いカウンター。とも言える)
❓なぜ AtomicLong を使うのか?
Webサービスは複数のユーザーが同時にアクセスすることがあります。
そのとき普通の long を使うと 同時アクセスで番号がかぶってしまう可能性があります。
AtomicLong を使うと、複数のユーザーが同時に来ても順番にIDを発行してくれる。つまり
private final AtomicLong counter = new AtomicLong();
// これで呼び出すたびに、IDを安全に一ずつ増やすことができる
counter.incrementAndGet();
✅greeting()の中身について
Greeting というオブジェクト(record)を返している
※public record Greeting(long id, String content) { }👈 このデータ構造を返すよ、と言っている
counter.incrementAndGet() → IDの値を1つ増やす
String.format(template, name) → たとえば "Hello, Alice!" のようにあいさつ文を作る
💡※戻り値、型について例
public int sum() → 戻り値は int 型(整数)
public String message() → 戻り値は String 型(文字列)
public Greeting greeting() → 戻り値は Greeting 型(自分で作ったクラス
❓static,finalなどもやもや
元のコード
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
私が考えたコード
private String template = "Hello, %s!";
private AtomicLong counter = new AtomicLong();
↓
static:クラス全体で 1つだけ共通で使う 変数にしたいときに使う。つまり「共通の定数」だから static 。
では、なぜ template に static を付けるのか?
template は 誰がアクセスしても内容は常に同じで、つまり、毎回インスタンスを作ってもコピーするだけの無駄。
それならクラスで1個だけ用意して、みんなでそれを見るようにすれば効率的!
↓
final(変更できない)
final :一度だけ値を入れて、あとから変更できなくするという意味。
final String s = "Hello";
s = "Hi"; // ❌ エラーになります!
なぜ template に final を付けるの?
この "Hello, %s!" というテンプレート文字列は、変える必要がない決まった定数だから「絶対に誰も変更できないようにする」のが安全。つまり「変わらない値だから final が付いている」。
↓
counter に final が付いているのに static が付いていないのはなぜ?
↓
「GreetingControllerクラスの1つ1つのインスタンスごとに、自分のカウントを持っていていい」からです。
↓
static じゃない → オブジェクトごとに別の値を持てる
final → 初期化された AtomicLong オブジェクト自体は変更できない(ただし中の数字は変えられる)
↓私が書いたコードの問題点
・template部分:本当は変える必要がないのに、他のコードで誤って変更できてしまう
・AtomicLong部分:動くけど「この変数はもう再代入しませんよ」という意図が伝わりにくくなる
↓
finalについて:
staticについて:
全体のながれ
【1】再生ボタン(三角)を押す
↓
【2】RestServiceApplication の main() が呼ばれる
↓
【3】Spring Boot が起動する(@SpringBootApplication の力)
↓
【4】同じパッケージにあるクラスを自動でスキャン
└→ GreetingController が見つかる
↓
【5】組み込みのWebサーバー(Tomcatなど)が起動(http://localhost:8080 が開く)
↓
【6】ブラウザで http://localhost:8080/greeting にアクセス
↓
【7】GreetingController がそのリクエストを受け取る
└→ greeting() メソッドが動く
↓
【8】Greetingクラスのインスタンスを作って返す(JSON形式で)
→ 例:{"id":1, "content":"Hello, World!"}