はじめに
業務でJavaを使うことになったが、少しブランクがあるため、記事としてまとめる。
背景
DBから値を取得するメソッドを使用した際に、検索結果が0件であった場合に
独自のExceptionを発生させるメソッドに出会った。また、このメソッドを使用
し、検索結果が0件であった場合500エラーが表示されてしまう。
今回、上記メソッドを使用した際には、HTTPステータスを404で返却し、
かつ既存の404エラーページではなく専用の404エラー画面を表示したい
という依頼である。
# 内容は一部ぼかしている
方針
特定のメソッドを実行する際に、0件であった場合に自作したExceptionを投げ、
そのExceptionを検知する。最終的に独自のエラー画面を呼び出すようにする。
# それ以外の404の場合は、既存のエラーページを呼び出す。
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クラスはこちら。
public class NotFoundDetailException extends RuntimeException {
private static final long serialVersionUID = 1L;
public NotFoundDetailException(String message) {
super(message);
}
}
NotFoundDetailExceptionを検知する@ControllerAdviceクラスを作成する。
@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に以下設定を追記する。
@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";
}
}
}
@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エラー画面を表示することが出来た。
既存の内容を修正しただけであるため、この方法がベストプラクティスではないとは思う。
ただ、もし参考になる記述があれば幸いである。