Spring Boot プロジェクト作成ハンズオン

このハンズオンについて

やること

JSON を返却するミニマムな API を例に、プロジェクト構成・作り方について説明します。

  • プロジェクトの作り方(Spring Initializr)
  • シンプルな API の実装
    • DI について
    • bean について
    • Controller -> Service と呼び出す API 構成
  • application.yaml の機能いろいろ
    • プロファイル
    • 環境変数読み込み
  • jar デプロイ

やらないこと

  • 認証(Spring Security)
  • DB アクセス

事前準備

  • JDK 21 以上がインストールされていること
  • curl コマンドが使えること

プロジェクトの作成

  1. Spring Initializr にアクセス
  2. 次のように設定して「Generate」をクリック
    • Project: Maven
    • Language: Java
    • Spring Boot: 4.0.2 (最新安定版)
    • Project Metadata
      • Group: dev.mikoto2000.workshop
      • Artifact: projectcreate
      • Name: projectcreate
      • Package name: dev.mikoto2000.workshop.projectcreate
      • Packaging: Jar
      • Configuration: YAML
      • Java: 21
    • Dependencies:
      • Spring Web
      • Spring Boot DevTools
      • Lombok
  3. ダウンロードした zip ファイルを解凍

各依存関係の説明

  • Spring Web: Web アプリケーションを作成するための基本的な機能を提供。RESTful API の作成に必要なライブラリが含まれる
  • Spring Boot DevTools: 開発効率を向上させるためのツール。コード変更時の自動再起動やライブリロード機能を提供
  • Lombok: ボイラープレートコード(getter/setter、コンストラクタなど)を自動生成するためのライブラリ。コードの可読性と保守性を向上させる

プロジェクトの構成

プロジェクトのディレクトリ構成は次のようになります。

projectcreate
├── src
│   ├── main
│   │   ├── java
│   │   │   └── dev
│   │   │       └── mikoto2000
│   │   │           └── workshop
│   │   │               └── projectcreate
│   │   │                   └── ProjectcreateApplication.java
│   │   └── resources
│   │       ├── application.yaml
│   │       └── static
│   └── test
│       └── java
│           └── dev
│               └── mikoto2000
│                   └── workshop
│                       └── projectcreate
│                           └── ProjectcreateApplicationTests.java
├── .gitignore
├── mvnw
├── mvnw.cmd
└── pom.xml

各ファイル・ディレクトリの説明

  • src/main/java: Java ソースコードを配置するディレクトリ
  • src/main/resources: アプリケーションの設定ファイルや静的リソースを配置するディレクトリ
  • src/test/java: テストコードを配置するディレクトリ
  • pom.xml: Maven のプロジェクト設定ファイル。依存関係やビルド設定が記述されている
  • .gitignore: Git で管理しないファイルやディレクトリを指定するファイル
  • mvnw / mvnw.cmd: Maven Wrapper スクリプト。Maven がインストールされていない環境でもプロジェクトをビルドできるようにする

エンドポイントを作る

設計

  • エンドポイント: /api/calc-age?birthDay=1990-01-01
  • HTTP メソッド: GET
  • クエリパラメータ: birthDay (ISO 8601 形式の生年月日、例: 1990-01-01)
  • レスポンス形式: JSON
  • レスポンス内容: { "age": 36 } (現在の年齢)

実装手順

1. DTO の作成

  1. src/main/java/dev/mikoto2000/workshop/projectcreate/calcage/dto ディレクトリに CalcAgeResponse.java ファイルを作成
  2. 次のコードを CalcAgeResponse.java に追加
    package dev.mikoto2000.workshop.projectcreate.calcage.dto;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @AllArgsConstructor
    @Data
    @NoArgsConstructor
    public class CalcAgeResponse {
      private int age;
    }

2. Service クラスの作成

  1. src/main/java/dev/mikoto2000/workshop/projectcreate/calcage/serviceCalcAgeService.java を作成
  2. 次のコードを CalcAgeService.java に追加
    package dev.mikoto2000.workshop.projectcreate.calcage.service;
    
    import org.springframework.stereotype.Service;
    import java.time.LocalDate;
    import java.time.Period;
    
    /**
     * 年齢計算サービスクラス
     */
    @Service
    public class CalcAgeService {
    
      /**
       * 指定された生年月日から現在の年齢を計算します。
       *
       * @param birthDate 生年月日
       * @return 年齢
       * @throws IllegalArgumentException 無効な生年月日が指定された場合
       */
      public int calculateAge(LocalDate birthDate) {
        LocalDate currentDate = LocalDate.now();
        if (birthDate == null || birthDate.isAfter(currentDate)) {
          throw new IllegalArgumentException("Invalid birth date");
        }
        return Period.between(birthDate, currentDate).getYears();
      }
    }
Note

LocalDate.now() を直書きするのは本来 NG ですが、今回はシンプルな例を示す目的でこのようにしています。 実際には、テスト時に任意の日時を指定できる工夫が必須です。 (詳細は「Spring Boot テスト入門」参照。)

@Service とは
  • @Service アノテーションは、Spring Framework においてサービス層のクラスを示すために使用される
  • サービス層は、ビジネスロジックを実装する場所であり、コントローラー層とデータアクセス層の間の仲介役
  • @Service アノテーションを付与することで、依存性注入(DI)によって他のクラスから利用できるようにする
    • (依存性注入(DI)によって他のクラスから利用できるクラス = Bean)
Bean とは
  • Spring コンテナによって管理されるオブジェクトのこと
  • @Service アノテーションを使用することで、CalcAgeService クラスが Spring の Bean として登録される
  • これにより、他のクラスから CalcAgeService を注入して利用できるようになる
  • Spring はアプリケーションの起動時に Bean をスキャンし、必要に応じてインスタンスを生成・管理する
  • @Controller@Repository@Component などのアノテーションも同様に Bean を定義する(Spring にインスタンスを管理してもらう)ために使用される

3. コントローラークラスの作成

  1. src/main/java/dev/mikoto2000/workshop/projectcreate/calcage/controllerCalcAgeController.java を作成
  2. 次のコードを CalcAgeController.java に追加
    package dev.mikoto2000.workshop.projectcreate.calcage.controller;
    
    import dev.mikoto2000.workshop.projectcreate.calcage.dto.CalcAgeResponse;
    import dev.mikoto2000.workshop.projectcreate.calcage.service.CalcAgeService;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.time.LocalDate;
    import java.time.format.DateTimeParseException;
    
    @RestController
    @RequestMapping("/api/calc-age")
    public class CalcAgeController {
    
      private final CalcAgeService calcAgeService;
    
      public CalcAgeController(CalcAgeService calcAgeService) {
        this.calcAgeService = calcAgeService;
      }
    
      @GetMapping
      public CalcAgeResponse calculateAge(@RequestParam("birthDay") LocalDate birthDay) {
        int age = calcAgeService.calculateAge(birthDay);
        return new CalcAgeResponse(age);
      }
    }
@RestController とは
  • @RestController アノテーションは、Spring Framework において RESTful Web サービスのコントローラークラスを示すために使用される
  • クライアントからの HTTP リクエストを受け取り、適切なサービスメソッドを呼び出してレスポンスを生成する役割を果たす
DI(Dependency Injection)について
  • CalcAgeController は、 @RestController アノテーションにより、Spring によって管理されるコントローラークラスとして登録される
  • コンストラクタの仮引数と同型の CalcAgeService@Service アノテーションがついている
  • そのため、Spring コンテナから CalcAgeService のインスタンスが自動的に注入される
    • これを依存性注入(Dependency Injection, DI)と呼ぶ
  • コンストラクタがひとつだけの場合、 @Autowired アノテーションを省略できる
  • これにより Spring が管理する Bean として CalcAgeService を利用できるようになる
  • CalcAgeService のインスタンスは、Spring が管理するため、コード内で直接インスタンス化する必要がない
  • また、DI により、テスト時にモックオブジェクトを注入することも容易になる

Spring が管理する Bean 工場からインスタンスを貰い受けて利用するイメージです。

プロジェクトの実行

  1. ターミナルを開き、プロジェクトのルートディレクトリに移動
  2. 次のコマンドを実行してアプリケーションを起動
    ./mvnw spring-boot:run
  3. ブラウザまたは curl コマンドでエンドポイントにアクセス
    curl "http://localhost:8080/api/calc-age?birthDay=1990-01-01"
    => {"age":36}

アプリケーションの設定

これからアプリケーションの設定を進めます。 次の挙動ができるように設定ファイルを記述します。

  • 待ち受けポートはデフォルト 8080, 環境変数があればその値で上書き
  • ローカル環境ではログレベル DEBUG
  • プロダクション環境ではログレベル INFO

application.yaml の作成

  1. src/main/resources/application.yaml ファイルを開く
  2. application.yaml を次のコードに置き換え
    server:
      port: ${CREATEPROJECT_SERVER_PORT:8080}
    spring:
      profiles:
        active: local
        group:
          local:
            - local-logging
          prod:
            - prod-logging
  3. 次のコードを application-local-logging.yaml に追加
    logging:
      level:
         root: DEBUG
  4. 次のコードを application-prod-logging.yaml に追加
    logging:
      level:
         root: INFO

これにより、 src/main/resources ディレクトリの構成は次のようになります。

src
 └── main
     └── resources
         ├── application.yaml
         ├── application-local-logging.yaml
         └── application-prod-logging.yaml

プロファイルの切り替えについて

プロファイルが active: local と設定されているため、デフォルトではアプリケーション起動時に application-local-logging.yaml が適用される。 起動時に、例えば prod プロファイルを指定すると、 application-prod-logging.yaml の設定が適用され、ログレベルが INFO に設定される。

実際に切り替える方法は、次の章の動作確認で説明します。

環境変数の利用

application.yamlserver.port${CREATEPROJECT_SERVER_PORT:8080} と設定されているため、環境変数 CREATEPROJECT_SERVER_PORT が設定されていればその値がポート番号として使用され、設定されていなければデフォルトで 8080 が使用される。

アプリケーション設定のまとめ

このように、Spring Boot では application.yaml を使用してアプリケーションの設定を柔軟に管理できる。 プロファイルを活用することで、開発環境と本番環境で異なる設定を簡単に切り替えることができる。 また、環境変数を利用することで、デプロイ先の環境に応じた設定を動的に変更することが可能となる。

DB やクラウドのエンドポイントなど、環境ごとに異なる設定が必要な場合に特に有用です。

例えば、次のように環境依存の要素ごとにファイルを分けることもできる。

src
 └── main
     └── resources
         ├── application.yaml
         ├── application-local-logging.yaml
         ├── application-prod-logging.yaml
         ├── application-local-db.yaml
         └── application-prod-db.yaml

アプリケーションのビルドとデプロイ

  1. ターミナルを開き、プロジェクトのルートディレクトリに移動
  2. 次のコマンドを実行してアプリケーションをビルド
    ./mvnw clean package
  3. ビルドが成功すると、 target ディレクトリに projectcreate-0.0.1-SNAPSHOT.jar ファイルが生成される
  4. 次のコマンドを実行してアプリケーションを起動(デフォルトプロファイル(local))
    java -jar target/projectcreate-0.0.1-SNAPSHOT.jar
  5. ブラウザまたは curl コマンドでエンドポイントにアクセス
    curl "http://localhost:8080/api/calc-age?birthDay=1990-01-01"
    => {"age":36}

プロファイルを指定して起動する場合は、次のように --spring.profiles.active オプションを使用する。

java -jar target/projectcreate-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod

これにより、 prod プロファイルが有効になり、 application-prod-logging.yaml の設定が適用される。

local で起動した場合と、 prod で起動した場合で、ログレベルが異なることを確認できる。

まとめ

このハンズオンでは、Spring Boot を使用してシンプルな JSON API を作成する方法を学びました。 プロジェクトの作成からエンドポイントの実装、設定ファイルの管理、そしてアプリケーションのビルドとデプロイまでの一連の流れを理解できたはずです。 これらの基本的な知識を活用して、より複雑なアプリケーションの開発に挑戦してみてください。

参考資料