2.

Java Servlet / JSP / Spring MVC / Thymeleaf でコンテキストパスを取得する方法まとめ

編集
この記事の要点
  • Servlet: request.getContextPath()(例: /myapp
  • JSP (EL): ${pageContext.request.contextPath}
  • Spring MVC: @Value("${server.servlet.context-path}") または HttpServletRequest#getContextPath()
  • Thymeleaf: th:href="@{/foo}" でコンテキストパスが自動付与
  • ハードコード厳禁。リバースプロキシ配下 (/api 等) に置いた瞬間にリンクが全滅する

コンテキストパスとは

Java EE / Jakarta EE の Web アプリは Tomcat 等のサーブレットコンテナにデプロイすると /myapp のようなコンテキストパスが前置されます。これを動的に取得しないと、デプロイ先が変わった瞬間にリンク・フォーム・リダイレクトが全滅します。

デプロイ形態URL 例contextPath
Tomcat の webapps/myapp.warhttp://host/myapp/login/myapp
Tomcat ROOT.warhttp://host/login空文字 ""
Spring Boot 組込 Tomcat 既定http://host/login空文字
Spring Boot で server.servlet.context-path=/apihttp://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 で取得(推奨) --%>
ログイン

<%-- フォーム --%>
...
<%-- JSTL もコンテキストパスを自動付与 --%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> ログイン <%-- 変数に格納して使い回す --%>

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 は @{/...} 構文で自動的にコンテキストパスを前置します。これが最も安全:


ログイン
...
詳細 検索 [ctx]

JavaScript 側へ渡す

SPA 化していなくても、AJAX 呼び出しのために JS にコンテキストパスを渡す必要があります:







web.xml での設定

従来の Servlet コンテナ (Tomcat 単体) では、コンテキストパスは war 名 or META-INF/context.xml で指定:




    



よくあるバグと対処

症状原因対処
本番だけリンクが 404 ハードコード${pageContext.request.contextPath} を前置
CSS / JS が読まれない同上@{/css/app.css} を使う
contextPath が空ROOT.war / Spring Boot 既定正常。"" + "/path" = "/path"
Ajax だけ 404JS にハードコード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 を読むパターンが多いです。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. タグ一覧
  2. コンテキストパスの取得