| この記事の要点 |
|
エラー画面
Spring Boot アプリにアクセスして 404 / 500 等のエラーが発生したとき、以下のような無味乾燥なページが表示されます:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Sat May 15 12:34:56 JST 2024
There was an unexpected error (type=Not Found, status=404).
原因
ここでは Spring Boot の Servlet / Spring MVC 自動構成を扱います。Spring Framework 単体や WebFlux の設定と同一視しません。Boot の既定の BasicErrorController が通常 /error を処理し、HTML の解決先がない場合に Whitelabel が使われます。「no explicit mapping」は元URLの controller が必ず存在しない、という診断ではありません。これは:
- 独自の
/errorコントローラが定義されていない - 適用できる独自の error view や status 別エラーページが解決されていない
- 結果として Spring Boot 内蔵の素っ気ない HTML が表示される
まず元URL・HTTP method・context path / servlet path と実際の HTTP status を確認します。404 は URL マッピングと controller の登録・component scan 範囲(通常は @SpringBootApplication のパッケージ配下)、静的資源の配置を分けて確認します。500 は対応する時刻の例外ログで原因を絞ります。401 / 403 やログインへのリダイレクトは認証・認可も確認し、アクセス拒否を 404 と決め付けません。画面の置換や Whitelabel の無効化は障害原因の修正とは別です。ログ全文・トークン・接続文字列等を公開しないでください。
対処1: error.html を配置(Thymeleaf)
Thymeleaf とその view resolver が構成済みの場合は src/main/resources/templates/error.html を error view として解決できます。テンプレートを置くだけで Thymeleaf が導入されたり、元URLの処理が追加されたりはしません。次の旧テンプレートは trace / message を表示するため、公開環境では詳細を渡さず、スタックトレース・内部例外文を外へ出さないでください。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title th:text="${status} + ' - ' + ${error}">エラー</title>
<link rel="stylesheet" href="/css/style.css">
</head>
<body>
<div class="error-container">
<h1 th:text="${status}">500</h1>
<h2 th:text="${error}">Internal Server Error</h2>
<p th:if="${message}" th:text="${message}"></p>
<div th:if="${trace}" class="trace">
<pre th:text="${trace}"></pre>
</div>
<a href="/">トップに戻る</a>
</div>
</body>
</html>
ステータスコードごとに別ファイルを置くと自動で振り分けられます:
src/main/resources/templates/error/
├── 404.html ← 404 専用
├── 500.html ← 500 専用
└── ...
src/main/resources/templates/
└── error.html ← その他すべて
対処2: ErrorController を実装
次は旧コードの抜粋です。javax.servlet は Boot 2.x 世代で、Boot 3.x は jakarta.servlet を使います。Map / HashMap / Date の import も省略されています。Boot 2.x内でも世代差があり、2.3/2.4等は非推奨でもgetErrorPath()の実装が必要です。掲載クラスはそのままでは未実装エラーになり、2.5で同メソッドは削除されています。非推奨化と実装不要を混同せず、server.error.pathの設定とも区別してください。JSON 内の status フィールドは HTTP status を設定しません。実装時は ERROR_STATUS_CODE を検証し、ResponseEntity.status(...) 等で応答にも反映する必要があります。通常リクエストとして /error を直接開くと error 属性が無い場合もあり、ERROR dispatch と区別します。ERROR_MESSAGE や元URIをそのまま公開せず、安全な応答項目を選んでください。Boot 4 では ErrorController は org.springframework.boot.webmvc.error.ErrorController に移っています。
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
@RestController
public class CustomErrorController implements ErrorController {
@RequestMapping("/error")
public Map<String, Object> handleError(HttpServletRequest request) {
Integer status = (Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
String message = (String) request.getAttribute(RequestDispatcher.ERROR_MESSAGE);
String path = (String) request.getAttribute(RequestDispatcher.ERROR_REQUEST_URI);
Map<String, Object> response = new HashMap<>();
response.put("status", status);
response.put("error", message);
response.put("path", path);
response.put("timestamp", new Date());
return response;
}
}
対処3: @ControllerAdvice で例外を catch
次は MVC の例外処理の抜粋で、NotFoundException / log はアプリ側定義、ResponseEntity / HttpStatus / AccessDeniedException 等の import は別途必要です。record は Java 16 以降の構文です。Spring Security の filter chain で発生する認証・認可例外を ControllerAdvice がすべて捕捉するわけではなく、AuthenticationEntryPoint / AccessDeniedHandler の役割と区別します。また汎用 Exception ハンドラで本来 404 等の例外を 500 に変えないよう対象と優先順位を確認し、ex.getMessage() の機密情報を応答へ流さないでください。
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(NotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(NotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse("NOT_FOUND", ex.getMessage()));
}
@ExceptionHandler(AccessDeniedException.class)
public ResponseEntity<ErrorResponse> handleForbidden(AccessDeniedException ex) {
return ResponseEntity.status(HttpStatus.FORBIDDEN)
.body(new ErrorResponse("FORBIDDEN", ex.getMessage()));
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleAll(Exception ex) {
log.error("Unexpected error", ex);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("INTERNAL", "サーバエラーが発生しました"));
}
public record ErrorResponse(String code, String message) {}
}
対処4: Whitelabel を無効化
Boot 2.x / 3.x で server.error.whitelabel.enabled=false にすると既定の Whitelabel view を無効化しますが、独自処理だけになる保証はなく、Servlet コンテナのエラー画面へ戻る場合があります。次の旧 properties はそのままコピーしないでください。値の後の # は行末コメントとして除外されないため、注釈を独立したコメント行へ移します。Boot 3.5 の属性出力の選択肢は never / always / on_param で、on_trace_param はその選択肢にありません。on_param は要求側が詳細出力を求められる条件であり、公開環境の安全策として選びません。Boot 4 の該当キーは spring.web.error.* なので server.error.* を全版共通と扱いません。パス変更時は固定の /error マッピングとの不一致にも注意します。
# application.properties
server.error.whitelabel.enabled=false
# エラー詳細表示の制御
server.error.include-stacktrace=on_param # never / always / on_param / on_trace_param
server.error.include-message=on_param # never / always / on_param
server.error.include-binding-errors=on_param
server.error.include-exception=false
# /error パスを変更
server.error.path=/api-error
本番 vs 開発でのエラー詳細制御
次の旧例でも値の後の # 注釈は別行へ移します。例えば # 機密漏洩防止 を独立した行にし、設定行は server.error.include-stacktrace=never だけにします。Boot 2.x / 3.x の例で、使用中の profile と有効設定を確認し、開発用 always を公開環境へ適用しません。Boot 3.5 の include-binding-errors も公開環境では never とし、独自 controller / advice が返す詳細はこれらのプロパティだけでは抑止できません。
# application-dev.properties (開発)
server.error.include-stacktrace=always
server.error.include-message=always
server.error.include-exception=true
# application-prod.properties (本番)
server.error.include-stacktrace=never # 機密漏洩防止
server.error.include-message=never
server.error.include-exception=false
404 だけを別ハンドラに
次はハンドラ未発見の旧例で、すべての 404 を捕捉する例ではありません。Spring Framework 6.1 以降は NoHandlerFoundException を投げる動作が既定となり、旧 throw-exception-if-no-handler-found 設定を一律に追加する必要はありません。Boot 3.5 の既定の静的資源マッピング /** に一致して資源が無い場合は NoResourceFoundException となり、別の例外です。add-mappings=false は静的資源配信自体を無効化するので、404 対策として無条件に適用しません。MVC へ届く前の拒否や別 servlet の 404 もこの Advice の対象と同じではありません。
// 404 専用ハンドラ
@ControllerAdvice
public class NotFoundHandler {
@ExceptionHandler(NoHandlerFoundException.class)
public ModelAndView handle404(NoHandlerFoundException ex) {
ModelAndView mav = new ModelAndView("error/404");
mav.setStatus(HttpStatus.NOT_FOUND);
return mav;
}
}
// application.properties で 404 例外を投げるように
// spring.mvc.throw-exception-if-no-handler-found=true
// spring.web.resources.add-mappings=false
JSON / HTML を自動切替
この同名ErrorControllerにも上記のBoot 2.x内のgetErrorPath()実装条件が及びます。またMap.ofはJava 9以降で、下記のstatusのスコープを補うだけではJava 8対応にはなりません。
既定の BasicErrorController にも HTML とその他の応答の分岐があります。次の旧例はその考え方の未完成な抜粋で、JSON メソッドの status は HTML メソッドのローカル変数であり参照できず、このままではコンパイルできません。JSON 側でも status の取得・欠落時処理と HTTP 応答への反映が必要です。独自 ErrorController は既定処理を置き換えるため、既存クラスと同名の2例を同時導入せず、エラー時の status / Content-Type と直接アクセス時を分けて確認します。
@Controller
public class CustomErrorController implements ErrorController {
@RequestMapping(value = "/error", produces = MediaType.TEXT_HTML_VALUE)
public String html(HttpServletRequest request, Model model) {
// HTML テンプレートで返す
Integer status = (Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
model.addAttribute("status", status);
return "error";
}
@RequestMapping(value = "/error")
@ResponseBody
public Map<String, Object> json(HttpServletRequest request) {
// JSON で返す(API リクエスト用)
// ...
return Map.of("status", status, "error", "...");
}
}
関連
- HandlerInterceptor: MVC ハンドラ処理の範囲で利用する。Security filter の拒否や全 ERROR dispatch を必ず通る仕組みではない
- Spring Security の AccessDeniedHandler: 認可拒否の処理。未認証時の AuthenticationEntryPoint と区別する。元の REQUEST とエラー表示用の ERROR dispatch は別に認可され得るため、適用中の filter chain と dispatcher 条件を確認し、認証解除や全URL公開で表示だけ直さない
- RestControllerAdvice: API 専用の @ControllerAdvice
- ProblemDetail (RFC 9457): Spring 6 / Boot 3 で標準化されたエラーレスポンス形式
- Actuator: 健全性チェック / エラー統計の収集
公式仕様の確認先:Spring Boot3.5 Servletのエラー処理、Boot4.0プロパティ、Java Propertiesの構文(2026-10-28確認)。画面・設定・コードは対象版と各例の前提条件を照合してください。
子ページはありません
- java.lang.IllegalStateException: CGLIB is required to process @Configuration classes
- Error creating bean with name 'org.springframework.aop.config.internalAutoProxyCreator': Instantiation of bean failed; nested exception is java.lang.NoClassDefFoundError: Could not initialize class org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
- No mapping found for HTTP request with URI ... in DispatcherServlet with name ...
- An internal error occurred during: "Building UI model". com/google/common/base/Function
- No identifier specified for entity : ...
- org.hibernate.hql.internal.ast.QuerySyntaxException: table_name is not mapped
- No compiler is provided in this environment
- java.sql.SQLException: The server time zone value ' ... ' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone
- Caused by: java.lang.RuntimeException: Executing an update/delete query
- Not supported for DML operations
- Field ... required a bean of type ... that could not be found.
- Annotation-specified bean name 'xxxController' for bean class [com.xxx.controller.xxxController] conflicts with existing, non-compatible bean definition of same name and class [com.xxx.xxxController]
- Whitelabel Error Page This application has no explicit mapping for /error, so you are seeing this as a fallback.
- Exception in thread "main" java.lang.UnsupportedClassVersionError
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 3Dグラフィックスのソフト一覧|Blender・Metasequoiaと用途別の選び方
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- Visual Studio「デザイナーを表示できません」エラーの原因と対処 2026-10-28 12:06:00
- SSH 認証に失敗しました。再試行してください の対処 2026-10-28 12:06:00
- SSH2 秘密鍵の読み込みに失敗しました の原因と対処 2026-10-28 12:06:00
- TeraTerm のよくあるエラーと対処法完全ガイド — Connection refused / 2026-10-28 12:06:00
- Visual Studio エラー一覧|コンパイルエラー・警告の確認方法と対処 2026-10-28 11:39:57
- Whitelabel Error Page の原因と消し方|Spring Boot のエラーページ 2026-10-28 11:39:57
- Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法 2026-10-28 11:39:57
- SQL WHERE 句完全ガイド 2026-10-28 11:39:57
- SQL JOIN 完全ガイド (INNER/LEFT/RIGHT/FULL OUTER) 2026-10-28 11:39:57
- tomcat の起動 / 停止ログと catalina.log・catalina.out の違い 2026-10-28 10:24:23
- Tomcat の起動確認方法 5 つ|localhost:8080・ポート・プロセス・ログ 2026-10-28 10:24:23
- Oracle 19c COMMITの使い方: 暗黙コミット・自動確定・応答不明時の確認 2026-10-28 09:59:09
- Oracle 19c DELETE文|削除対象の確認・COMMIT前の判断・ROLLBACKの条件 2026-10-28 09:59:09
- Oracle 19c INSERT文|INSERT ALL・SELECT・RETURNINGとMERGEの使い分け 2026-10-28 09:59:09
- Oracle 19cのトランザクション制御|COMMIT・ROLLBACK・分離レベルと接続設定 2026-10-28 09:59:09