コントローラーメソッドの引数に何が使えるか?Spring MVCでの基本を解説!
新人
「Springでコントローラークラスを使っているんですが、メソッドの引数って自由に決めていいんですか?」
先輩
「いい質問だね。Spring MVCでは、使える引数がある程度決まっているんだ。」
新人
「たとえば、リクエストのパラメータを受け取るにはどうすればいいですか?」
先輩
「それじゃあ、今回はSpringの@Controllerで使える引数について一緒に学んでいこうか。」
1. Spring MVCのコントローラとは
Spring MVCでは、Webアプリケーションにおけるリクエスト処理を行うのが「コントローラ」です。具体的には、ユーザーからのリクエスト(URL)を受け取り、その内容に応じてレスポンスを返す役割があります。
@Controllerアノテーションを使うことで、そのクラスがコントローラとして動作するようになります。ここで注意したいのは、今回は@RestControllerではなく、@Controllerを使う点です。HTMLなどのビューを返す場合には@Controllerを使用するのが基本です。
Springプロジェクトの作成には、pleiadesを使い、Gradleで構成されています。依存関係もpleiadesのチェック機能を使って追加しましょう。
@Controller
public class HelloController {
@RequestMapping("/hello")
public String helloPage() {
return "hello";
}
}
2. コントローラーメソッドとは?その役割
Spring MVCでは、コントローラ内の各メソッドが「リクエストハンドラ」として動作します。リクエストされたURLに応じて、それに対応するメソッドが呼び出されます。このメソッドのことを「コントローラーメソッド」と呼びます。
このメソッドでは、フォームから送られてきたデータを受け取ったり、処理結果をビューに渡したりするために、引数を使うことができます。引数には、リクエストの情報やフォームデータ、モデルオブジェクトなど、さまざまな型を指定できます。
このとき、使える引数の種類には制限があります。Springがサポートしている型やアノテーションを使う必要があります。
@Controller
public class SampleController {
@RequestMapping("/submit")
public String handleForm(String name, int age) {
// リクエストパラメータ name, age を受け取る
return "result";
}
}
上記のように、フォームのnameやageを直接受け取ることもできますが、より柔軟に処理するには専用のアノテーションや型を使った方がよいケースもあります。
3. 使える引数には何がある?ざっくり紹介
ここでは、Springの@Controllerで使える引数の種類をざっくりと紹介します。これらは、今後詳しく説明していくので、まずは「こんなものが使えるんだな」という感覚を持ってください。
- HttpServletRequest / HttpServletResponse:リクエストやレスポンスを直接操作できます。
- Model / ModelMap:ビューに値を渡すために使用します。
- @RequestParam:リクエストパラメータを受け取るためのアノテーションです。
- @ModelAttribute:フォームのデータをオブジェクトにマッピングして受け取るために使います。
- BindingResult:バリデーション結果を受け取るために使います。
これらの引数は、Springが内部で自動的に適切なオブジェクトをバインドしてくれます。自分で生成したりする必要はありません。
次回は、これらの引数について一つひとつ詳しく解説し、どのように使うのか、どんなときに使うべきなのかを具体的なコードとともに学んでいきましょう。
4. コントローラーメソッドで使える主な引数を詳しく解説
ここからは、Spring コントローラー 引数として使える代表的な項目について、より詳しく解説していきます。初心者でも理解できるように、具体例と共に説明します。
HttpServletRequest / HttpServletResponse
Java Servlet APIのHttpServletRequestとHttpServletResponseは、リクエスト情報やレスポンスの制御に使えます。
例えば、リクエストヘッダーやセッションの値を取得したり、レスポンスに直接文字列を書き出したりすることができます。
@Controller
public class RequestController {
@RequestMapping("/request")
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
String name = request.getParameter("name");
response.getWriter().write("Hello " + name);
}
}
Model / ModelMap
ModelやModelMapは、コントローラーからビュー(JSPなど)にデータを渡すときに使用します。リクエストスコープに属性を追加するのと同じ感覚です。
@Controller
public class ModelController {
@RequestMapping("/model")
public String handleModel(Model model) {
model.addAttribute("message", "こんにちは、Spring MVC!");
return "hello";
}
}
@RequestParam
@RequestParamは、リクエストパラメータを引数として受け取るためのアノテーションです。URLやフォームから送られてくるデータを、簡単に変数にバインドできます。
@RequestParam 使い方としてよくあるのは、下記のようなケースです。
@Controller
public class ParamController {
@RequestMapping("/param")
public String handleParam(@RequestParam("name") String name, Model model) {
model.addAttribute("userName", name);
return "greeting";
}
}
パラメータ名と変数名が同じであれば、@RequestParamの属性は省略することもできます。
@RequestBody
@RequestBodyは、リクエストボディの内容をJavaオブジェクトに変換して受け取るためのアノテーションです。ただし、@Controllerでは通常、HTMLビューを返すため、@RequestBodyはあまり使いません。
どうしてもJSONなどのデータを直接受け取る必要がある場合は、内部処理専用や例外的に使う形になります。
@Controller
public class JsonController {
@PostMapping("/json")
public String handleJson(@RequestBody UserForm userForm, Model model) {
model.addAttribute("user", userForm);
return "userView";
}
}
@ModelAttribute
@ModelAttributeは、リクエストパラメータをJavaオブジェクトにまとめてバインドするためのアノテーションです。フォームで入力された複数の項目を、一つのオブジェクトとして受け取るときに便利です。
public class UserForm {
private String name;
private int age;
// getterとsetterは省略
}
@Controller
public class FormController {
@PostMapping("/submit")
public String handleForm(@ModelAttribute UserForm form, Model model) {
model.addAttribute("user", form);
return "result";
}
}
BindingResult
BindingResultは、@ModelAttributeとセットで使用され、バリデーションの結果を受け取るための引数です。入力エラーのチェックやエラーメッセージの表示に役立ちます。
@Controller
public class ValidController {
@PostMapping("/validate")
public String handleValidation(@ModelAttribute @Valid UserForm form, BindingResult result, Model model) {
if (result.hasErrors()) {
return "form";
}
model.addAttribute("user", form);
return "success";
}
}
5. よく使われるコントローラーメソッドのパターン例
ここでは、実際の開発現場でよく使われる「フォーム送信を受け取る処理」の基本パターンを紹介します。Spring コントローラー 引数を理解する上で非常に重要な部分です。
まずは、HTML側で下記のようなフォームがあるとします。
<form action="/submit" method="post">
名前:<input type="text" name="name">
年齢:<input type="number" name="age">
<button type="submit">送信</button>
</form>
このフォームから送られてくるリクエストを、Springのコントローラーで下記のように受け取ることができます。
public class UserForm {
private String name;
private int age;
// getterとsetterは省略
}
@Controller
public class SubmitController {
@PostMapping("/submit")
public String submit(@ModelAttribute UserForm form, Model model) {
model.addAttribute("userName", form.getName());
model.addAttribute("userAge", form.getAge());
return "confirmation";
}
}
このように、HTMLフォームの内容を@ModelAttributeを使って一つのオブジェクトとして受け取り、ビューにそのまま渡すというパターンが非常によく使われます。
また、フォーム入力のチェックを加える場合は、@ValidとBindingResultを組み合わせることで、エラーのある入力を検出し、適切に表示することも可能です。
Springの@Controllerで使える引数には、非常に多くのバリエーションがありますが、今回紹介した内容を押さえておけば、基本的な開発において困ることは少ないでしょう。
次回は、これらの引数を組み合わせたときの注意点や、よくあるエラーとその対処法について詳しく紹介していきます。
6. 引数の組み合わせ例と注意点
ここでは、実際に@Controllerのコントローラーメソッドに複数の引数を組み合わせる場合の注意点について解説します。特に初心者が混乱しやすいのが@ModelAttributeとBindingResultの組み合わせです。
BindingResultと@ModelAttributeの順番に注意
BindingResult 注意点として最も重要なのは、BindingResultは、@ModelAttributeや@Validでバインドされるオブジェクトの「すぐ後ろ」に書く必要があるという点です。
順番を間違えると、バリデーションが実行されず、例外が発生してしまいます。以下は正しい例です。
@PostMapping("/register")
public String register(@ModelAttribute @Valid UserForm form, BindingResult result, Model model) {
if (result.hasErrors()) {
return "form";
}
model.addAttribute("user", form);
return "success";
}
しかし、次のようにBindingResultの位置がずれてしまうと、Springがバリデーション結果を保持できず、エラーになります。
// ❌ NGな例
@PostMapping("/register")
public String register(BindingResult result, @ModelAttribute @Valid UserForm form, Model model) {
// BindingResultがバリデーション対象の直後でないため、エラーになる
return "error";
}
複数の引数を使い分けるときの注意
同じリクエストに対して複数の引数を指定する場合、それぞれの役割を明確にすることが大切です。
@RequestParam:単一の値を受け取りたいとき@ModelAttribute:複数項目のフォームデータを受け取りたいときModel:ビューにデータを渡したいときBindingResult:バリデーションの結果を受け取りたいとき
これらを同時に使うことで、柔軟なリクエスト処理が可能になります。
@PostMapping("/save")
public String save(
@RequestParam("mode") String mode,
@ModelAttribute @Valid UserForm form,
BindingResult result,
Model model) {
if (result.hasErrors()) {
model.addAttribute("mode", mode);
return "form";
}
model.addAttribute("user", form);
model.addAttribute("mode", mode);
return "result";
}
このように、Spring Controller 引数 組み合わせを正しく理解することで、より堅牢で保守性の高いコードを書くことができます。
7. よくあるエラーとその対処法
Spring MVCで@Controllerを使った開発をしていると、引数の順序やアノテーションの使い方に関するエラーがよく発生します。ここでは、初心者が特につまずきやすいケースとその解決法を紹介します。
BindingResultを後ろに書かなかった場合の例外
BindingResultを@ModelAttributeの前に書いてしまうと、Springがバリデーション結果を格納できず、IllegalStateExceptionという例外が発生します。
java.lang.IllegalStateException:
Errors/BindingResult argument declared without preceding model attribute
この例外が出たら、すぐにメソッドの引数順を確認してください。
@RequestParamの型変換エラー
@RequestParamで数値型の引数を指定した場合、送られてきた値が不正だったり、未指定だったりすると、400 Bad Requestのエラーになります。
未指定でも許容したい場合は、required = falseを指定し、デフォルト値を用意するなどの工夫が必要です。
@GetMapping("/search")
public String search(@RequestParam(name = "id", required = false, defaultValue = "0") int id, Model model) {
model.addAttribute("userId", id);
return "searchResult";
}
@ModelAttributeのオブジェクトがnullになる
フォームの入力項目名とJavaオブジェクトのフィールド名が一致していない場合、値が正しくバインドされず、オブジェクトのプロパティがnullになることがあります。
このようなときは、HTMLフォームのname属性とJavaのフィールド名をしっかり確認しましょう。
バリデーションのアノテーションが効かない
@Validを使ってもバリデーションが機能しない場合、以下のような原因が考えられます。
- 依存関係に
spring-boot-starter-validationが含まれていない - Javaクラスに
@NotNullなどのアノテーションを付けていない @ValidとBindingResultの順序が不正
Gradleでの依存関係追加は、pleiadesのチェック機能で「validation-api」などを有効にして対応しましょう。
8. 引数を使い分けるための簡単な指針
ここまで、Spring Controller 引数 組み合わせの使い方や、BindingResult 注意点を中心に解説してきました。最後に、どの引数をどんな状況で使えばいいのか、簡単にまとめておきます。
- リクエストパラメータを受け取りたいとき:
@RequestParam - 複数のフォーム項目をオブジェクトとして受け取りたいとき:
@ModelAttribute - 入力内容の検証をしたいとき:
@ValidとBindingResult - ビューにデータを渡すとき:
ModelまたはModelMap - リクエストやレスポンスを直接操作したいとき:
HttpServletRequestやHttpServletResponse
Spring MVCのコントローラーメソッドでは、引数の組み合わせが柔軟である反面、順序や使い方を間違えると想定外の動作やエラーにつながる可能性があります。
特にBindingResultの位置や、パラメータ名とオブジェクトフィールド名の一致などは、初学者にとって混乱しやすいポイントなので、繰り返し実践しながら理解を深めていきましょう。
次の記事では、実際の開発シナリオでのコントローラー設計例や、より複雑なバリデーション処理について詳しく解説していきます。