1. test 1
  2. test 2
  3. test 3
  4. test 4
コース一覧
Spring Boot入門
リポジトリという抽象

Spring Boot入門

Java で Web API サーバーを作るための Spring Boot の入門コースです。DI コンテナ、REST コントローラ、リクエスト検証、レイヤ分割、Spring Data JPA、例外ハンドリング、テストまでを扱います。毎レッスン、Spring が裏側でやっている判断そのものを pure Java の関数として自分で書き、フレームワークが何を肩代わりしてくれているのかを手触りで理解できる構成にしました。約 12 時間 (1 日 30 分 × 24 日) で 48 レッスンを修了できます。

1
Spring Bootとは何か
01. Spring Bootで何が作れるのか10分
02. サーブレットからフレームワークへ15分
03. ルーティング表という発想15分
04. プロジェクトの構成10分
05. 起動のしくみと自動設定15分
06. パスのマッチング15分
2
DIコンテナ
01. newで書くと何が困るのか15分
02. コンストラクタインジェクション15分
03. インターフェースへの依存15分
04. @Componentと@Bean15分
05. 自作のDIコンテナ20分
06. Beanのスコープとライフサイクル15分
3
RESTコントローラ
01. RESTという設計方針15分
02. @RestControllerの役割15分
03. @GetMappingとパス変数15分
04. クエリパラメータの受け取り15分
05. @PostMappingとリクエストボディ15分
06. ステータスコードの選び方15分
07. ResponseEntityで組み立てる15分
4
リクエストとレスポンスの変換
01. JSONとオブジェクトの往復15分
02. DTOとエンティティを分ける15分
03. recordでDTOを書く15分
04. 入力検証の基本15分
05. 検証エラーをまとめて返す15分
06. アノテーションによる検証15分
5
レイヤ構成とビジネスロジック
01. 3層アーキテクチャ10分
02. @Serviceに置くもの15分
03. 状態遷移をルールにする15分
04. 料金計算のような業務ロジック15分
05. @Transactionalとは何か15分
06. トランザクションの巻き戻し15分
6
データアクセス
01. @Entityとテーブルの対応15分
02. リポジトリという抽象15分
03. メソッド名からクエリを作る20分
04. 検索条件の組み立て15分
05. ページングと並び替え15分
06. N+1問題15分
7
例外処理と横断的関心事
01. 例外をHTTPに変換する15分
02. @ExceptionHandlerと@ControllerAdvice15分
03. エラーレスポンスの形を決める15分
04. フィルタとインターセプタ15分
05. ログとリクエストの追跡15分
06. 設定値の外部化15分
8
テストと仕上げ
01. テストの種類と使い分け15分
02. Serviceの単体テスト15分
03. モックで依存を差し替える15分
04. MockMvcでエンドポイントを試す15分
05. 本番へ出すための次の一歩10分

リポジトリという抽象

このレッスンでは、実装クラスを1行も書かずに保存と検索ができる Spring Data JPA のリポジトリの仕組みを説明できるようになります。

インターフェースを1つ書くだけです

Spring Data JPA でデータアクセスを用意するときに書くのは、次の3行だけです。

Java

public interface UserRepository extends JpaRepository<User, Long> { }

implements UserRepository と書いたクラスはどこにもありません。それでも userRepository.save(user) が動きます。起動時に Spring が、このインターフェースを実装したクラスを動的に生成し、DI コンテナへ登録しているからです。開発者から見ると「契約だけ宣言すれば、実装は用意される」という形になります。

型引数の2つは、扱うエンティティの型と、その主キーの型です。JpaRepository<User, Long> なら User を扱い、主キーは Long です。この2つが決まれば、後述する基本操作のシグネチャがすべて決まります。

継承するだけで手に入る操作

JpaRepository を継承すると、少なくとも次の操作がそのまま使えます。

メソッド戻り値役割
save(entity)保存されたエンティティ新規なら INSERT、既存なら UPDATE
findById(id)Optional<T>主キーで1件取得。無ければ空
findAll()List<T>全件取得
deleteById(id)なし主キーで1件削除
count()long件数
existsById(id)boolean存在確認

注目すべきは findById の戻り値です。User ではなく Optional<User> を返します。「見つからないかもしれない」という事実が型に現れているので、呼び出す側は必ずその場合を考えることになります。

Java

User user = userRepository.findById(1L) .orElseThrow(() -> new NoSuchElementException("user not found"));

save が新規と更新を兼ねている点も特徴です。渡されたエンティティの主キーが未設定なら新規として INSERT し、値が入っていて既に存在するなら UPDATE になります。呼び出し側は同じメソッドを呼ぶだけで済みます。

リポジトリは「保管庫」という考え方です

リポジトリという言葉はもともと、データの置き場所をコレクションのように扱う設計の呼び名です。save して findById で取り出す、という操作は、Map に put して get するのとほとんど同じ形をしています。SQL やコネクションの話は保管庫の中に閉じ込められ、外からは「入れる」「取り出す」だけが見えます。

この抽象が効いてくるのは差し替えのときです。テストでは本物のデータベースの代わりに、Map を使った軽い実装を差し込めます。同じインターフェースを実装している限り、呼び出す側のコードは1文字も変わりません。前の章で学んだ「インターフェースに依存する」という方針が、そのまま形になっています。

Java

public class InMemoryUserRepository implements UserRepository { private final Map<Long, User> store = new HashMap<>(); // save と findById を Map の操作で実装する }

演習で書くもの

演習では、Spring が生成してくれるリポジトリの中身を自分で書きます。Map を保管庫にした疑似リポジトリをインターフェースと実装クラスの組で用意し、save してから findById した結果を返します。Spring では extends JpaRepository の1行で済むところを、ここでは保管庫が実際にやっている「主キーをキーにして入れる、キーで引く」という操作として書き下します。見つからなかったときにどう返すか、という Optional に相当する扱いも自分で決めます。

要件

  1. UserRepository インターフェースに save と findById を宣言し、InMemoryUserRepository が Map で実装すること
  2. run は保管庫を1つ作り、save してから findById した結果を返すこと
  3. 見つかったときは found: に名前をつないだ文字列、見つからないときは empty を返すこと

入出力例

run(1, "taro", 1) → "found:taro" run(1, "taro", 2) → "empty" run(99, "hanako", 99) → "found:hanako" run(7, "guest", 0) → "empty"

ヒント

ネストしたインターフェースと static class が使えます。interface UserRepository と static class InMemoryUserRepository を Main の中に置いてください

保管庫は `Map<Long, String>` で十分です。save は put、findById は get に対応します

get は見つからないと null を返します。null かどうかで found と empty を分けます

生田 陸人
監修生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア監修者プロフィールを見る →
編集 ゆめさく編集部·公開 2026/08/09

関連レッスン

  • メソッド名からクエリを作る

    findByNameAndAge のような名前を解析する処理を実装します。

  • 検索条件の組み立て

    指定された条件だけを WHERE 句に足す処理を実装します。

  • ページングと並び替え

    ページ番号と件数から取り出す範囲を計算します。

  • N+1問題

    発行されるクエリ本数を数え、N+1 を検出できるようになります。

このレッスンに出てくる用語

意味があいまいなまま進んだ語は、ここから読み直せます。

  • クラスデータと振る舞いを束ねる単位
  • リポジトリプロジェクトの保管場所
  • インターフェースインターフェースはメソッドの宣言のみ(実装なし)、複数実装可能。
  • コンテナデータ取得や状態を担う上位コンポーネント
  • 引数位置引数=順番で渡す。
  • エンティティDB の 1 行 = アプリの 1 オブジェクト
  • 外部キーテーブル同士を結びつける鍵
  • 主キーレコードを一意に特定する列
main.java
学習モード
エディタを読み込んでいます

メモ

リポジトリという抽象

⌘S で保存