Spring Bootで例外処理
エラーページの表示
spring bootでは、Thymeleafを使用している場合、デフォルトで例外発生時にはsrc/main/resources/template/error.html
に遷移する。
上記のパスにファイルが存在しない場合は、springが準備したWhitelabel Error Page
に遷移する。
ControllerAdviceを使用
- クラスに
@ControllerAdvice
をつけることで全てのコントローラーを対象に例外処理を行うことができる。 - このクラス内の
@ExceptionHandler
をつけたメソッドで、実際に例外発生時に行う処理を記述する。 @ExceptionHandler
の引数に指定した例外がスローされた場合にメソッドが実行される。- 引数に与える例外クラスは複数記述することができる。
- 例外の親クラスを引数に設定した場合は、その例外クラスの子の例外が発生した場合も捕捉される。
(例:引数にRuntimeException.classを指定時にNullPointerExceptionが発生しても例外処理メソッドが実行される)
以下の実装例では、IllegalArgumentExceptionが発生した際に、src/main/resources/template/exception/runtime.htmlに遷移する。
@ControllerAdvice public class ControllerAdviceSample { @ExceptionHandler({ IllegalArgumentException.class }) public String testExceptionHandle(IllegalArgumentException e, Model model) { String stackTrace = ExceptionUtils.getStackTrace(e); model.addAttribute("message0", e); model.addAttribute("message1", stackTrace); return "/exception/runtime"; } }
フィルターで発生した例外を捕捉する
上のControllerAdviceでは、フィルターで発生した例外を処理することができない。
フィルターで発生した例外を処理するためには、フィルターで発生した例外を捕捉するためのフィルターを作成する。
例外捕捉用のフィルターの実装例を以下に示す。
public class ExceptionHandleFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { try { // 後続のフィルターを実行する chain.doFilter(request, response); } catch (Throwable e) { // 例外発生時の処理を記述する // サンプルではRequestMappingが「/error_filter」であるコントローラのメソッド // を呼び出してエラー画面へ遷移している RequestDispatcher dispatcher = request.getRequestDispatcher("/error_filter"); request.setAttribute("exception", e); dispatcher.forward(request, response); } } }
@Controller public class SampleFilterErrorController { // フィルターで例外発生時に呼び出されるメソッド。 // src/main/resources/template/exception/filter.htmlに遷移する @RequestMapping(value = "/error_filter") public String result(Model model, HttpServletRequest req) { Exception ex = (Exception) req.getAttribute("exception"); String stackTrace = ExceptionUtils.getStackTrace(ex); model.addAttribute("message0", ex.toString()); model.addAttribute("message1", stackTrace); return "/exception/filter"; } }
このフィルターは、後続のフィルターで発生した例外しか捕捉することが出来ないため、
フィルターで1番最初に実行されるように別途Configクラスに設定が必要。
setOrder(int)に設定する数字は負数でも可。値が小さい順にFilterの順序付けがされる。
順序を指定しなかった場合は、順序は不定となる。
@Configuration public class SampleConfig { // フィルターをDIコンテナに登録する @Bean public Filter sampleFilter() { return new SampleFilter(); } // 例外処理フィルターをDIコンテナに登録する @Bean public Filter exceptionHandleFilter() { return new ExceptionHandleFilter(); } @Bean public FilterRegistrationBean<Filter> sampleFilter0(Filter sampleFilter) { FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<Filter>(sampleFilter); bean.addUrlPatterns("/*"); bean.setOrder(2); return bean; } @Bean public FilterRegistrationBean<Filter> exceptionHandleFilter0(Filter exceptionHandleFilter) { FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<Filter>(exceptionHandleFilter); bean.addUrlPatterns("/*"); // フィルターの実行順序を1に設定する bean.setOrder(1); return bean; } }