Spring Boot プロジェクト作成ワークショップ

このワークショップについて

やること

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

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

やらないこと

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

事前準備

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

プロジェクトの作成

  1. Spring Initializr にアクセス
  2. 以下のように設定して「Generate」をクリック
    • Project: Maven Project
    • Language: Java
    • Spring Boot: 4.0.0 (最新安定版)
    • Project Metadata
      • Group: dev.mikoto2000.workshop
      • Artifact: projectcreate
      • Name: projectcreate
      • Package name: dev.mikoto2000.workshop.projectcreate
      • Packaging: Jar
      • 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.properties
│   │       └── static
│   └── test
│       └── java
│           └── dev
│               └── mikoto2000
│                   └── workshop
│                       └── projectcreate
│                           └── ProjectcreateApplicationTests.java
├── .gitignore
├── mvnw
├── mvnw.cmd
├── pom.xml
└── README.md

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

  • src/main/java: Java ソースコードを配置するディレクトリ
  • src/main/resources: アプリケーションの設定ファイルや静的リソースを配置するディレクトリ
  • src/test/java: テストコードを配置するディレクトリ
  • pom.xml: Maven のプロジェクト設定ファイル。依存関係やビルド設定が記述されている
  • README.md: プロジェクトの説明や使用方法を記述するファイル
  • .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": 33 } (現在の年齢)

実装手順

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/service ディレクトリに CalcAgeService.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();
      }
    }
@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/controller ディレクトリに CalcAgeController.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.beans.factory.annotation.Autowired;
    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;
    
      @Autowired
      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)について
  • @Autowired アノテーションを使用して、Spring コンテナから CalcAgeService のインスタンスを自動的に注入
    • これを依存性注入(Dependency Injection, DI)と呼ぶ
  • これにより Spring が管理する Bean として CalcAgeService を利用できるようになる
  • CalcAgeService のインスタンスは、Spring が管理するため、コード内で直接インスタンス化する必要がない
  • また、DI により、テスト時にモックオブジェクトを注入することも容易になる

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

ステップアップ Tips
  • コンストラクタの @Autowired は省略可能
  • Lombok の @RequiredArgsConstructor と組み合わせるとさらにコードを簡潔にできる
    ...(snip)
    @RestController
    @RequestMapping("/api/calc-age")
    @RequiredArgsConstructor // private final フィールドにに代入するコンストラクタを自動生成
    public class CalcAgeController {
    
      private final CalcAgeService calcAgeService;
    
      @GetMapping("/calc-age")
      public CalcAgeResponse calculateAge(@RequestParam("birthDay") LocalDate birthDay) {
    ...(snip)

プロジェクトの実行

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

アプリケーションの設定

application.yaml の作成

  1. src/main/resources ディレクトリから application.properties を削除し、 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: WARN

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

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

プロファイルの切り替え

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

環境変数の利用

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":125}

プロファイルを指定して起動する場合は、以下のように --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 を作成する方法を学びました。 プロジェクトの作成からエンドポイントの実装、設定ファイルの管理、そしてアプリケーションのビルドとデプロイまでの一連の流れを理解できたと思います。 これらの基本的な知識を活用して、より複雑なアプリケーションの開発に挑戦してみてください。