Template MethodパターンとHttpServlet内部実装の詳細解説

Template Methodパターンの本質

Template Methodはアルゴリズムの骨格を上位クラスで定め、可変部分のみを下位クラスに委ねる振る舞い型パターンである。

  • 抽象クラス(例:AbstractReport)がfinalで修飾されたgenerate()メソッドを持つ。
  • generate()内部ではbuildHeader()buildBody()buildFooter()などのフックメソッドを順番に呼び出す。
  • フックメソッドは抽象または空実装であり、具象クラスが必要に応じてオーバーライドする。
  • これにより共通処理の繰り返しを防ぎ、拡張ポイントを明確化できる。

HttpServletクラスの内部構造

位置づけ

jakarta.servlet.http.HttpServletはHTTP特有の処理を抽象化したクラスであり、GenericServletを継承している。

主要インタフェース/クラス一覧

種別完全修飾名役割
インタフェースjakarta.servlet.ServletServlet基本API
インタフェースjakarta.servlet.ServletConfig初期化パラメータ保持
インタフェースjakarta.servlet.ServletContextアプリケーション全体の情報
インタフェースjakarta.servlet.ServletRequestプロトコル非依存リクエスト
インタフェースjakarta.servlet.ServletResponseプロトコル非依存レスポンス
クラスjakarta.servlet.http.HttpServletRequestHTTPリクエスト情報
クラスjakarta.servlet.http.HttpServletResponseHTTPレスポンス構築

リクエスト処理フロー

  1. Tomcatがservice(ServletRequest, ServletResponse)を呼び出す。
  2. 内部でHttpServletRequest/HttpServletResponseへキャスト。
  3. オーバーロードされたservice(HttpServletRequest, HttpServletResponse)へディスパッチ。
  4. HTTPメソッドごとに分岐し、doGetdoPost…を呼び出す。
  5. 下位クラスで未実装のHTTPメソッドが呼ばれると405エラーが返却される。

public abstract class HttpServlet extends GenericServlet {
    protected void service(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

        String m = req.getMethod();
        switch (m) {
            case "GET"  -> processGet(req, resp);
            case "POST" -> processPost(req, resp);
            case "PUT"  -> processPut(req, resp);
            case "DELETE" -> processDelete(req, resp);
            default -> resp.sendError(501);
        }
    }

    protected void processGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        long lastMod = getLastModified(req);
        if (lastMod == -1) {
            doGet(req, resp);
            return;
        }
        long since = req.getDateHeader("If-Modified-Since");
        if (since < lastMod / 1000 * 1000) {
            maybeSetLastModified(resp, lastMod);
            doGet(req, resp);
        } else {
            resp.setStatus(304);
        }
    }

    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        String msg = lStrings.getString("http.method_get_not_supported");
        sendMethodNotAllowed(req, resp, msg);
    }
}

Servlet実装の推奨手順

  1. HttpServletを直接継承する。
  2. 必要なHTTPメソッド(doGetまたはdoPost)のみをオーバーライドする。
  3. web.xmlまたはアノテーションでURLマッピングを定義する。
  4. 対応するHTMLフォームのmethod属性と一致させる。

ウェルカムページの設定

基本設定

<welcome-file-list>
    <welcome-file>top.html</welcome-file>
</welcome-file-list>

ルート直下のサブフォルダを含む場合:

<welcome-file-list>
    <welcome-file>secure/portal/index.html</welcome-file>
</welcome-file-list>

複数候補と優先順位

<welcome-file-list>
    <welcome-file>home.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
</welcome-file-list>

上から順に存在確認を行い、最初に見つかったファイルが返却される。

Servletをウェルカムページにする

  1. WelcomeServletを作成し/entryへマッピング。
  2. ウェルカムファイルとしてentryを指定。
<welcome-file-list>
    <welcome-file>entry</welcome-file>
</welcome-file-list>

デフォルト挙動と優先ルール

Tomcatのconf/web.xmlで以下がデフォルト指定されている。

<welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
</welcome-file-list>

アプリケーション固有のweb.xmlが存在すればそちらが優先される(局所優先)。

WEB-INF配下の制限

/WEB-INF/以下に配置した静的リソースは直接ブラウザからアクセスできない。必ずServlet経由で取得する必要がある。

タグ: TemplateMethod HttpServlet ServletLifecycle WelcomeFile JavaEE

7月8日 23:50 投稿