| この記事の要点 |
|
コンテキストパスとは
Java EE / Jakarta EE の Web アプリは Tomcat 等のサーブレットコンテナにデプロイすると /myapp のようなコンテキストパスが前置されます。これを動的に取得しないと、デプロイ先が変わった瞬間にリンク・フォーム・リダイレクトが全滅します。
| デプロイ形態 | URL 例 | contextPath |
|---|---|---|
Tomcat の webapps/myapp.war | http://host/myapp/login | /myapp |
| Tomcat ROOT.war | http://host/login | 空文字 "" |
| Spring Boot 組込 Tomcat 既定 | http://host/login | 空文字 |
Spring Boot で server.servlet.context-path=/api | http://host/api/login | /api |
Servlet で取得
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res)
throws IOException {
// コンテキストパス取得
String ctx = req.getContextPath(); // 例: "/myapp"
// リダイレクト先を組み立て
res.sendRedirect(ctx + "/login"); // → /myapp/login
// 関連メソッド
String servletPath = req.getServletPath(); // 例: "/hello"
String pathInfo = req.getPathInfo(); // 例: "/users/3"
String requestURI = req.getRequestURI(); // 例: "/myapp/hello/users/3"
String contextURL = req.getRequestURL().toString();
}
}
JSP で取得 (EL / JSTL)
<%-- EL で取得(推奨) --%>
<a href="${pageContext.request.contextPath}/login">ログイン</a>
<%-- フォーム --%>
<form action="${pageContext.request.contextPath}/user/save" method="post">
...
</form>
<%-- JSTL <c:url> もコンテキストパスを自動付与 --%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<a href="<c:url value='/login'/>">ログイン</a>
<%-- 変数に格納して使い回す --%>
<c:set var="ctx" value="${pageContext.request.contextPath}" />
<link rel="stylesheet" href="${ctx}/css/app.css" />
<script src="${ctx}/js/app.js"></script>
Spring MVC / Spring Boot
// 1. 設定値として注入
@Service
public class UrlBuilder {
@Value("${server.servlet.context-path:}")
private String contextPath; // 設定が無い場合は空文字
public String buildUrl(String path) {
return contextPath + path;
}
}
// 2. HttpServletRequest 経由
@GetMapping("/hello")
public String hello(HttpServletRequest req, Model model) {
model.addAttribute("ctx", req.getContextPath());
return "hello";
}
// 3. ServletUriComponentsBuilder(フル URL)
@GetMapping("/api/me")
public String me() {
String fullUrl = ServletUriComponentsBuilder.fromCurrentContextPath()
.path("/users/me")
.build()
.toUriString();
return fullUrl; // 例: http://localhost:8080/api/users/me
}
application.properties での設定:
# Spring Boot 2.x / 3.x 共通
server.servlet.context-path=/api
# ポート変更も合わせて
server.port=8080
# 旧 Spring Boot 1.x
server.context-path=/api
Thymeleaf で取得
Thymeleaf は @{/...} 構文で自動的にコンテキストパスを前置します。これが最も安全:
<!-- @{} を使えば contextPath は自動付与 -->
<a th:href="@{/login}">ログイン</a>
<form th:action="@{/user/save}" method="post"> ... </form>
<!-- 静的リソースも同じ -->
<link rel="stylesheet" th:href="@{/css/app.css}" />
<script th:src="@{/js/app.js}"></script>
<!-- パスパラメータ -->
<a th:href="@{/user/{id}(id=${user.id})}">詳細</a>
<!-- クエリパラメータ -->
<a th:href="@{/search(q=${keyword},page=1)}">検索</a>
<!-- どうしても文字列で欲しいとき -->
<span th:text="${#httpServletRequest.contextPath}">[ctx]</span>
JavaScript 側へ渡す
SPA 化していなくても、AJAX 呼び出しのために JS にコンテキストパスを渡す必要があります:
<!-- JSP -->
<script>
window.CONTEXT_PATH = '${pageContext.request.contextPath}';
</script>
<!-- Thymeleaf -->
<script th:inline="javascript">
window.CONTEXT_PATH = /*[[@{/}]]*/ '/';
</script>
<script>
// 利用側
fetch(window.CONTEXT_PATH + '/api/users')
.then(r => r.json())
.then(console.log);
</script>
web.xml での設定
従来の Servlet コンテナ (Tomcat 単体) では、コンテキストパスは war 名 or META-INF/context.xml で指定:
<!-- META-INF/context.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/myapp" reloadable="true">
<!-- DataSource 等もここに -->
</Context>
<!-- Tomcat の conf/server.xml に <Context> を書くのは非推奨 -->
<!-- war ファイル名 myapp.war を webapps に置くだけで /myapp になる -->
よくあるバグと対処
| 症状 | 原因 | 対処 |
|---|---|---|
| 本番だけリンクが 404 | <a href="/login"> ハードコード | ${pageContext.request.contextPath} を前置 |
| CSS / JS が読まれない | 同上 | @{/css/app.css} を使う |
| contextPath が空 | ROOT.war / Spring Boot 既定 | 正常。"" + "/path" = "/path" |
| Ajax だけ 404 | JS にハードコード | JSP/Thymeleaf 側で window.CONTEXT_PATH 等に渡す |
Spring Boot で server.servlet.context-path が効かない | 1.x 系設定 server.context-path のまま | Spring Boot 2.0+ は server.servlet.context-path |
FAQ
Q: request.getContextPath() と request.getServletContext().getContextPath() の違い
A: 同じ値を返します。Servlet 3.0+ なら好きな方で OK。
Q: HTML 内ハードコード /myapp/login でも動く
A: 動きますが、デプロイ先が変わった瞬間に全 URL を grep 置換する羽目に。常に動的取得が原則です。
Q: 静的 HTML から呼ぶときは?
A: 静的 HTML は JSP/Thymeleaf を介さないので、JS で document.querySelector('base').href や <meta name="ctx"> を読むパターンが多いです。
子ページ
子ページはありません
同階層のページ
- タグ一覧
- コンテキストパスの取得
人気ページ
- 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 / Maya)
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- djangoのテンプレートの作成とヘッダー・フッターの共通化 2026-10-03 21:41:49
- テンプレートフラグメント(ヘッダー等の共有化) 2026-10-03 21:41:49
- reCAPTCHA v3 使い方(サンプル付き) 2026-10-03 21:37:05
- Content-Type一覧|MIMEタイプとはとHTTPでの主な使用場面 2026-10-03 21:37:05
- SpringにおけるAOPの使い方 2026-10-03 21:37:05
- X (Twitter) API でツイートできないがエラーが出ない問題の原因と対処 2026-10-03 11:33:01
- X (Twitter) API アプリケーション登録完全ガイド|v2・Bearer Token・OAuth 2.0 PKCE 2026-10-03 11:33:01
- X (Twitter) API 完全ガイド|従量課金の料金・単価(2026年10月)と v2 移行 2026-10-03 11:32:40
- Google DeepMind とは?Gemini・AlphaFold の開発元 2026-10-03 11:26:56
- Cursor とは?AI 統合型コードエディタの使い方・料金 2026-10-03 11:26:56
- Claude (Anthropic) とは?AIチャットの使い方・モデルファミリ・API 2026-10-03 11:26:56
- AIベンダー一覧:OpenAI・Anthropic・Google DeepMind・Microsoft・Meta 2026-10-03 11:26:56
- クラウド・インフラ完全ガイド — AWS/Azure/GCP/Kubernetes 2026-10-03 11:26:56
- テキストエディタ完全比較 (VS Code / Cursor / Vim / Emacs / IDE) 2026-10-03 11:26:56
- プログラミング学習プラットフォーム|Scratch・micro:bit ほか 2026-10-03 11:26:56