【Spring MVC】例外ハンドリングを行う方法その2(HandlerExceptionResolverの使用)

概要

Spring MVCを使用したWebアプリケーションにて、例外ハンドリングを行う方法についてまとめた。
例外ハンドリングはweb.xmlまたはHandlerExceptionResolverの実装によって行う。

当記事ではHandlerExceptionResolverを使用してどのようハンドリングするのかについて紹介する。

あわせて読みたい

概要 Spring MVCを使用したWebアプリケーションにて、例外ハンドリングを行う方法についてまとめた。 例外ハンドリングはweb.xmlまたはHandlerExceptionResolverの実装によって行う。 当記事では例[…]

 

HandlerExceptionResolver

Spring MVCでは、フロントコントローラー以下で発生する例外をハンドリングするため、以下のHandlerExceptionResolverの実装クラスが用意されている。

・DefaultHandlerExceptionResolver
・ExceptionHandlerExceptionResolver
・ResponseStatusExceptionResolver

 

DefaultHandlerExceptionResolver

デフォルトで用意されているHandlerExceptionResolverの実装クラス。
開発者が特に意識することはない。

特定の例外に対してHTTPステータスとマッピングする情報を保持しており、その例外が発生するとマッピングしたHTTPステータスを返却する

スタックトレースの露出はされず、ステータスコードの表示されたエラー画面が表示される。

Spring Boot の概要から各機能の詳細までが網羅された公式リファレンスドキュメントです。開発者が最初に読むべきド…

 

以下はHttpMediaTypeNotAcceptableExceptionを発生させた例。

▲HttpMediaTypeNotAcceptableExceptionが発生した場合、DefaultHandlerExceptionResolverがステータスコード406に変換する

 

DefaultHandlerExceptionResolverが想定していない例外が発生した場合、その例外は対策されていない限りNestedServletExceptionにラップされてサーブレットコンテナに渡される。

上記のようなケースでは対策していない限り、スタックトレースが表示されてしまうため開発者が例外ハンドリングを行う必要がある。

 

以下はNullPointerExceptionを発生させた例。

▲NestedServletExceptionにラップされてスタックトレースが表示される

 

ExceptionHandlerExceptionResolver

DefaultHandlerExceptionResolverでハンドリングされない例外やアプリケーション内で発生した例外をハンドリングする場合、ExceptionHandlerExceptionResolverを使用する。

使い方

@ExceptionHandlerアノテーションをつけたメソッドを、「Controller」または「ControllerAdvice」クラスに定義することで例外ハンドリングを行う。

ExceptionHandlerExceptionResolverによって、Spring MVCフレームワーク内で発生した例外と@ExceptionHandlerアノテーションがついたメソッドがマッピングされる

@ExceptionHandlerアノテーションを付与して作成するメソッドには、アノテーションに例外の型を指定する方法や、引数に例外クラスを指定する方法がある。

 

アノテーションに例外の型を指定

アノテーションに例外の型を指定することで、複数の例外をハンドリングできる。

HogeController.java


// NullPointerExceptionとIndexOutOfBoundsExceptionの例外ハンドリング	
@ExceptionHandler({NullPointerException.class, IndexOutOfBoundsException.class}) // ①	
public String handlerException1(RuntimeException e) { // ②	
	return "errors/app_error";
}	

 

@ExceptionHandler({NullPointerException.class, IndexOutOfBoundsException.class}) // ①

上記のようにハンドリングしたい例外の型を複数指定することで、複数の例外ハンドリングを共通して行うことができる。

 

public String handlerException1(RuntimeException e) { // ②

引数にハンドリングしたい例外の親クラスを指定することで、例外オブジェクトを取得できる。

 

引数に例外の型を指定

引数に例外の型を指定することでハンドリングできる。

HogeController.java


// NullPointerExceptionの例外ハンドリング	
@ExceptionHandler // ①	
public String handlerException1(NullPointerException e) {	
	return "errors/app_error";
}	

 

@ExceptionHandler // ①
public String handlerException1(NullPointerException e) {

上記のように引数にハンドリングしたい例外の型を指定することで、対象の例外をハンドリングできる。

 

@ExceptionHandlerを定義する場所

@ExceptionHandlerを付与した例外ハンドリングメソッドは「Controller」または「ControllerAdvice」クラスに定義する。

Controller特有の例外ハンドリングを行う場合は「Controller」クラスに、
アプリケーション全体の共通例外ハンドリングを行う場合は「ControllerAdvice」クラスに定義する

Controllerに定義する例

Controller特有の例外などは以下のようにController内に定義する。

HogeController.java


@Controller		
@RequestMapping(value = "hoge")		
public class HogeController {		
	// 画面表示	
	@GetMapping(value = "/")	
	public String menu() {	
		return "hoge/menu";
	}	
		
	// NestedExceptionの発生	
	@GetMapping(value = "type1")	
	public String type1(String test) {	
		test.length(); // NullPointerExceptionを発生させる
		return "hoge/menu";
	}	
		
	// NullPointerExceptionの例外ハンドリング	
	@ExceptionHandler	
	public String handlerException1(NullPointerException e) {	
		return "errors/app_error";
	}	
}		

 

ControllerAdviceに定義する例

アプリケーション全体の例外ハンドリングは、以下のようにControllerAdvice(コントローラーの共通処理クラス)に定義する。

GlobalExceptionHandler.java


@ControllerAdvice // ①		
public class GlobalExceptionHandler {		
		
	@ExceptionHandler // ②	
	public String handleDataNotFoundException(DataNotFoundException e) { 	
		return "errors/global_error";
	}	
}		

 

@ControllerAdvice // ①

上記アノテーションはコントローラー全体の共通処理を定義するアドバイスクラスであるという意味。

 

@ExceptionHandler // ②
public String handleDataNotFoundException(DataNotFoundException e) {

上記と@ControllerAdviceにより、アプリケーション全体で発生したDataNotFoundExceptionのハンドリングを共通して行うことができる。

 

ResponseStatusExceptionResolver

@ResponseStatusアノテーションを付与した例外クラスを作成する。
カスタマイズした例外クラスがスローされると、上記アノテーションと共に定義したHTTPステータスコードを返却する

ResponseStatusExceptionResolverによって、発生した例外とHTTPステータスコードがマッピングされる
尚、スタックトレースは表示されない。

使い方

以下のように@ResponseStatusを付与した例外クラスを作成する。

ResourceNotFountException.java


package com.example.prototype.exception;	
	
import org.springframework.http.HttpStatus;	
import org.springframework.web.bind.annotation.ResponseStatus;	
	
@ResponseStatus(HttpStatus.NOT_FOUND) // ①	
public class ResourceNotFountException extends RuntimeException{	
	
}	

 

@ResponseStatus(HttpStatus.NOT_FOUND) // ①
public class ResourceNotFountException extends RuntimeException{

上記アノテーションにより、ResourceNotFoundExceptionがアプリケーションからスローされた場合、HTTPステータスコード404が返却される。

 

スポンサーリンク