Springで404エラー(ページが見つからない)を処理するには?
新人
「Spring Bootで画面を作ったんですが、ブラウザでアクセスしたら『ページが見つかりません』って出てきました…。どうすればいいですか?」
先輩
「なるほど。それはよくある 404エラー ってやつだね。SpringのURLマッピングがうまくいってない可能性があるよ。」
新人
「えっ、それってどういうことですか?URLもちゃんと打ったんですけど…」
先輩
「じゃあ一緒に、Spring 404エラー の原因と仕組みについて見てみよう!」
1. 404エラーとは?
「404エラー」とは、ブラウザからアクセスしたURLに対応するページがサーバー側に存在しないときに返されるHTTPステータスコードです。正式には「HTTP 404 Not Found」と呼ばれます。
たとえば、Spring BootでWebアプリケーションを開発しているときに、指定したURLがコントローラにマッピングされていない場合、このエラーが発生します。
このエラーは、ユーザーにとって「ページが見つからない 原因」がわかりにくく、操作を止めてしまう原因になります。だからこそ、適切に処理しておくことが重要なんです。
2. なぜ404エラーが発生するのか?
404エラーが出る原因の多くは、URLとSpringの@RequestMappingや@GetMappingなどのURLマッピングが一致していないことです。つまり、リクエストされたパスに対する処理が定義されていない状態ですね。
Springでは、DispatcherServletがリクエストを受け取り、対応する@Controllerのメソッドに振り分ける仕組みになっています。
この時、該当するマッピングが存在しないと、Springは「該当のページが見つかりません」として404 Not Foundエラーを返します。
以下に、正しくマッピングされた@Controllerの例を示します。
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class HomeController {
@GetMapping("/home")
public String showHomePage() {
return "home"; // resources/templates/home.html を返す(Thymeleaf)
}
}
上記の例では、ブラウザでhttp://localhost:8080/homeにアクセスすれば、home.htmlが表示されます。
しかし、たとえば/homと打ち間違えたり、Controller側のURL指定が間違っていたりすると、Springは「ページが見つからない」として404エラーを返すのです。
もう一つ例を出してみましょう。URLの指定ミスでエラーになるパターンです。
@Controller
public class AboutController {
@GetMapping("/about")
public String showAboutPage() {
return "about"; // 正しくは /about にアクセス
}
}
この場合、ブラウザで/aboutとアクセスすればOKですが、/aboutusと間違えると404になります。
このように、URLの打ち間違いやマッピングの指定ミスが「Spring 404エラー」の主な原因です。特にSpringでは、URLマッピングが厳密に一致しないとエラーになるため、URL設計には注意が必要です。
3. Springでの404エラーの基本的な処理方法
Spring Bootでは、昔のJavaアプリケーションのようにweb.xmlを使ってエラーページを定義する必要はありません。代わりに、テンプレートファイルとしてエラーページを用意するだけで自動的に処理されます。
たとえば、404エラー用にresources/templates/error/404.htmlというHTMLファイルを用意しておけば、Spring 404エラー 処理方法として、Springが自動的にこのファイルを読み込み表示してくれます。
この方法は非常に簡単で、特別なJavaコードを記述しなくても対応可能です。
4. @ControllerAdviceを使った404エラーのカスタマイズ方法
より柔軟に404エラーを処理したい場合は、@ControllerAdviceを使う方法がおすすめです。@ControllerAdvice 使い方の基本は、例外クラスをハンドリングして、エラーページやメッセージを自由にカスタマイズできる点にあります。
以下は、NoHandlerFoundExceptionを使って、404エラーをキャッチし、自作のエラーページを返す例です。
package com.example.demo.advice;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.stereotype.Controller;
@ControllerAdvice(annotations = Controller.class)
public class ErrorControllerAdvice {
@ExceptionHandler(NoHandlerFoundException.class)
public String handle404(NoHandlerFoundException ex, Model model) {
model.addAttribute("errorMessage", "お探しのページが見つかりませんでした。URLをご確認ください。");
return "error/404"; // templates/error/404.html を表示
}
}
この例では、404エラーが発生したときにerrorMessageという変数をテンプレートに渡し、ユーザーにわかりやすいメッセージを表示できます。
ただし、この方法を使うには、application.propertiesに以下の設定が必要です。
spring.mvc.throw-exception-if-no-handler-found=true
spring.web.resources.add-mappings=false
この設定を入れることで、SpringがNoHandlerFoundExceptionをスローするようになります。
このようにしておけば、コントローラ外で発生した「ページが見つからない」リクエストにも、丁寧なエラーページを表示できます。
5. エラーページの表示用HTML(テンプレート)の作り方
それでは、実際にtemplates/error/404.htmlを作成してみましょう。Spring Bootでは、Thymeleafを使ったテンプレートを作るのが一般的です。
下記は、404カスタムページ Springの例として、初心者でも簡単に作れるHTMLテンプレートです。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>ページが見つかりません</title>
</head>
<body>
<h1>404 Not Found</h1>
<p th:text="${errorMessage}">お探しのページは存在しません。</p>
<a th:href="@{/}">トップページへ戻る</a>
</body>
</html>
th:textを使うことで、先ほどの@ControllerAdviceから渡したエラーメッセージを表示できます。
このテンプレートは、resources/templates/error/404.htmlというパスに置くことで、Springが自動的に読み込んでくれます。
また、カスタマイズの幅も広く、エラーコードごとに500.htmlや403.htmlなどを用意すれば、それぞれのエラーに対応した画面も表示可能になります。
6. 404エラー処理の注意点(ControllerのURLミス、staticリソースなど)
Spring 404エラー 注意点として、初心者が特につまずきやすいポイントは@GetMappingのURL記述ミスや、staticリソースの配置ミスです。
まず、ControllerのURL指定で気をつけるべきなのは、スラッシュ(/)の付け方や、パス名の正確さです。以下のような違いに注意しましょう。
@Controller
public class ContactController {
@GetMapping("contact") // ← 先頭にスラッシュがないとマッピングされない
public String showContact() {
return "contact";
}
}
このように、URLの前に/が付いていない場合、リクエストが意図した通りに届かず、「URL マッピング エラー」として404エラーになることがあります。
次に、画像やCSSなどの静的ファイル(staticリソース)の扱いも注意が必要です。Springでは、resources/static以下に置くことで、ファイルが自動的に公開されます。
たとえば以下のような構成にしたとします:
src/
└─ main/
└─ resources/
└─ static/
├─ css/
│ └─ style.css
└─ images/
└─ logo.png
この場合、style.cssは/css/style.cssでアクセス可能ですが、パスを間違えると404になります。たとえば以下のようにHTMLで指定するのが正しいです。
<link rel="stylesheet" href="/css/style.css">
<img src="/images/logo.png" alt="ロゴ画像">
ファイルがtemplatesにあると思い込み、/templates/images/logo.pngのように書くと「ページが見つからない」という結果になります。これはSpring 404エラー 注意点として非常に多いミスです。
7. 現場でよくある404エラーとその原因
実際の開発現場でも、初心者だけでなく経験者も404エラーに悩まされることがあります。ここでは、404エラー 原因 特定に役立つ典型的なパターンを紹介します。
- Controllerに
@GetMappingを記述したが、クラスに@Controllerをつけ忘れた - リターン値とテンプレートファイル名が一致していない(例:
return "about";に対してabout.htmlが存在しない) application.propertiesで静的ファイルのマッピング設定を無効化してしまった- リクエストパスに余計な
/やパラメータが付いていてマッピングできない - Gradleの依存関係が正しく設定されていない(特に
spring-boot-starter-thymeleafなど)
特に、Gradleの設定でテンプレートエンジンが入っていないと、テンプレートが描画できずに「ページが見つからない」となるケースがあります。依存関係は以下のように定義しましょう。
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
}
また、テンプレートファイルはsrc/main/resources/templates配下に正しく配置する必要があります。場所が違うと、存在していても表示できず、Springは404を返してしまいます。
8. デバッグのコツとログの見方(初心者向け)
最後に、「404エラー 原因 特定」を行うためのログの見方や、デバッグのポイントを紹介します。404エラーは目に見えないミスが原因であることが多いため、地道な確認が大切です。
まず、application.propertiesに以下のようなログ設定を追加することで、リクエストの詳細を確認できます。
logging.level.org.springframework.web=DEBUG
logging.level.org.springframework.boot.autoconfigure.web=DEBUG
これにより、SpringがどのURLに対してどのような処理をしているかがログに出力されるようになります。
Pleiadesで開発している場合、コンソールに以下のような出力が表示されます。
2025-09-08 13:20:22.123 DEBUG ... DispatcherServlet - GET "/contact", parameters={}
2025-09-08 13:20:22.125 WARN ... No mapping for GET /contact
このようなログが出ていれば、「/contact」に対するマッピングが存在しないことが明確です。この情報をもとに、ControllerのURLやHTMLのリンクを見直しましょう。
また、ブラウザでF12キーを押すことで開ける「開発者ツール」でも、リクエストURLやレスポンスステータス(404など)を確認できます。
ログを読むことに慣れるまでは難しく感じるかもしれませんが、404エラーを素早く解決するには非常に重要なスキルです。
URLが正しいか、テンプレートファイルがあるか、Controllerが正しくマッピングされているか。これらを一つひとつ確認しながら、原因を特定していきましょう。