1. test 1
  2. test 2
  3. test 3
  4. test 4
  5. test 5
コース一覧
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分

検索条件の組み立て

このレッスンでは、指定された条件だけを WHERE 句に足していく動的クエリの考え方を身に付けます。

検索フォームは条件が毎回変わります

利用者向けの検索画面を思い浮かべてください。名前で絞り込みたい人もいれば、年齢だけで絞りたい人もいて、何も入れずに一覧を見たい人もいます。つまりリクエストごとに、使われる条件の組み合わせが変わります。

Java

@GetMapping("/users") public List<UserResponse> search( @RequestParam(required = false) String name, @RequestParam(required = false) Integer minAge) { // name も minAge も来ないことがある }

この状況をメソッド名クエリで表そうとすると行き詰まります。findByName、findByMinAge、findByNameAndMinAge、findAll の4つを用意しなければならず、条件が1つ増えるたびに必要なメソッド数が倍になります。条件が5つあれば32通りです。名前で列挙する方式は、この時点で限界を迎えます。

指定されたものだけを足す

解き方は単純です。条件を最初から全部書くのではなく、指定されているものだけを順に足していきます。

Java

StringBuilder sql = new StringBuilder("SELECT * FROM users"); List<String> conditions = new ArrayList<>(); if (name != null && !name.isEmpty()) { conditions.add("name = ?"); } if (minAge != null) { conditions.add("age >= ?"); } if (!conditions.isEmpty()) { sql.append(" WHERE ").append(String.join(" AND ", conditions)); }

ここで大事なのは、条件をいったんリストに集めてから最後にまとめてつなぐ、という順序です。文字列に直接足していく書き方をすると、AND を先頭に付けるべきか否かの判定が条件ごとに必要になり、必ず事故が起きます。よくある失敗は次の2つです。

  1. 条件が1つも無いのに WHERE だけが残り、SELECT * FROM users WHERE という壊れた SQL になる
  2. 先頭の条件の前に AND が付いて WHERE AND name = ? になる

リストに集める方式なら、どちらも構造的に起こりません。区切り文字を挟むのは要素と要素の間だけ、という仕事を String.join に任せられるからです。

未指定をどう表すか

実務でつまずきやすいのが「未指定」の表現です。Spring の @RequestParam(required = false) を Integer で受ければ未指定は null になりますが、int で受けると未指定でも 0 が入ってしまい、区別が付きません。文字列も同様で、パラメータそのものが来ない場合と、空文字列で来た場合の両方を未指定として扱うのが普通です。

型未指定の表し方注意点
Stringnull または空文字列両方を弾く必要がある
Integernullint にすると 0 と区別できない
boolean使わない方が良い未指定と false が同じになる

Spring 本体では、この分岐をより宣言的に書くための Specification や Query by Example といった仕組みも用意されていますが、内部でやっていることは今書いた「指定された条件だけを足す」という判断そのものです。

演習で書くもの

演習では、この組み立てを自分の手で書きます。name と minAge を受け取り、指定されたものだけを含む WHERE 句を作ります。今回は引数に null を使えないので、name は空文字列を、minAge は -1 を未指定の印として扱います。どちらも未指定なら WHERE 句そのものを付けない、という判定が肝です。Spring が Specification の内側でやっている判断を、そのまま条件分岐として書き下すことになります。

要件

  1. name が空文字列でなければ name = 'taro' の形の条件を足すこと。値はシングルクォートで囲むこと
  2. minAge が -1 でなければ age >= 20 の形の条件を足すこと
  3. 条件が2つあるときは name の条件を先にして AND でつなぎ、条件が1つも無いときは WHERE 句を付けないこと

入出力例

buildQuery("taro", 20) → "SELECT * FROM users WHERE name = 'taro' AND age >= 20" buildQuery("taro", -1) → "SELECT * FROM users WHERE name = 'taro'" buildQuery("", 20) → "SELECT * FROM users WHERE age >= 20" buildQuery("", -1) → "SELECT * FROM users" buildQuery("hanako", 0) → "SELECT * FROM users WHERE name = 'hanako' AND age >= 0"

ヒント

条件を `List<String>` に集めてから、最後にまとめてつなぐと分岐が減ります

String.join(" AND ", conditions) で条件をつなげます

conditions が空かどうかで WHERE 句を足すかどうかを決めます。空のときは基本の文をそのまま返します

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

関連レッスン

  • ページングと並び替え

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

  • N+1問題

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

  • 例外をHTTPに変換する

    例外の種類からステータスコードを決める処理を実装します。

  • テストの種類と使い分け

    @SpringBootTest と @WebMvcTest の違いを確認します。

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

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

  • フォームinput(text, email, password, checkbox, radio)、select、textarea、button。
  • リクエストWeb 通信の基本単位、ブラウザの問い合わせとサーバーの返答
  • メソッドクラスに属する関数
  • リスト順序付きで複数の値を扱うデータ構造
  • SQLデータベースを操作するための共通言語
  • 判断YES/NO 分岐を表す菱形
  • 引数位置引数=順番で渡す。
main.java
学習モード
エディタを読み込んでいます

メモ

検索条件の組み立て

⌘S で保存