0
0

More than 1 year has passed since last update.

【Spring】特定のExceptionを発生させた際に独自のエラー画面を表示したい

Last updated at Posted at 2022-08-25

はじめに

業務でJavaを使うことになったが、少しブランクがあるため、記事としてまとめる。

背景

DBから値を取得するメソッドを使用した際に、検索結果が0件であった場合に
独自のExceptionを発生させるメソッドに出会った。また、このメソッドを使用
し、検索結果が0件であった場合500エラーが表示されてしまう。

今回、上記メソッドを使用した際には、HTTPステータスを404で返却し、
かつ既存の404エラーページではなく専用の404エラー画面を表示したい
という依頼である。
# 内容は一部ぼかしている

方針

特定のメソッドを実行する際に、0件であった場合に自作したExceptionを投げ、
そのExceptionを検知する。最終的に独自のエラー画面を呼び出すようにする。
# それ以外の404の場合は、既存のエラーページを呼び出す。

呼び出し元.java
int id = 1;

// idを元にDBから値を取得し、TestDetailに格納する(取得出来なければ独自のExceptionを投げる)
TestDetail detail = TestDetailDao.fetchTestData(id)
    .orElseThrow(() -> new NotFoundDetailException(
        messageSource.getMessage("detail.notfound.log", new String[]{String.valueOf(id)}, Locale.JAPAN)));

自作したExceptionクラスはこちら。

NotFoundDetailException.java
public class NotFoundDetailException extends RuntimeException {

    private static final long serialVersionUID = 1L;

    public NotFoundDetailException(String message) {
        super(message);
    }
}

NotFoundDetailExceptionを検知する@ControllerAdviceクラスを作成する。

ErrorAdvice.java
@ControllerAdvice
@Slf4j
public class ErrorAdvice {

  @ExceptionHandler(NotFoundDetailException.class)
  // 発生させたいHTTPステータスと、発生理由を設定(発生理由は別途使用)
  @ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "detail not found")
  @ResponseBody
  public void NotFoundJobOfferExceptionHandler(NotFoundDetailException e) {
    log.warn(e.getMessage(), e);
  }
}

エラー画面に遷移させるControllerに以下設定を追記する。

ErrorController.java

@Controller
@RequestMapping("/error")
public class ErrorController implements org.springframework.boot.web.servlet.error.ErrorController {

  @Deprecated
  @Override
  public String getErrorPath() {
    return "error";
  }

  @RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
  public String myErrorHtml(HttpServletRequest req, ModelAndView mav) {
    HttpStatus status = getHttpStatus(req);
    switch (status) {
      case NOT_FOUND:
        // ここで上記で設定したエラー理由のreasonを元に判定(Enumクラスは以下に記載)
        Object errorReason = req.getAttribute(RequestDispatcher.ERROR_MESSAGE);
        String errorPath = NotFoundReasonType.getErrorPageByReason(errorReason.toString());
        return errorPath;
      default:
        return "error/xxx";
    }
  }
}
NotFoundReasonType.java
@Getter
public enum NotFoundReasonType {

  DETAIL_NOT_FOUND("detail not found", "error/notFoundDetail"),
  DEFAULT("", "error/404");

  private String errorReason;

  private String errorPath;

  private NotFoundReasonType(String errorReason, String errorPath) {
      this.errorReason = errorReason;
      this.errorPage = errorPath;
  }

  public static String getErrorPageByReason(String errorReason) {

    NotFoundReasonType targetEnum = Arrays.stream(NotFoundReasonType.values())
      .filter(x -> x.getErrorReason().equals(errorReason))
      .findFirst()
      .orElse(DEFAULT);

    return targetEnum.getErrorPath();
  }    
}

上記で、特定のExceptionが発生した場合に自作の404エラー画面を表示することが出来た。
既存の内容を修正しただけであるため、この方法がベストプラクティスではないとは思う。
ただ、もし参考になる記述があれば幸いである。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0