Springの@ControllerAdviceと@ExceptionHandlerの使い方を完全ガイド!初心者でもわかる例外処理の基本
生徒
「Springでコントローラーの処理中にエラーが起きたとき、全部にtry-catchを書かないといけないんですか?」
先生
「それは大変ですよね。でもSpringには共通の例外処理を一箇所にまとめられる@ControllerAdviceという便利な仕組みがあります。」
生徒
「それって、全体のエラーハンドリングが簡単になるってことですか?」
先生
「そうなんです。さらに、@ExceptionHandlerと組み合わせると、例外の種類ごとに丁寧な対応ができますよ。詳しく見ていきましょう!」
1. Springの例外処理とは?初心者向けにわかりやすく解説
「1. Springの例外処理とは?初心者向けにわかりやすく解説」の重要ポイントを、初心者の方にも分かりやすく簡潔に解説します。
Spring Frameworkでは、アプリケーション中で発生する例外(エラー)を効率よく処理する方法として、@ControllerAdviceと@ExceptionHandlerを使った「グローバル例外処理」がよく使われます。これは、全体のコントローラーに共通する例外処理を一元化し、メンテナンス性の向上やコードの簡略化に役立ちます。
例えば、Webアプリケーションでユーザーが存在しないIDを指定してアクセスしたときや、バリデーションエラーが起きたときに、それぞれ適切なエラーメッセージを返す処理が可能です。
2. @ControllerAdviceの基本と役割
@ControllerAdviceは、複数の@Controllerに共通する処理をまとめるためのアノテーションです。例外処理だけでなく、バインディングエラーの処理なども扱えますが、今回は例外処理に特化して解説します。
グローバルなエラーハンドリングを実現するには、以下のようにクラスに@ControllerAdviceを付けて定義します。
@ControllerAdvice
public class GlobalExceptionHandler {
// 例外ハンドラをここに記述
}
このクラス内に@ExceptionHandlerを使ったメソッドを定義することで、アプリ全体の例外を一箇所で処理できます。
3. @ExceptionHandlerで例外をキャッチする方法
@ExceptionHandlerは、特定の例外クラスに対する処理を記述するためのアノテーションです。たとえば、IllegalArgumentExceptionが発生したときに、指定したメソッドが呼ばれるようにできます。
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<String> handleIllegalArgument(IllegalArgumentException ex) {
return ResponseEntity.badRequest().body("不正なリクエストです:" + ex.getMessage());
}
上記のように記述すれば、例外に応じたエラーメッセージを返すことが可能です。
4. 例外ごとに異なるレスポンスを返す方法
「4. 例外ごとに異なるレスポンスを返す方法」の重要ポイントを、初心者の方にも分かりやすく簡潔に解説します。
たとえば「リソースが存在しない場合」と「入力値が間違っていた場合」とでは、返すHTTPステータスやメッセージを変えたいですよね。そのようなケースでも@ExceptionHandlerは柔軟に対応できます。
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<String> handleNotFound(ResourceNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("リソースが見つかりません:" + ex.getMessage());
}
このようにすることで、HTTP 404 Not Found を返せるようになります。
5. 共通フォーマットのエラーレスポンスを作る
フロントエンドやAPI連携で一貫性のあるエラー形式を返すことは重要です。JSON形式のレスポンスを返すことで、エラー処理がしやすくなります。
@ExceptionHandler(Exception.class)
public ResponseEntity<Map<String, String>> handleGenericException(Exception ex) {
Map<String, String> response = new HashMap<>();
response.put("error", "予期しないエラーが発生しました");
response.put("details", ex.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
}
6. 実践!@ControllerAdviceと@ExceptionHandlerの組み合わせ例
ここまでの知識を使って、実際にグローバルな例外処理を実装してみましょう。例えば、以下のようにカスタム例外とハンドラを組み合わせます。
public class UserNotFoundException extends RuntimeException {
public UserNotFoundException(String message) {
super(message);
}
}
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<String> handleUserNotFound(UserNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("ユーザーが見つかりません:" + ex.getMessage());
}
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleOther(Exception ex) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("内部エラー:" + ex.getMessage());
}
}
7. REST APIと組み合わせて使うコツ
「7. REST APIと組み合わせて使うコツ」の重要ポイントを、初心者の方にも分かりやすく簡潔に解説します。
@RestControllerと組み合わせると、レスポンスボディに直接エラーメッセージを返すことができます。JSONでエラーデータを構造化して返すと、クライアント側の処理が楽になります。
また、ResponseEntityを活用することで、ステータスコードとメッセージの一貫性が保てます。
8. よくあるミスと注意点
@ControllerAdviceはSpring MVCのコンポーネントスキャンの対象に入っていないと動作しません。@ComponentScanの範囲に入れておくことを確認しましょう。
また、例外がハンドルされずにスルーされてしまう場合は、@ExceptionHandlerの引数となる例外クラスが一致しているかを再確認してください。
9. HTMLエラーページを返したい場合
APIではなくWeb画面でエラーを表示したい場合は、ModelAndViewを使ってHTMLテンプレートに遷移させることも可能です。
@ExceptionHandler(RuntimeException.class)
public ModelAndView handleRuntime(RuntimeException ex) {
ModelAndView mv = new ModelAndView("error");
mv.addObject("message", ex.getMessage());
return mv;
}
このように書けば、エラー時にerror.htmlなどのテンプレートに遷移できます。
まとめ
「まとめ」の重要ポイントを、初心者の方にも分かりやすく簡潔に解説します。
Springの@ControllerAdviceと@ExceptionHandlerを理解することの重要性
ここまでSpringの@ControllerAdviceと@ExceptionHandlerについて学んできました。これらはSpring BootやSpring Frameworkを利用したWebアプリケーション開発やREST API開発において非常に重要な例外処理機能です。
Java初心者のうちは、エラーが発生したらtry catchを使えば良いと考えがちです。しかし実際の業務システムでは、すべてのコントローラーやサービスクラスに同じような例外処理を書くとコード量が増え、保守性が低下してしまいます。
そこで活躍するのが@ControllerAdviceです。ControllerAdviceを利用すると、アプリケーション全体で共通の例外処理を一箇所にまとめることができます。これにより、Spring MVCのコントローラーごとに同じエラーハンドリングを書く必要がなくなり、コードがすっきりします。
また、@ExceptionHandlerを組み合わせることで、発生した例外ごとに処理を分けられます。例えばユーザーが存在しない場合は四〇四エラーを返し、入力内容に問題がある場合は四〇〇エラーを返すなど、状況に応じた適切なレスポンスを返せるようになります。
Spring Bootの実務開発では、例外処理の設計が非常に重要です。例外処理が適切に行われていないと、ユーザーに分かりにくいエラーページが表示されたり、システム障害の原因調査が難しくなったりします。そのため、Springの@ControllerAdviceと@ExceptionHandlerは早い段階で身につけておきたい知識のひとつです。
例外処理を共通化するメリット
グローバル例外処理を導入する最大のメリットは、コードの重複を減らせることです。例えば会員管理システム、商品管理システム、予約管理システムなど複数の機能がある場合でも、例外処理を一つのクラスに集約できます。
もし共通化しなければ、各コントローラーで同じようなtry catchを書くことになります。開発当初は問題なくても、機能追加や仕様変更が発生すると修正箇所が増え、メンテナンスが大変になります。
一方で@ControllerAdviceを利用すれば、エラーメッセージの内容やHTTPステータスコードの変更も一箇所で対応できます。これは保守性の高いSpring Bootアプリケーションを作るうえで非常に大きなメリットです。
実務でよく使われる例外処理のサンプル
実際の業務では、独自の例外クラスを作成して運用することがよくあります。例えば会員情報が見つからない場合や商品情報が存在しない場合など、それぞれ専用の例外クラスを作成することで可読性が向上します。
public class ProductNotFoundException extends RuntimeException {
public ProductNotFoundException(String message) {
super(message);
}
}
このようなカスタム例外を利用すると、エラーの原因が分かりやすくなります。また、@ExceptionHandlerで個別に処理できるため、利用者にも適切なエラーメッセージを返せるようになります。
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ProductNotFoundException.class)
public ResponseEntity<String> handleProductNotFound(
ProductNotFoundException ex) {
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.body(ex.getMessage());
}
}
REST API開発での活用ポイント
REST API開発では、単純な文字列ではなくJSON形式でエラー情報を返すケースが一般的です。フロントエンド側では受け取ったJSONを解析して画面表示を行うため、統一されたフォーマットが求められます。
@ExceptionHandler(Exception.class)
public ResponseEntity<Map<String, String>> handleException(
Exception ex) {
Map<String, String> map = new HashMap<>();
map.put("status", "error");
map.put("message", ex.getMessage());
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(map);
}
このような実装を行うことで、フロントエンド側でも統一的なエラー処理が可能になります。Spring BootによるREST API開発では非常によく使われる実装方法です。
初心者が覚えておきたいポイント
Spring初心者がまず覚えておきたいのは、ControllerAdviceは全体を管理する司令塔のような存在であり、ExceptionHandlerは個別の例外を処理する担当者のような存在だということです。
ControllerAdviceだけでは例外を処理できません。必ずExceptionHandlerと組み合わせて使用します。
また、Exceptionクラスを対象にした例外処理を書くと、多くの例外をまとめて処理できますが、細かな制御ができなくなる場合があります。そのため実務では、独自例外クラスを作成して個別にハンドリングする方法がよく採用されています。
Spring Boot、Spring MVC、REST API、例外処理、エラーハンドリング、ControllerAdvice、ExceptionHandler、ResponseEntity、HTTPステータスコード、カスタム例外、グローバル例外処理といったキーワードは、今後のSpring開発でも何度も登場します。今回の内容をしっかり理解しておくことで、より実践的なWebアプリケーション開発ができるようになります。
特に業務システム開発では、正常系だけでなく異常系の設計も重要です。ユーザーが誤った入力をした場合、存在しないデータにアクセスした場合、データベース接続に失敗した場合など、さまざまなケースを想定しながら例外処理を設計することが求められます。
Springの@ControllerAdviceと@ExceptionHandlerを活用すれば、例外処理を整理しながら品質の高いシステムを構築できます。今後はバリデーションエラー処理や独自例外クラスの設計、REST APIのエラーレスポンス設計などにも挑戦しながら理解を深めていきましょう。
生徒
Springの@ControllerAdviceはアプリ全体の例外処理をまとめるための機能でしたね。
先生
その通りです。複数のコントローラーに共通する例外処理を一箇所で管理できます。
生徒
@ExceptionHandlerは発生した例外ごとに処理を書くためのアノテーションでした。
先生
はい。IllegalArgumentExceptionやRuntimeException、独自例外クラスなどを個別に処理できます。
生徒
すべてのコントローラーにtry catchを書く必要がなくなるので、コードが見やすくなりますね。
先生
その通りです。保守性や可読性が向上するため、実務でも非常によく利用されています。
生徒
REST APIではResponseEntityと組み合わせてJSON形式のエラーレスポンスを返すこともできました。
先生
はい。フロントエンドとの連携もしやすくなります。
生徒
例外処理は後回しにされがちですが、とても重要な機能だと分かりました。
先生
その理解で大丈夫です。Spring Boot開発では正常な処理だけでなく、エラー発生時の動作も設計することが重要です。ControllerAdviceとExceptionHandlerを活用して、安全で保守しやすいWebアプリケーションを作れるようになりましょう。
Spring FrameworkやThymeleafを使った Webアプリ開発の全体像をやさしく理解したい人には、 この入門書が定番です。
Spring Framework超入門をAmazonで見る※ Amazon広告リンク