Springの@ControllerAdviceと@ExceptionHandlerの使い方を完全ガイド!初心者でもわかる例外処理の基本
生徒
「Springでコントローラーの処理中にエラーが起きたとき、全部にtry-catchを書かないといけないんですか?」
先生
「それは大変ですよね。でもSpringには共通の例外処理を一箇所にまとめられる@ControllerAdviceという便利な仕組みがあります。」
生徒
「それって、全体のエラーハンドリングが簡単になるってことですか?」
先生
「そうなんです。さらに、@ExceptionHandlerと組み合わせると、例外の種類ごとに丁寧な対応ができますよ。詳しく見ていきましょう!」
1. Springの例外処理とは?初心者向けにわかりやすく解説
Spring Frameworkでは、アプリケーション中で発生する例外(エラー)を効率よく処理する方法として、@ControllerAdviceと@ExceptionHandlerを使った「グローバル例外処理」がよく使われます。これは、全体のコントローラーに共通する例外処理を一元化し、メンテナンス性の向上やコードの簡略化に役立ちます。
例えば、Webアプリケーションでユーザーが存在しないIDを指定してアクセスしたときや、バリデーションエラーが起きたときに、それぞれ適切なエラーメッセージを返す処理が可能です。
2. @ControllerAdviceの基本と役割
@ControllerAdviceは、複数の@Controllerに共通する処理をまとめるためのアノテーションです。例外処理だけでなく、バインディングエラーの処理なども扱えますが、今回は例外処理に特化して解説します。
グローバルなエラーハンドリングを実現するには、以下のようにクラスに@ControllerAdviceを付けて定義します。
@ControllerAdvice
public class GlobalExceptionHandler {
// 例外ハンドラをここに記述
}
このクラス内に@ExceptionHandlerを使ったメソッドを定義することで、アプリ全体の例外を一箇所で処理できます。
将来を見据えて、+αのスキルを身につけたい方へ
JavaやLinuxを学んでいても、「このままで市場価値は上がるのか」 「キャリアの選択肢を広げたい」と感じる方は少なくありません。
AIを学ぶならアイデミープレミアム3. @ExceptionHandlerで例外をキャッチする方法
@ExceptionHandlerは、特定の例外クラスに対する処理を記述するためのアノテーションです。たとえば、IllegalArgumentExceptionが発生したときに、指定したメソッドが呼ばれるようにできます。
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<String> handleIllegalArgument(IllegalArgumentException ex) {
return ResponseEntity.badRequest().body("不正なリクエストです:" + ex.getMessage());
}
上記のように記述すれば、例外に応じたエラーメッセージを返すことが可能です。
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と組み合わせて使うコツ
@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 FrameworkやThymeleafを使った Webアプリ開発の全体像をやさしく理解したい人には、 この入門書が定番です。
Spring Framework超入門をAmazonで見る※ Amazonアソシエイト・プログラムを利用しています