WEBアプリケーションを作成する際、処理の途中でエラーが発生した場合に、特定のエラーページに遷移してエラーメッセージを表示したり、エラーログを出力したりする必要がある。
Spring BootのWEBアプリケーションにおいては、処理の途中で例外が発生した場合は、何もしなくても「resources/templates/error.html」に画面遷移するようになっている。また、RequestDispatcherFilterやErrorControllerによって、エラー時の画面遷移先を変えたり、エラーメッセージの文言を変えたり、エラーログの出力機能を追加したりすることもできる。
今回は、Filter内でエラーが発生した場合のサンプルプログラムを通して、Spring Bootの例外処理について共有する。Spring Bootデフォルトのエラー処理・RequestDispatcherを利用したエラー処理・ErrorControllerを利用したエラー処理の3種類について共有する。
前提条件
以下の記事のSpring BootのWEB画面へのフィルタ追加が完了していること。
やってみたこと
Spring Bootデフォルトのエラー処理
今回は、フィルタ処理内(DemoFilter2.java)でエラーを発生させ、エラーログを出力後、エラー画面(error.html)に遷移するサンプルプログラムを作成した。
また、今回変更したプログラムの内容は以下の通り。DemoFilter2.javaでは、エラーログを出力後に発生した例外をそのままスローしているだけとなっているが、これだけで「error.html」に遷移するようになっている。
package com.example.demo;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.servlet.Filter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import java.io.IOException;
public class DemoFilter2 implements Filter {
//ログ出力のためのクラス
private static Log log = LogFactory.getLog(DemoFilter2.class);
/**
* 処理(本プログラムではコントローラクラスのメソッド)の前後にログ出力
* を行うフィルタ定義
* @param request サーブレットリクエスト
* @param response サーブレットレスポンス
* @param chain フィルタチェイン
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response
, FilterChain chain) throws IOException, ServletException {
log.debug("DemoFilter2 started.");
try{
//ここでArithmeticExceptionを強制的に発生させる
int i = 1 / 0;
}catch(Exception e){
//エラーログを出力
log.error(e.toString());
//例外をスローすると、resources/templates/error.htmlに遷移
throw e;
}
//一連の処理(本プログラムではコントローラクラスのメソッド)を実行
chain.doFilter(request, response);
log.debug("DemoFilter2 ended.");
}
}
<!DOCTYPE html>
<html lang="ja">
<meta charset="UTF-8">
<title>error page</title>
</head>
<body>
Error Occured!!
<p>システムエラーが発生しました、ログを確認してください。</p>
</body>
</html>
その他のソースコード内容は、以下のサイトを参照のこと。
https://github.com/purin-it/java/tree/master/spring-boot-filter2/default/demo
その後、Spring Bootアプリケーションを起動し、「http:// (ホスト名):(ポート番号)」とアクセスした結果は以下の通りで、エラー画面(error.html)に遷移する。

また、その際のコンソール・ログ出力結果は以下の通りで、下図赤枠部分で、「DemoFilter2.java」の開始ログ出力後に、エラーログが出力されているのが確認できる。
●ログファイル(C:/work/logs/demo.log)

RequestDispatcherによるエラー処理
今回は、RequestDispatcherによってエラー画面に遷移するコントローラのメソッドを、パラメータを付与した形で呼び出すサンプルプログラムを作成した。
また、今回変更したプログラムの内容は以下の通り。DemoFilter2.javaでは、エラーログを出力後に、RequestDispatcherによって、「/error_filter」のパス(DemoController.javaに記載)に遷移するようになっている。また、その際にexceptionというパラメータを渡すようにしていて、画面上に発生したエラー内容が表示できるようになっている。
package com.example.demo;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.servlet.Filter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.RequestDispatcher;
import java.io.IOException;
public class DemoFilter2 implements Filter {
//ログ出力のためのクラス
private static Log log = LogFactory.getLog(DemoFilter2.class);
/**
* 処理(本プログラムではコントローラクラスのメソッド)の前後にログ出力を行うフィルタ定義
* @param request サーブレットリクエスト
* @param response サーブレットレスポンス
* @param chain フィルタチェイン
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response
, FilterChain chain) throws IOException, ServletException {
log.debug("DemoFilter2 started.");
try{
//ここでArithmeticExceptionを強制的に発生させる
int i = 1 / 0;
}catch(Exception e){
//エラーログを出力
log.error(e.toString());
StackTraceElement[] errors = e.getStackTrace();
for(StackTraceElement element : errors){
log.error(element);
}
//RequestMappingが「/error_filter」であるコントローラのメソッド
//(DemoController.java、errorFilter)を呼び出す
RequestDispatcher rd = request.getRequestDispatcher(
"/error_filter?exception=" + e.toString());
rd.forward(request, response);
return;
}
//一連の処理(本プログラムではコントローラクラスのメソッド)を実行
chain.doFilter(request, response);
log.debug("DemoFilter2 ended.");
}
}
package com.example.demo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class DemoController {
/**
* 初期表示を行う
* @return 初期表示画面のパス
*/
@RequestMapping("/")
public String index(){
return "index";
}
/**
* フィルタ内でエラーが発生した場合の画面遷移を行う
* @param exception パラメータとして渡された例外
* @param mav ModelAndViewオブジェクト
* @return ModelAndViewオブジェクト
*/
@RequestMapping("/error_filter")
public ModelAndView errorFilter(@RequestParam("exception") String exception
, ModelAndView mav){
//resources/templates下のerror.htmlに遷移
mav.setViewName("error");
//error.htmlに埋め込むパラメータ「errClass」に、
//パラメータとして渡された例外を埋め込む
mav.addObject("errClass", exception);
return mav;
}
}
<!DOCTYPE html>
<html lang="ja" xmlns:th="http://www.thymeleaf.org">
<meta charset="UTF-8">
<title>error page</title>
</head>
<body>
Error Occured!!
<p>エラーが発生しました、ログを確認してください。</p>
<p th:text="'発生したエラー: ' + ${errClass}">
ここに発生したエラーのクラス名が設定されます
</p>
</body>
</html>
その他のソースコード内容は、以下のサイトを参照のこと。
https://github.com/purin-it/java/tree/master/spring-boot-filter2/requestdispatcher/demo
その後、Spring Bootアプリケーションを起動し、「http:// (ホスト名):(ポート番号)」とアクセスした結果は以下の通りで、エラー画面(error.html)に遷移し、パラメータで渡したエラー内容が表示されることが確認できる。

また、その際のコンソール・ログ出力結果は以下の通りで、下図赤枠部分で、「DemoFilter2.java」の開始ログ出力後に、エラーログが出力されているのが確認できる。
●ログファイル(C:/work/logs/demo.log)

ErrorControllerによるエラー処理
今回は、フィルタ処理内(DemoFilter2.java)でエラーを発生させた後で、ErrorControllerクラスをimplementsしたクラス内(DemoExceptionController.java)で、エラーログの出力とエラー画面(error_filter.html)への遷移を行うサンプルプログラムを作成した。
また、今回変更したプログラムの内容は以下の通り。DemoFilter2.javaでは、エラーログを出力後にRuntimeException例外をスローしていて、これがruntimeExceptionHandlerメソッド(DemoExceptionController.javaに記載)で処理できるようになっている。
package com.example.demo;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.servlet.Filter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import java.io.IOException;
public class DemoFilter2 implements Filter {
//ログ出力のためのクラス
private static Log log = LogFactory.getLog(DemoFilter2.class);
/**
* 処理(本プログラムではコントローラクラスのメソッド)の前後にログ出力を行うフィルタ定義
* @param request サーブレットリクエスト
* @param response サーブレットレスポンス
* @param chain フィルタチェイン
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response
, FilterChain chain) throws IOException, ServletException {
log.debug("DemoFilter2 started.");
try{
//ここでArithmeticExceptionを強制的に発生させる
int i = 1 / 0;
}catch(Exception e){
throw new RuntimeException(e);
}
//一連の処理(本プログラムではコントローラクラスのメソッド)を実行
chain.doFilter(request, response);
log.debug("DemoFilter2 ended.");
}
}
package com.example.demo;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* RuntimeException発生時の処理を実装
* 通常、SpringBootアプリケーションでエラーが発生した場合は resources/templates/error.html に
* 遷移するようになっているが、その遷移先を変えたり、文言追加オブジェクト等を追加するには、
* このクラスのように、ErrorControllerクラスをimplementsしたクラスを作成する
*/
@Controller
public class DemoExceptionController implements ErrorController {
/**
* エラーが発生した場合の画面遷移
* @param e RuntimeException例外
* @param mav ModelAndViewオブジェクト
* @return ModelAndViewオブジェクト
*/
@RequestMapping("/error")
@ExceptionHandler(RuntimeException.class)
public ModelAndView runtimeExceptionHandler(RuntimeException e, ModelAndView mav){
mav.setViewName("error_filter");
mav.addObject("errMsg", "システムエラーが発生しました、ログを確認してください。");
return mav;
}
/**
* エラーパスを取得
* (このメソッドを追加しないとコンパイルエラーになるため追加)
* @return エラーパス
*/
@Override
public String getErrorPath() {
return "";
}
}
<!DOCTYPE html>
<html lang="ja" xmlns:th="http://www.thymeleaf.org">
<meta charset="UTF-8">
<title>error page</title>
</head>
<body>
Error Occured!!
<p th:text="${errMsg}">ここに発生したエラーメッセージが設定されます</p>
</body>
</html>
その他のソースコード内容は、以下のサイトを参照のこと。
https://github.com/purin-it/java/tree/master/spring-boot-filter2/errorcontroller/demo
その後、Spring Bootアプリケーションを起動し、「http:// (ホスト名):(ポート番号)」とアクセスした結果は以下の通りで、エラー画面(error_filter.html)に遷移する。

また、その際のコンソール・ログ出力結果は以下の通りで、下図赤枠部分で、「DemoFilter2.java」の開始ログ出力後に、エラーログが出力されているのが確認できる。
●ログファイル(C:/work/logs/demo.log)

要点まとめ
- Spring BootのWEBアプリケーションにおいては、処理の途中で例外が発生した場合は、何もしなくても「resources/templates/error.html」に画面遷移するようになっている。
- RequestDispatcherクラスのオブジェクトでforwardすることによって、例外処理を行うメソッドに遷移することができる。
- ErrorControllerをimplementsしたクラスを利用した例外処理も行える。











