@RequestParamが多すぎる時のController引数整理を解説する記事のアイキャッチ。若手エンジニアがJava道場風の学習空間で検索条件のまとめ方を学ぶイラスト。

Spring

@RequestParamが多すぎる時はどうする?Controller引数の整理方法

AIによる要約

@RequestParamが増えすぎたControllerは、読みづらく、修正漏れも起きやすくなります。検索条件や入力項目がひとまとまりなら、Formクラスや検索条件クラスへまとめることを検討します。ただし、何でもまとめればよいわけではなく、関連する値だけをまとめるのが大事です。

新人SE
新人SE
@RequestParamが10個くらいあるControllerを見ました。これは普通ですか?
ポンコツSE
ポンコツSE
動くことはありますが、レビューでは整理対象になりやすいです。検索条件としてまとまるなら、FormやConditionクラスにした方が読みやすくなります。

検索画面や一覧画面を作っていると、Controllerの引数に@RequestParamがどんどん増えることがあります。

最初は2個だった条件が、名前、ステータス、日付範囲、担当者、ページ番号と増えていき、気づくとメソッドのシグネチャだけで画面が埋まります。

この記事のポイント

  • @RequestParamが多すぎるControllerは読みづらい
  • 関連する検索条件はFormやConditionクラスにまとめる
  • 単発の値まで無理にクラス化する必要はない
  • Controller、Service、Repositoryへ渡す値の形を揃える

@RequestParamが増える典型パターン

検索画面や一覧画面では、最初はキーワードだけだった条件が、ステータス、日付範囲、担当者、並び順、ページ番号と増えていきます。

@GetMapping("/orders")
public String list(@RequestParam(required = false) String keyword,
                   @RequestParam(required = false) String status,
                   @RequestParam(required = false) String fromDate,
                   @RequestParam(required = false) String toDate,
                   @RequestParam(required = false) String staffId,
                   @RequestParam(defaultValue = "1") int page,
                   Model model) {
    model.addAttribute("orders",
            orderService.search(keyword, status, fromDate, toDate, staffId, page));
    return "orders/list";
}

このコードは動きますが、引数の数が増えるほど読みづらくなります。Service呼び出しの順番を間違えるリスクもあります。

関連する条件はクラスにまとめる

検索条件として関連している値なら、FormクラスやSearchConditionクラスにまとめます。

public class OrderSearchForm {
    private String keyword;
    private String status;
    private String fromDate;
    private String toDate;
    private String staffId;
    private int page = 1;
}

@GetMapping("/orders")
public String list(OrderSearchForm form, Model model) {
    model.addAttribute("orders", orderService.search(form));
    return "orders/list";
}

Controllerの引数がすっきりし、検索画面の入力項目もFormクラスを見れば分かります。

何でもまとめればよいわけではない

注意したいのは、無関係な値まで1つのクラスに押し込まないことです。検索条件、ページング条件、画面制御用のフラグなどが混ざりすぎると、逆に分かりにくくなります。

// 避けたい例
public class ScreenForm {
    private String keyword;
    private String status;
    private String loginUserRole;
    private boolean showAdminMenu;
    private String csrfToken;
}

Formクラスは便利ですが、画面に関係するものを何でも入れる箱ではありません。検索条件なら検索条件、登録入力なら登録入力というまとまりを守ります。

Serviceへ渡す前に整える

Controllerで受けたFormを、そのままServiceに渡してよいかはプロジェクト方針によります。検索条件を正規化してから渡す形にすると、Service以降が扱いやすくなります。

@GetMapping("/orders")
public String list(OrderSearchForm form, Model model) {
    OrderSearchCondition condition = form.toCondition();
    model.addAttribute("orders", orderService.search(condition));
    return "orders/list";
}

日付文字列をLocalDateに変換する、空文字をnullにする、といった処理をどこで行うかを決めておくと、検索処理が安定します。

レビューでは変更しやすさを見られる

// レビューコメント例
@RequestParamが多くなっているので、検索条件クラスにまとめたいです。

// レビューコメント例
Service呼び出しの引数順が分かりづらいです。
OrderSearchConditionにまとめると、条件追加時の修正漏れを減らせます。

引数が多いこと自体より、条件追加や修正のときに壊れやすいことが問題です。

単発なら@RequestParamでよい

逆に、1つか2つの値しかない処理まで無理にForm化する必要はありません。

@GetMapping("/users")
public String list(@RequestParam(required = false) String keyword, Model model) {
    model.addAttribute("users", userService.search(keyword));
    return "users/list";
}

大事なのは、機械的にクラス化することではなく、読みやすさと変更しやすさです。

レビュー前のセルフチェック

確認リスト

  • Controllerの引数が5個以上になっていないか
  • 関連する検索条件を1つのクラスにまとめられないか
  • Service呼び出しで引数順ミスが起きそうではないか
  • 無関係な値まで同じFormに入れていないか

この記事とあわせて読みたい

まとめ

@RequestParamが多すぎるControllerは、検索条件や入力項目をクラスにまとめるサインです。

ただし、何でもまとめればよいわけではありません。関連する値をひとまとまりにし、ControllerとServiceの引数を読みやすくすることを目的に整理しましょう。

-Spring
-, , , , ,