Spring Boot 入門 (2025年)

Yusuke Shinyama, May. 2025
概要: この記事では Java/Kotlin/Spring/TDD のいずれにもなじみがない読者のために Spring Boot + Kotlin + JPA を使ったアプリ開発の基礎を紹介する。

必要なもの: 簡単なWebアプリ制作経験。 IntelliJ IDEA Ultimate。

  1. はじめの準備
  2. IntelliJ IDEA の基本
  3. Spring Initializr による雛形アプリ生成
  4. 最初のTDD - TodoControllerの作成
  5. TodoRepositoryの作成
  6. うまく動かない場合は
  7. おわりに・参考資料

1. はじめの準備

  1. IntelliJ IDEA Ultimate をインストールしておく。
  2. Java SDK をダウンロード・インストールする。
今回作りたいもの:

Spring Boot + Kotlin を使った To Do (やること管理) アプリのバックエンド。 以下のAPIエンドポイントを提供する:

  1. POST /todos を実行すると、JSONで与えられた項目をデータベースに追加する。 このとき、新しく追加された項目の ID を返す。
    $ curl -H 'Content-Type: application/json' -d '{"text": "Hello!"}' http://localhost:8080/todos
    1
    
  2. GET /todos を実行すると、データベースにある項目すべてを JSON形式で返す。
    $ curl http://localhost:8080/todos
    [{"id":1, "text":"Hello!"}]
    
  3. GET /todos/ID を実行すると、与えられた IDをもつ項目ひとつをJSON形式で返す。
    $ curl http://localhost:8080/todos/1
    {"id":1, "text":"Hello!"}
    
  4. DELETE /todos/ID を実行すると、与えられた IDをもつ項目をデータベースから削除する。
    $ curl -X DELETE http://localhost:8080/todos/1
    $ curl http://localhost:8080/todos
    []
    
  5. 存在しないIDに対して GET をおこなうと、ステータスコードとして 404 (Not Found) を返す。
    $ curl -i http://localhost:8080/todos/999
    HTTP/1.1 404 
    Content-Length: 0
    Date: Tue, 20 May 2025 02:57:31 GMT
    
参考: HTTP レスポンスステータスコード

2. IntelliJ IDEA の基本

画面構成 (設定によっては異なる場合もある)

プロジェクト Gitブランチ ファイル一覧 Gitコミット テスト・実行 ビルド Docker ターミナル 問題 Git履歴 タスク 実行 Code With Me 検索 更新 通知 データベース ファイル一覧 編集画面

覚えたいショートカット

行頭・行末 Command ⌘ +
Command ⌘ +
1単語前・1単語後 Option ⌥ +
Option ⌥ +
文字選択 (1文字ごと) Shift +
Shift +
文字選択 (行頭・行末まで) Shift + Command ⌘ +
Shift + Command ⌘ +
文字選択 (単語ごと) Shift + Option ⌥ +
Shift + Option ⌥ +
文字選択 (範囲) Shift + クリック
単語選択 ダブルクリック
単語選択 (範囲) ダブルクリック + ドラッグ
行選択 トリプルクリック
行選択 (範囲) トリプルクリック + ドラッグ

3. Spring Initializr による雛形アプリ生成

  1. Spring Initializr を使って雛形アプリを生成し、ダウンロードする。
    ここでは以下のプラグインを利用している:
  2. 展開されたフォルダを IntelliJ IDEA で開く。
  3. index.html を新規作成する (staticフォルダで Command ⌘ + N):
    src/main/resources/static/index.html:
    <!DOCTYPE html>
    <html>
    <body>
    Welcome!
    </body>
    </html>
    
  4. IntelliJ の画面右上のメニューから todoApp [bootRun] を選択すると、アプリが起動する。
  5. http://localhost:8080/ にアクセスし、 "Welcome!" テキストが見えることを確認する。
    Javaの基本概念
    Java言語、classファイル、jarファイル
    Javaソースコード (xxx.java) をコンパイルすると、 classファイル (xxx.class) が生成される。 jarファイル (xxx.jar) は複数のclassファイルをまとめたもので、 JVM (Java Virtual Machine) と呼ばれる仮想マシンで実行する。
    Java ソースコード class ファイル jar ファイル
    Kotlin言語
    Javaを改良したもの。 Kotlinソースコード (xxx.kt) をclassファイルにコンパイルし、 Javaと同じく JVMで実行できる。
    Kotlin ソースコード class ファイル jar ファイル
    アノテーション (annotation)
    JavaおよびKotlinのコードには、アノテーションをつけることができる。 アノテーションはコメントに似ているが、コメントは人間が読むのに対し、 アノテーションはプログラムによって解析される。 Java/Kotlin では、クラスや関数 (メソッド)、変数に対してアノテーションをつけることができる。 Spring Boot では、アノテーションを多用している。
    @ClassAnnotation
    class MyClass {
      @MethodAnnotation
      fun foo() {
        @VariableAnnotation
        val x = 123
      }
    }
    

コマンドラインを使ったビルドと起動

IntelliJ を使わず、コマンドラインからアプリのビルド・起動をする場合は、 以下のようにする:

$ ./gradlew build  (アプリのビルドおよびテスト)
Starting a Gradle Daemon, 1 stopped Daemon could not be reused, use --status for details
...

BUILD SUCCESSFUL in 11s
8 actionable tasks: 8 executed

$ ./gradlew bootrun  (アプリの実行)
> Task :bootRun
  .   ____          _            __ _ _
 /∖∖ / ___'_ __ _ _(_)_ __  __ _ ∖ ∖ ∖ ∖
( ( )∖___ | '_ | '_| | '_ ∖/ _` | ∖ ∖ ∖ ∖
 ∖∖/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_∖__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.4.6)
...

4. 最初のテスト駆動開発 - TodoControllerの作成

GETエンドポイントの作成

  1. まず TodoAppApplicationTests.kt (最初から存在している) に、以下のように書く:
    src/test/kotlin/com/example/todoApp/TodoAppApplicationTests.kt
    package com.example.todoApp
    ...
    
    @SpringBootTest
    class TodoAppApplicationTests {
    
        @Test
        fun contextLoads() {
        }
    
    
    @Test fun `最初のテスト`() { assertThat(1+2, equalTo(3)) }
    }
    ぜひとも覚えたい IntelliJ IDEA の機能 その1

    コード中の赤色になっている部分Option + Return を押すと、 その問題を解決するための手段を提案してくれる。 たとえば上の例では「どのモジュールからインポートするか?」を訊かれるので

    • assertThat では org.hamcrest.MatcherAssert
    • equalTo では org.hamcrest.Matchers
    それぞれ選択する。

  2. TodoAppApplicationTests を以下のように変更する:
    src/test/kotlin/com/example/todoApp/TodoAppApplicationTests.kt
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    class TodoAppApplicationTests(
    
    @Autowired val restTemplate: TestRestTemplate, @LocalServerPort val port: Int
    ) { ...
    @Test fun `GETリクエストはOKステータスを返す`() { // localhost/todos に GETリクエストを発行する。 val response = restTemplate.getForEntity("http://localhost:$port/todos", String::class.java) // レスポンスのステータスコードは OK である。 assertThat(response.statusCode, equalTo(HttpStatus.OK)) }
    ...
    Spring における「依存注入 (DI)」の考え方 - その1

    Springでは @Autowired@LocalServerPort のようなアノテーションを書くことによって、 実行時に必要な値やオブジェクトをフレームワークが自動的に作成・注入してくれるようになっている。 この機能を「依存注入 (Dependency Injection, DI)」と呼ぶ。 Spring では、コントローラーやデータベース接続など、アプリの動作に関連するほとんどのオブジェクトは DI を使って作成させる (ビジネスロジックに関連するオブジェクトを除く)。

    Application Context TestRestTemplate LocalServerPort TodoAppApplicationTests 依存 注入 依存 注入
    TestRestTemplate と LocalServerPort を TodoAppApplicationTests に注入する
  3. 新しいファイル TodoController.kt を作成し、以下のように書く:
    src/main/kotlin/com/example/todoApp/TodoController.kt
    package com.example.todoApp
    ...
    
    @RestController
    class TodoController {
    
        @GetMapping("/todos")
        fun getTodos(): String {
            return "Hello"
        }
    
    }
    
    注意: ファイル先頭のパッケージ宣言を忘れるべからず

    Springのコードにおいては、ファイル先頭のパッケージ宣言

    package com.example.todoApp
    
    非常に重要である。 Springの依存注入は、同一パッケージ内のクラスをスキャンすることによって行うので、 パッケージ宣言を忘れると「あるはずのコンポーネントが見つからない」 「宣言したはずのメソッドが動作しない」という状況が発生する。

    Spring における「依存注入 (DI)」の考え方 - その2

    Springにおける @RestController@GetMapping のようなアノテーションは、 依存注入のもう一方の側面を表している。 ここまでのコードでは明示的に TodoController を作成するロジックは存在していない。 にもかかわらず、TodoController オブジェクトが作成され、動作しているように見える。

    ここでは、@RestController は、当該クラスが Spring Boot の DI候補として 利用可能であることを示す。さらに @GetMapping("/todos") は、当該メソッドが GET /todos リクエストに対するハンドラとして利用可能であることを示す。 この2つのアノテーションが存在することによって、 Spring Boot は getTodos() メソッドの周囲に HTTP リクエスト・レスポンスを処理する機構をくっつけ全体を Webサーバとして動作させる。 この仕組みを使って、数行で新しい Web API を作成することができる。

    Application Context GET /todos TodoController getTodos() リクエスト レスポンス
    依存注入を使った APIエンドポイントの作成

POSTエンドポイントの作成

  1. POSTリクエストで受け取る JSONの型を定義する。 これはデータ型の定義だけなので、テストを書く必要はない:
    src/main/kotlin/com/example/todoApp/TodoRequest.kt
    package com.example.todoApp
    
    data class TodoRequest(val text: String)
    
    Kotlin の data class とは?

    Kotlin における data class は、データの格納に使うクラスを定義するためのショートカットである。 通常であれば、以下のようなクラス定義を書く必要があるが、data class の定義は自動でこれらを追加してくれる。

    class TodoRequest {
        val text: String
    
        constructor(text: String) {
            this.text = text
        }
    
        getText(): String {
            return text
        }
        ...
    }
    

  2. テストを書く:
    src/test/kotlin/com/example/todoApp/TodoAppApplicationTests.kt
        @Test
        fun `POSTリクエストはOKステータスを返す`() {
            // localhost/todos に POSTリクエストを送る。このときのボディは {"text": "hello"}
            val request = TodoRequest("hello")
            val response = restTemplate.postForEntity("http://localhost:$port/todos", request, String::class.java)
            // レスポンスのステータスコードは OK であること。
            assertThat(response.statusCode, equalTo(HttpStatus.OK))
        }
    
    ぜひとも覚えたい IntelliJ IDEA の機能 その2

    Kotlinファイル内で Java言語のコードをペーストすると、 IntelliJ は自動的に Java → Kotlin に変換してくれる。 これはJavaのサンプルコードをKotlinで使いたいときに役に立つ。 たとえば、以下のJavaコードを上記のメソッド内にペーストしてみよう:

    TodoRequest request = new TodoRequest("hello");
    ResponseEntity<String> response = restTemplate.postForEntity("http://localhost:"+port+"/todos", request, String.class);
    
  3. 実装する。POSTリクエストを処理するためには @GetMapping ではなく @PostMapping を使う。 また、このとき引数の前に @RequestBody を使うと ボディとして受け取った JSON を TodoRequestオブジェクトに変換できる。
    src/main/kotlin/com/example/todoApp/TodoController.kt
        ...
        @PostMapping("/todos")
        fun postTodo(@RequestBody todoRequest: TodoRequest): String {
            return "gotcha"
        }
        ...
    

5. TodoRepositoryの作成

データベースを扱う準備

  1. まずデータベースが格納するオブジェクト (Entity) である TodoEntity クラスを作成する。 TodoEntity.kt ファイルを作成し、以下のように書く (これはテストを書く必要はない):
    src/main/kotlin/com/example/todoApp/TodoEntity.kt
    package com.example.todoApp
    
    import jakarta.persistence.Entity
    import jakarta.persistence.GeneratedValue
    import jakarta.persistence.Id
    
    @Entity
    class TodoEntity(
        @Id
        @GeneratedValue
        var id: Long? = null,
        var text: String,
    )
  2. つぎに TodoRepository.kt ファイルを作成し、以下のように書く。これにもテストは必要ない:
    src/main/kotlin/com/example/todoApp/TodoRepository.kt
    package com.example.todoApp
    
    import org.springframework.data.repository.CrudRepository
    import org.springframework.stereotype.Repository
    
    @Repository
    interface TodoRepository : CrudRepository<TodoEntity, Long>
    
    JPA とは?

    JPA (Java Persistence API) とは、Java/Kotlin 言語における ORM (オブジェクト関係マッピング) の共通の枠組みである。 JPA を使うと SQLを書かずに Java API を使ってオブジェクト ("エンティティ") をあたかも 直接データベースに保存 (save)、読み込み (find) するような処理を書くことができる。 Spring では、JPA は Hibernate ORM を使って実装されている。 @Entity@Repository などのアノテーションをつけることによって、指定した クラスを使った実装が自動的に生成される。

    アプリケーション JPA層 データベース save エンティティ find SQL
    JPA層の機能
    ぜひとも覚えたい IntelliJ IDEA の機能 その3

    コード中のクラス名・関数名・変数名などを Command ⌘ キーを押しながらクリックすると、 そのクラスや関数の定義箇所に移動する。

データの格納と読み出し

  1. テストを書く。 まず、アプリ起動直後にはデータベースが空であるはずなので「Todoには何も入っていない」というテストを書いてみる:
    src/test/kotlin/com/example/todoApp/TodoAppApplicationTests.kt
        @Test
        fun `GETリクエストは空のTodoリストを返す`() {
            // localhost/todos に GETリクエストを送り、レスポンスを TodoEntity の配列として解釈する。
            val response = restTemplate.getForEntity("http://localhost:$port/todos", Array<TodoEntity>::class.java)
            val todos = response.body!!
    
            // 配列は0個の要素をもつこと。
            assertThat(todos.size, equalTo(0))
        }
    
  2. 実装する。この段階ではまだ空のリストを返すだけでよいので、データベースを参照する必要はない。
    src/main/kotlin/com/example/todoApp/TodoController.kt
        ...
        @GetMapping("/todos")
        fun getTodos(): List<TodoEntity> {
            // 空のリストを返すだけ。
            return emptyList()
        }
        ...
    
    ぜひとも覚えたい IntelliJ IDEA の機能 その4

    IntelliJ では、(Javaではなく) Kotlin言語の独自機能で書かれている部分は emptyList() ではなく emptyList() のように斜体で表示される。

  3. 次のテストを書く。 ここで初めて「正しくデータベースに追加できているか」をテストすることにしよう。 そのためには、以下のようにする:
    1. POST /todos でなにか適当な Todoをひとつ追加する。
    2. GET /todos を実行し、得られた Todoリストに 新しい Todo項目が追加されているかどうかをチェックする。
    src/test/kotlin/com/example/todoApp/TodoAppApplicationTests.kt
        @Test
        fun `POSTリクエストはTodoオブジェクトを格納する`() {
            // localhost/todos に POSTリクエストを送る。このときのボディは {"text": "hello"}
            ...
    
            // localhost/todos に GETリクエストを送り、レスポンスを TodoEntity の配列として解釈する。
            // このときのレスポンスを todos として記憶。
            ...
    
            // 配列 todos の長さは 1。
            assertThat(todos.size, equalTo(1))
            // 配列 todos[0] には "hello" をもつTodoEntity が含まれている。
            assertThat(todos[0].text, equalTo("hello"))
        }
    
    ブラックボックス・テストの考え方

    テストするときは、基本的にテスト対象は「ブラックボックス」であると考える。 つまり、テスト対象の内部は未知であり、ふるまいを外からテストする唯一の手段は その入力を変化させ、その出力を観察することしかできない。 したがって、テストする場合には 「どういう入力→出力の変化を確認すれば、期待通りのふるまいであると確信できるのか?」 を考えることになる。

    入力 出力 テスト 対象
    ブラックボックス・テスト
  4. 実装する。まず TodoController に対して TodoRepository を注入させる:
    src/main/kotlin/com/example/todoApp/TodoController.kt
    @RestController
    class TodoController(
        @Autowired private val repository: TodoRepository
    ) {
        ...
    }
    

    つぎに getTodos(), postTodo() の両方を書き換えてテストが通るようにする:

    src/main/kotlin/com/example/todoApp/TodoController.kt
        ...
        @GetMapping("/todos")
        fun getTodos(): List<TodoEntity> {
            val todos = repository.findAll()
            return todos.toList()
        }
    
        @PostMapping("/todos")
        fun postTodo(@RequestBody todo: TodoRequest) {
            val entity = TodoEntity(text=todo.text)
            repository.save(entity)
        }
        ...
    
    なぜ依存注入が重要なのか?

    なぜ Spring が「依存注入」「IoCコンテナ」などという概念を使っているのかというと、 それはコードを変えずにシステムのふるまいを変更するためである。 たとえば、以下のようなコードを考えてみよう:

    name = "tododb"
    repository = H2TodoRepository(name)
    repository.save(entity)
    

    このコードでは、ふるまいは完全に固定されている。 データベース名を変更したり、H2 以外のデータベースを使うためには コードを変更する必要がある。しかしテストの際には できるだけコードを変えずに、本番コードそのものをテストしたい。 上のようなコードでは本番・テスト時にあわせてリポジトリを切り替えることができない。 そこで Spring を使ったプログラミングでは、コードの各部分を分解し、 フレームワークに「配管作業」を任せている。そしてこの接続を 切り替えられるようにしておくことで、システムの柔軟性を実現している。 この配管作業が依存注入に相当する。

    "tododb" H2TodoRepository(name) repository.save(entity) "tododb2" "otherdb" PostgreSQLTodoRepository(name)
    依存注入のイメージ (実線は有効な接続)

    Spring における依存注入や機能拡張は、基本的にアプリケーション ロジックの各箇所に Springのコードを挿入することによって行われる。 このために、Springではアプリのロジックを細かく分割して書く必要がある。

    アプリのロジック本体 Springが 挿入した部分 実行 実行
    Spring による機能拡張のイメージ

テストごとのデータのリセット

  1. 上のテストは単体で走らせると成功するが、TodoAppApplicationTests 全体を 走らせると失敗することがある。それはテスト時に、前のテストで格納したTodoEntityがデータベース中に残っている 場合があるためである ("テスト汚染")。このような事態を避けるために、テストごとにデータベースを空にする ロジックを書いておく。
    src/test/kotlin/com/example/todoApp/TodoAppApplicationTests.kt
        @BeforeEach
        fun setup() {
            // 各テストは項目が空の状態で始める。
            repository.deleteAll()
        }
    

    これですべてのテストがうまく動く状態になるはずである。

アプリを実際に走らせる

  1. ここまできたら、実際にアプリを走らせてリクエストを送り、データの格納・取得をおこなうことができるはずである。 まず準備として、application.properties に以下の一行を追加しておく。
    src/main/resources/application.properties
    spring.application.name=todoApp
    spring.h2.console.enabled=true
    
    つぎに todoApp を実行し、リクエストを送ってみよう:
    $ curl -H 'Content-Type: application/json' -d '{"text": "Hello!"}' http://localhost:8080/todos
    1
    $ curl -H 'Content-Type: application/json' -d '{"text": "Goodbye!"}' http://localhost:8080/todos
    2
    $ curl http://localhost:8080/todos
    [{"id":1, "text":"Hello!"}, {"id":2, "text":"Goodbye!"}]
    

    ここでH2データベースに接続して、実際にデータが格納されているかどうか確認する。 まず todoApp のログの中から以下のような行を探す:

    ...
    H2 console available at '/h2-console'. Database available at 'jdbc:h2:mem:f5f5a25c-05be-4b71-8b5e-248bf4365353'
    ...
    

    そして http://localhost:8080/h2-console にアクセスし、 "JDBC URL" の欄に上記の文字列を入力してデータベースに接続する。 ここで SQL クエリを発行すると格納された Todo 項目が確認できるはずである。

その他のテスト

  1. アプリを完成させるためには、さらにいくつかのテストを加える必要がある。 参考例は以下のとおり。
    src/test/kotlin/com/example/todoApp/TodoAppApplicationTests.kt
        @Test
        fun `POSTリクエストは新規作成した項目のIDを返す`() {
            // 項目を新規作成し、返されたIDを取得する。
            ...
    
            // TodoEntity の配列を取得する。
            ...
    
            // 配列中に返されたIDをもつ要素があること。
            ...
        }
    
        @Test
        fun `特定の項目をIDを指定してGETできる`() {
            // 項目を新規作成する。
            ...
            
            // localhost/todos/$id に GETリクエストを送り、レスポンスを1個の TodoEntity として解釈する。
            ...
    
            // 新規作成したものと内容が一致している。
            ...
        }
    
        @Test
        fun `存在しないIDでGETするとステータス404を返す`() {
            // id=999 を指定して GETリクエストを送る。
            ...
    
            // レスポンスのステータスコードは NOT_FOUND である。
            ...
        }
    
        @Test
        fun `DELETEでIDを指定して削除できる`() {
            // 項目を新規作成する。
            ...
    
            // localhost/todos/$id に DELETEリクエストを送る。
            ...
    
            // 再度GETすると、その項目は存在しない (削除されている)。
            ...
        }
    
    Spring 用語解説
    Bean と POJO
    Spring Bean は、Springによって作成・管理されるオブジェクト。 これに対してコード上で作成する (newする) オブジェクトは POJO (Plain Old Java Object) と呼ばれる。 一般に、アプリの動作に必要なオブジェクトには Bean を使い、ビジネスロジックで使うオブジェクトは POJO を使う。

    注意: "Java Bean" という用語もあるが、 これは特定の規則に従って作られた Javaオブジェクトのことをさし、 Spring Beanとは別物

    Spring IoC コンテナと Application Context
    Spring IoC (Inversion of Control) コンテナには、 Spring によって作成・管理される Bean が入っている。 Spring は必要に応じて Beanを作成し、依存注入をおこなう。 "Application Context" もほぼ同義。
    Application Context Bean Bean ...
    @Controller, @Repository, @Service, @Component など
    Spring Bean の候補となるクラスにつけられるアノテーション。 役割によって使い分ける。 Spring Boot では起動時にこれらのアノテーションが自動検出されるため、 何も設定もしなくても依存注入が可能になる。
    • @Controller (または @RestController) … Web APIのエンドポイントを提供する。
    • @Repository … データの保存・変更・削除等の機能を提供する。
    • @Service … ビジネスロジックに関連した機能を提供する。
    • @Component … 上記以外の目的で使われる。

6. うまく動かない場合は

コードがうまく動かない場合、以下の2つの方法で問題を特定する:

  1. ソースコード中で止めたい箇所にブレークポイントを設定し、デバッガで実行する。
  2. Spring Bootのログを調べる。 main あるいは test の application.properties に以下の行を追加して実行してみよう:
    application.properties
    ...
    spring.jpa.show-sql=true
    logging.level.org.springframework.web=DEBUG
    

Spring Bootのログの読み方

アプリの実行時にターミナルに現れる Spring Bootのログは、 何かイベントが発生するたびに記録される。 ログの各行は以下のような書式になっている。

  1. タイムスタンプ: そのイベントが発生した日時。(+09:00 は日本時間を表す)
  2. ログレベル: イベントの種類。(上のものほど深刻)
    1. ERROR … 何らかのエラーが発生し、処理を完了できなかった場合。
    2. INFO … エラーではないが、ユーザに有用と思われる情報。
    3. DEBUG … 通常のユーザには必要ない、開発者がデバッグ用に使う情報。
    4. TRACE … 実行過程を詳細にトレースする場合の情報。(使用注意)

    注意: 通常は DEBUGレベルまたはTRACEレベルのログは出力すべきでない (出力量が膨大なため)。

  3. プロセスID: アプリが実行されているUNIXプロセスID。
  4. スレッド名: イベントが発生した JVMスレッドの名前。
  5. モジュール名: イベントが発生した Javaモジュール名。長い名前は省略される。
    例:
  6. メッセージ: イベントの内容。

ログ出力例 (上記の設定を有効にした場合):

/Users/euske/Library/Java/JavaVirtualMachines/corretto-21.0.7/Contents/Home/bin/java ...

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.4.6)

2025-05-22T14:04:19.527+09:00  INFO 12389 --- [todoApp] [           main] c.example.todoApp.TodoAppApplicationKt   : Starting TodoAppApplicationKt using Java 21.0.7 with PID 12389 (/Users/euske/work/ws/spring-todoApp-2025/build/classes/kotlin/main started by euske in /Users/euske/work/ws/spring-todoApp-2025)
2025-05-22T14:04:19.528+09:00  INFO 12389 --- [todoApp] [           main] c.example.todoApp.TodoAppApplicationKt   : No active profile set, falling back to 1 default profile: "default"
2025-05-22T14:04:19.700+09:00  INFO 12389 --- [todoApp] [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2025-05-22T14:04:19.714+09:00  INFO 12389 --- [todoApp] [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 11 ms. Found 1 JPA repository interface.
2025-05-22T14:04:19.828+09:00  INFO 12389 --- [todoApp] [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 8080 (http)
2025-05-22T14:04:19.832+09:00  INFO 12389 --- [todoApp] [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2025-05-22T14:04:19.832+09:00  INFO 12389 --- [todoApp] [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.40]
2025-05-22T14:04:19.845+09:00  INFO 12389 --- [todoApp] [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2025-05-22T14:04:19.845+09:00  INFO 12389 --- [todoApp] [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 302 ms
2025-05-22T14:04:19.880+09:00  INFO 12389 --- [todoApp] [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2025-05-22T14:04:19.942+09:00  INFO 12389 --- [todoApp] [           main] com.zaxxer.hikari.pool.HikariPool        : HikariPool-1 - Added connection conn0: url=jdbc:h2:mem:f5f5a25c-05be-4b71-8b5e-248bf4365353 user=SA
2025-05-22T14:04:19.943+09:00  INFO 12389 --- [todoApp] [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2025-05-22T14:04:19.958+09:00  INFO 12389 --- [todoApp] [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
2025-05-22T14:04:19.973+09:00  INFO 12389 --- [todoApp] [           main] org.hibernate.Version                    : HHH000412: Hibernate ORM core version 6.6.13.Final
2025-05-22T14:04:19.982+09:00  INFO 12389 --- [todoApp] [           main] o.h.c.internal.RegionFactoryInitiator    : HHH000026: Second-level cache disabled
2025-05-22T14:04:20.058+09:00  INFO 12389 --- [todoApp] [           main] o.s.o.j.p.SpringPersistenceUnitInfo      : No LoadTimeWeaver setup: ignoring JPA class transformer
2025-05-22T14:04:20.080+09:00  INFO 12389 --- [todoApp] [           main] org.hibernate.orm.connections.pooling    : HHH10001005: Database info:
    Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-1)']
    Database driver: undefined/unknown
    Database version: 2.3.232
    Autocommit mode: undefined/unknown
    Isolation level: undefined/unknown
    Minimum pool size: undefined/unknown
    Maximum pool size: undefined/unknown
Hibernate: create global temporary table HTE_todo_entity(rn_ integer not null, id bigint, text varchar(255), primary key (rn_)) TRANSACTIONAL
2025-05-22T14:04:20.315+09:00  INFO 12389 --- [todoApp] [           main] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
Hibernate: drop table if exists todo_entity cascade 
Hibernate: drop sequence if exists todo_entity_seq
Hibernate: create sequence todo_entity_seq start with 1 increment by 50
Hibernate: create table todo_entity (id bigint not null, text varchar(255), primary key (id))
2025-05-22T14:04:20.323+09:00  INFO 12389 --- [todoApp] [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2025-05-22T14:04:20.410+09:00  WARN 12389 --- [todoApp] [           main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2025-05-22T14:04:20.417+09:00  INFO 12389 --- [todoApp] [           main] o.s.b.a.w.s.WelcomePageHandlerMapping    : Adding welcome page: class path resource [static/index.html]
2025-05-22T14:04:20.434+09:00 DEBUG 12389 --- [todoApp] [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : 6 mappings in 'requestMappingHandlerMapping'
2025-05-22T14:04:20.460+09:00 DEBUG 12389 --- [todoApp] [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Patterns [/webjars/**, /**] in 'resourceHandlerMapping'
2025-05-22T14:04:20.470+09:00 DEBUG 12389 --- [todoApp] [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : ControllerAdvice beans: 0 @ModelAttribute, 0 @InitBinder, 1 RequestBodyAdvice, 1 ResponseBodyAdvice
2025-05-22T14:04:20.483+09:00 DEBUG 12389 --- [todoApp] [           main] .m.m.a.ExceptionHandlerExceptionResolver : ControllerAdvice beans: 0 @ExceptionHandler, 1 ResponseBodyAdvice
2025-05-22T14:04:20.498+09:00  INFO 12389 --- [todoApp] [           main] o.s.b.a.h2.H2ConsoleAutoConfiguration    : H2 console available at '/h2-console'. Database available at 'jdbc:h2:mem:f5f5a25c-05be-4b71-8b5e-248bf4365353'
2025-05-22T14:04:20.523+09:00  INFO 12389 --- [todoApp] [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8080 (http) with context path '/'
2025-05-22T14:04:20.527+09:00  INFO 12389 --- [todoApp] [           main] c.example.todoApp.TodoAppApplicationKt   : Started TodoAppApplicationKt in 1.102 seconds (process running for 1.269)
2025-05-22T14:04:32.424+09:00  INFO 12389 --- [todoApp] [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2025-05-22T14:04:32.425+09:00  INFO 12389 --- [todoApp] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2025-05-22T14:04:32.425+09:00 DEBUG 12389 --- [todoApp] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Detected StandardServletMultipartResolver
2025-05-22T14:04:32.425+09:00 DEBUG 12389 --- [todoApp] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Detected AcceptHeaderLocaleResolver
2025-05-22T14:04:32.425+09:00 DEBUG 12389 --- [todoApp] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Detected FixedThemeResolver
2025-05-22T14:04:32.426+09:00 DEBUG 12389 --- [todoApp] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Detected org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator@31a80c88
2025-05-22T14:04:32.426+09:00 DEBUG 12389 --- [todoApp] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Detected org.springframework.web.servlet.support.SessionFlashMapManager@2dd4a7a9
2025-05-22T14:04:32.426+09:00 DEBUG 12389 --- [todoApp] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : enableLoggingRequestDetails='false': request parameters and headers will be masked to prevent unsafe logging of potentially sensitive data
2025-05-22T14:04:32.426+09:00  INFO 12389 --- [todoApp] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms
2025-05-22T14:04:32.429+09:00 DEBUG 12389 --- [todoApp] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : GET "/todos", parameters={}
2025-05-22T14:04:32.432+09:00 DEBUG 12389 --- [todoApp] [nio-8080-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to com.example.todoApp.TodoController#getTodos()
Hibernate: select te1_0.id,te1_0.text from todo_entity te1_0
2025-05-22T14:04:32.592+09:00 DEBUG 12389 --- [todoApp] [nio-8080-exec-1] m.m.a.RequestResponseBodyMethodProcessor : Using 'application/json', given [*/*] and supported [application/json, application/*+json]
2025-05-22T14:04:32.592+09:00 DEBUG 12389 --- [todoApp] [nio-8080-exec-1] m.m.a.RequestResponseBodyMethodProcessor : Writing [[]]
2025-05-22T14:04:32.597+09:00 DEBUG 12389 --- [todoApp] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed 200 OK

7. おわりに

Spring Boot の長所:

Spring Boot の短所:

今後の改良点

このチュートリアルは簡単のため、本来であれば推奨されるいくつかの作業をしていない。 この例を参考に本格的なアプリを作る場合は、以下の改良点を参考のこと:

参考資料

Spring Boot リファレンスマニュアル
RestTemplate
Spring Boot 各種クラス・メソッドのリファレンス文書。
Spring Bootでよく使うアノテーション一覧
Spring Boot でよく使うアノテーションまとめ。
とほほのKotlin入門
Kotlinの文法まとめ。
Hamcrestチュートリアル (英語)
テストで使う assertThat の書き方。
Spring Academy (英語)
Spring Boot を詳しく学びたい人向けのサイト。多数の動画・例題および実験用ラボが用意されている。

Yusuke Shinyama