@ExceptionHandler の基本的な使い方を徹底解説!Spring MVCコントローラ入門
新人
「Spring MVCで画面を作っていると、エラーが出たときに急に処理が止まってしまうことがあるんですが、こういう場合ってどう対応するのが正解なんでしょうか?」
先輩
「そのまま何もしていないと、利用者には分かりにくいエラー画面が表示されてしまいます。そこで重要になるのが例外処理と @ExceptionHandler です。」
新人
「@ExceptionHandlerって名前は見たことがありますが、正直いつ使うものなのか分かっていません。」
先輩
「大丈夫です。Spring MVCの例外処理は、最初に全体の流れを理解すると一気に分かりやすくなります。順番に見ていきましょう。」
1. @ExceptionHandlerとは何か
@ExceptionHandler は、Spring MVCで例外処理を行うための仕組みの一つです。 コントローラの処理中に例外が発生した場合、その例外を専用のメソッドで受け取り、 画面遷移やエラーメッセージ表示などの処理をまとめて記述できます。
初心者のうちは、例外が発生すると「プログラムが失敗した」とだけ捉えてしまいがちですが、 Webアプリケーションでは例外は日常的に発生するものです。 入力値が不正だったり、想定外のリクエストが送られてきたりすることは珍しくありません。
@ExceptionHandlerを使うことで、 「例外が起きたらこの処理をする」というルールを明確に定義できます。 これにより、Spring MVC 例外処理 初心者でも、 コントローラの中身をシンプルに保ちながら安全な処理を書くことができます。
「@ExceptionHandler 使い方」というキーワードで検索されることが多いのは、 try-catchだけでは対応しきれない場面が多く、 より分かりやすい例外処理の方法が求められているからです。
2. なぜSpring MVCで例外処理が必要なのか
Spring MVCは、ユーザーからのリクエストを受け取り、 コントローラで処理を行い、画面を返すという流れで動いています。 この一連の流れの中では、さまざまな問題が発生する可能性があります。
例えば、数値を想定している入力欄に文字が入力された場合や、 存在しないURLにアクセスされた場合などです。 こうした問題が起きたときに例外処理をしていないと、 アプリケーションはエラー画面をそのまま表示してしまいます。
それでは利用者にとって非常に不親切ですし、 開発者にとっても「どこで何が起きたのか」が分かりにくくなります。 Spring MVCでは、例外処理を適切に行うことで、 ユーザー体験と保守性の両方を向上させることができます。
@ExceptionHandlerは、 コントローラ内で発生した例外をまとめて扱うための仕組みです。 そのため、例外処理を一箇所に集約でき、 コードの見通しが良くなるという大きなメリットがあります。
3. コントローラで例外が発生する基本的な流れ
Spring MVCにおける例外発生の流れを、文章で整理してみましょう。 まず、ユーザーがブラウザからリクエストを送信します。 そのリクエストはコントローラのメソッドに渡され、処理が開始されます。
その処理の途中で問題が発生すると、例外が発生します。 何も設定していない場合、Spring MVCはその例外を処理できず、 デフォルトのエラー画面を表示します。
ここで @ExceptionHandler が定義されていると、 Spring MVCは「この例外を処理するメソッドがあるか」を探します。 該当する @ExceptionHandler が見つかれば、 そのメソッドに処理が移り、指定した画面を返すことができます。
つまり、@ExceptionHandlerは、 例外が発生した後の「受け皿」として機能します。 この流れを理解しておくことで、 なぜコントローラに例外処理を書くのかが自然と見えてきます。
@Controller
public class SampleController {
@GetMapping("/sample")
public String sample(@RequestParam String value) {
int number = Integer.parseInt(value);
return "sample";
}
@ExceptionHandler(NumberFormatException.class)
public String handleNumberFormatException() {
return "error";
}
}
この例では、数値に変換できない文字列が渡された場合に例外が発生します。 その例外を @ExceptionHandler で受け取り、 エラー画面へ遷移させています。
@Controller
public class AnotherController {
@GetMapping("/calc")
public String calc(@RequestParam String input) {
int result = 100 / Integer.parseInt(input);
return "calc";
}
@ExceptionHandler(Exception.class)
public String handleException() {
return "commonError";
}
}
このように、コントローラ内で発生する例外を想定し、 @ExceptionHandlerで処理を定義しておくことで、 Spring MVCの例外処理を安全かつ分かりやすく実装できます。 これが @ExceptionHandler の基本的な役割です。
4. @ExceptionHandler を使った基本的な例外処理の書き方
ここからは、@ExceptionHandler を使った具体的な例外処理の書き方について見ていきます。 初心者がまず押さえておきたいポイントは、 「@ExceptionHandler はコントローラの中に書く」という点です。
Spring MVCでは、コントローラのメソッドで例外が発生すると、 そのコントローラ内に定義されている @ExceptionHandler を探しに行きます。 そのため、通常のリクエスト処理メソッドと同じクラスに、 例外処理用のメソッドを用意するのが基本的な書き方になります。
@ExceptionHandler の引数には、 処理したい例外クラスを指定します。 これにより、「どの例外が発生したときに、このメソッドを呼ぶのか」が明確になります。 この仕組みがあることで、Spring MVC @ExceptionHandler は非常に読みやすい例外処理を実現できます。
@Controller
public class BasicExceptionController {
@GetMapping("/basic")
public String basic(@RequestParam String value) {
int num = Integer.parseInt(value);
return "basic";
}
@ExceptionHandler(NumberFormatException.class)
public String handleNumberFormat() {
return "numberError";
}
}
このコードでは、数値変換に失敗した場合に NumberFormatException が発生し、 handleNumberFormat メソッドが自動的に呼ばれます。 例外が発生したタイミングで、 Spring MVCが処理の流れを切り替えているイメージを持つと理解しやすくなります。
重要なのは、通常の処理メソッドには例外処理のコードを書かず、 例外専用のメソッドに役割を分けている点です。 これが @ExceptionHandler の基本的な考え方です。
5. try-catch と @ExceptionHandler の違い
例外処理と聞いて、まず思い浮かぶのが try-catch という初心者の方も多いでしょう。 実際、Javaの基本として try-catch はとても重要な仕組みです。 しかし、Spring MVCのコントローラでは、 try-catch と @ExceptionHandler には明確な役割の違いがあります。
try-catch は、「その場で処理を完結させたい例外」を扱うための仕組みです。 例えば、そのメソッド内でエラー内容を判定し、 別の処理に分岐させたい場合などに向いています。
一方で @ExceptionHandler は、 「コントローラ全体で共通して扱いたい例外」を処理するための仕組みです。 どのメソッドで発生しても同じ対応をしたい例外は、 try-catch ではなく @ExceptionHandler にまとめた方が分かりやすくなります。
@GetMapping("/try")
public String trySample(@RequestParam String value) {
try {
int num = Integer.parseInt(value);
} catch (NumberFormatException e) {
return "error";
}
return "success";
}
このような try-catch は、 処理の流れが一つのメソッドに閉じているため、 簡単な処理では問題ありません。 しかし、同じ例外処理を複数のメソッドに書き始めると、 コードが重複し、読みづらくなってしまいます。
Spring MVC 例外処理では、 「局所的な制御は try-catch」、 「コントローラ全体のルールは @ExceptionHandler」 という使い分けを意識すると、設計がとても整理しやすくなります。
6. どの例外を @ExceptionHandler で処理すべきか
次に悩みやすいのが、 「どの例外を @ExceptionHandler で処理すればよいのか」という点です。 初心者のうちは、すべての例外を @ExceptionHandler に書きたくなりがちですが、 それはあまりおすすめできません。
@ExceptionHandler で処理すべきなのは、 ユーザー操作や入力値に起因する例外です。 例えば、数値変換エラーや必須項目の未入力などは、 Webアプリケーションではよく発生する問題です。
これらの例外は、 エラーメッセージを表示したり、 入力画面に戻したりすることで回復可能です。 そのため、例外処理 コントローラ の設計では、 @ExceptionHandler の対象として扱うのが適しています。
@ExceptionHandler(ArithmeticException.class)
public String handleArithmetic() {
return "calcError";
}
一方で、プログラムのバグやシステムレベルの問題まで @ExceptionHandler で無理に処理しようとすると、 問題の原因が分かりにくくなります。 まずは「ユーザーが起こしやすい例外」に絞って考えるのがポイントです。
7. コントローラ単位で例外処理を書くメリット
最後に、コントローラ単位で @ExceptionHandler を使うメリットについて整理します。 Spring MVCでは、コントローラごとに役割が分かれているため、 その役割に応じた例外処理を書くことができます。
例えば、計算処理を担当するコントローラと、 入力画面を担当するコントローラでは、 発生しやすい例外の種類が異なります。 それぞれに合った @ExceptionHandler を定義することで、 例外処理の意図が非常に分かりやすくなります。
また、コントローラ単位で例外処理を書くことで、 不要に大きな共通処理を作らずに済みます。 これは初心者がつまずきやすい、 「最初から共通化しすぎて分からなくなる」問題を防ぐ効果もあります。
Spring MVC @ExceptionHandler は、 小さく始めて、必要になったら整理するという使い方が理想的です。 まずはコントローラごとに例外処理を書き、 全体像が見えてきた段階で次の仕組みを学ぶと、 例外処理の理解がより深まります。
ここまで理解できれば、 @ExceptionHandler を使った例外処理の基本は十分に身についています。 次のステップでは、より広い範囲で例外を扱う方法を学ぶことで、 Spring MVCのエラーハンドリングをさらに強化できるようになります。
8. @ExceptionHandler を使うときの注意点
@ExceptionHandler はとても便利な仕組みですが、使い方を間違えると、 かえってコードが分かりにくくなることがあります。 そのため、いくつかの注意点を意識しながら使うことが大切です。
まず注意したいのは、 例外処理を何でもかんでも @ExceptionHandler に集めすぎないことです。 Spring MVC 例外処理 設計では、 「本当に画面遷移やエラーページ表示が必要な例外か」 という視点で考える必要があります。
例えば、プログラム内部のちょっとした判定ミスや、 開発中にしか起こらない例外まで @ExceptionHandler で処理すると、 本来気づくべき問題を見逃してしまうことがあります。 例外はすべて利用者向けに処理すればよい、という考え方は危険です。
また、@ExceptionHandler の対象に Exception クラスを指定しすぎるのも注意が必要です。 どんな例外でも同じ画面に遷移してしまうと、 原因の切り分けが難しくなり、保守性が下がります。 具体的な例外クラスを指定することで、 処理の意図が明確になります。
@ExceptionHandler(Exception.class)
public String handleAllException() {
return "error";
}
このような書き方は一見便利ですが、 どのような例外が起きても同じ処理になってしまいます。 初心者のうちは特に、 「例外の種類ごとに役割を分ける」という意識を持つことが重要です。
9. よくある失敗例とその原因
@ExceptionHandler を学び始めた初心者がよくやってしまう失敗には、 いくつか共通したパターンがあります。 これらを事前に知っておくことで、 無駄なつまずきを減らすことができます。
よくある失敗の一つが、 「例外が発生しているのに @ExceptionHandler が呼ばれない」というケースです。 この原因の多くは、 例外が発生している場所と @ExceptionHandler を書いているコントローラが 一致していないことにあります。
@ExceptionHandler は、 基本的に同じコントローラ内で発生した例外しか処理しません。 別のコントローラで発生した例外を処理したい場合、 設計を見直す必要があります。
もう一つの失敗例は、 try-catch と @ExceptionHandler を混在させすぎることです。 あちこちに try-catch が書かれている状態で、 さらに @ExceptionHandler を追加すると、 「どこで例外を処理しているのか」が分からなくなります。
@GetMapping("/mix")
public String mix(@RequestParam String value) {
try {
int num = Integer.parseInt(value);
} catch (NumberFormatException e) {
throw e;
}
return "mix";
}
このような書き方は、 try-catch で例外を捕まえたあとに再度例外を投げており、 処理の意図が非常に分かりにくくなります。 例外処理は「どこで処理するのか」を明確に決めることが大切です。
10. 実務での @ExceptionHandler の使われ方
実務のSpring MVC開発では、 @ExceptionHandler は「画面表示を整えるための仕組み」として使われることが多いです。 例えば、入力エラー用の画面や、 業務エラー専用の画面を表示するために利用されます。
実務では、 コントローラの処理自体はできるだけシンプルに保ち、 想定される例外だけを @ExceptionHandler で受け取る設計が好まれます。 これにより、通常の処理と例外処理の役割がはっきり分かれます。
結果として、 コントローラのメソッドを読むだけで 「通常時の処理」がすぐに理解できるようになります。 これが @ExceptionHandler を使うとコードが読みやすくなる大きな理由です。
Spring MVC 例外処理 設計では、 例外処理は脇役であり、主役ではありません。 必要最低限の例外処理を適切な場所に置くことで、 全体の設計が安定します。
11. @ExceptionHandler を理解することで得られるメリット
@ExceptionHandler を正しく理解すると、 Spring MVCのコントローラ設計が一気に分かりやすくなります。 通常処理と例外処理の役割を分けることで、 コードの流れが自然になり、読みやすさが向上します。
また、例外処理を書きすぎないという考え方を身につけることで、 本当に必要なエラー対応だけに集中できるようになります。 これは実務において非常に重要な感覚です。
@ExceptionHandler は、 あくまで「コントローラ単位での例外処理」を整理するための仕組みです。 コントローラごとの役割を意識して使うことで、 無理のない設計ができます。
ここまで理解できたら、 次に学ぶべき内容として、 複数のコントローラに共通する例外処理をまとめる方法が気になってくるはずです。 そのときに登場するのが、 ControllerAdvice という仕組みです。
まずは @ExceptionHandler の基本をしっかり身につけ、 コントローラ単位での例外処理に慣れることが、 Spring MVCのエラーハンドリングを理解するための最短ルートです。