Manual / アプリケーション開発2026.10.14 · ユーザーマニュアル
CHAPTER 05 / KOHAKU

アプリケーション開発

Servlet、JSP/JSTL、非同期処理、WebSocketを利用する際の配置とAPIを説明します。

javax.*を使う

対象はJava EE 8世代です。Maven座標に jakarta が含まれていても、APIパッケージは javax.servlet、javax.websocket などです。Servlet 5以降の jakarta.servlet.* アプリはそのままでは対象になりません。仕様APIはprovidedとして扱い、WARに重複同梱しない構成にします。

アプリケーションで使う仕様API
API配布API座標・版
Servlet 4.0jakarta.servlet:jakarta.servlet-api:4.0.3
EL 3.0jakarta.el:jakarta.el-api:3.0.3
JSP 2.3jakarta.servlet.jsp:jakarta.servlet.jsp-api:2.3.6
JSTL 1.2jakarta.servlet.jsp.jstl:jakarta.servlet.jsp.jstl-api:1.2.7
JTA中核jakarta.transaction:jakarta.transaction-api:1.3.3
Concurrency Utilitiesjakarta.enterprise.concurrent:jakarta.enterprise.concurrent-api:1.1.2
WebSocket 1.1jakarta.websocket:jakarta.websocket-api:1.1.2

最小のServlet

Javaクラスを WEB-INF/classes またはWAR内のjarへ配置します。アノテーションの走査は web.xml の metadata-complete と記述子の規則に従います。

src/main/java/example/HelloServlet.java
package example;

import java.io.IOException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request,
                         HttpServletResponse response) throws IOException {
        response.setContentType("text/plain;charset=UTF-8");
        response.getWriter().println("Hello, Kohaku");
    }
}

sample.war として配備した場合は /sample/hello で確認します。依存APIの指定例:

アプリ側のpom.xmlのdependencies内
<dependency>
  <groupId>jakarta.servlet</groupId>
  <artifactId>jakarta.servlet-api</artifactId>
  <version>4.0.3</version>
  <scope>provided</scope>
</dependency>

JSP・EL・JSTL

JSPは要求時に翻訳・Javaコンパイルされます。JDK 21で実行し、webappの作業領域を実行ユーザーが書けるようにします。JSTL実装とAPIは配布物の shared/ からwebappクラスローダの末尾へ追加されます。WARが同じタグライブラリを持つ場合はWAR側が優先されます。

WARルートのindex.jsp
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!doctype html>
<html lang="ja">
<head><meta charset="UTF-8"><title>Hello</title></head>
<body><h1><c:out value="${param.name}" default="Kohaku" /></h1></body>
</html>

/sample/index.jsp?name=Hello で出力を確認します。出力に外部入力を使う場合は、この例のように c:out 等でエスケープします。

JSTLの資源制限

以下は 各WARのWEB-INF/web.xmlのcontext-param です。server.yamlからは読みません。負数や非整数の数値はタグ使用時に JspTagException になります。

context-paramの一覧
param-name既定意味
kohaku.jstl.import.connectTimeoutMillis10000接続期限。0はこの層で設定しない
kohaku.jstl.import.readTimeoutMillis30000read期限。0はこの層で設定しない
kohaku.jstl.import.maxBytes1048576010 MiB。0は本文無制限
kohaku.jstl.import.allowedSchemeshttp,httpsカンマ区切り。*は全スキーム
kohaku.jstl.import.allowedHosts未設定ホスト/IP/CIDRの許可リスト
kohaku.jstl.import.deniedHosts未設定拒否リスト。許可より優先
kohaku.jstl.import.maxRedirects20手動追従の上限。明示設定かホストポリシー設定時に手動追従
kohaku.jstl.sql.queryTimeoutSeconds0SQL実行期限。0はsetQueryTimeoutを呼ばない
kohaku.jstl.sql.maxRows0query結果の行数上限。0は無効。指定時はページの上限より小さい値で縛る
WEB-INF/web.xmlのweb-app直下 — 外部取込先を限定
<context-param>
  <param-name>kohaku.jstl.import.allowedHosts</param-name>
  <param-value>content.example.invalid:443</param-value>
</context-param>
<context-param>
  <param-name>kohaku.jstl.sql.queryTimeoutSeconds</param-name>
  <param-value>30</param-value>
</context-param>
<context-param>
  <param-name>kohaku.jstl.sql.maxRows</param-name>
  <param-value>1000</param-value>
</context-param>

Servlet非同期と管理タスク

非同期Servlet/Filterは asyncSupported=true を宣言します。AsyncContext.start() の枠は async.maxTasks と async.maxTasksPerWebapp です。Concurrency UtilitiesのManagedExecutorは別の枠を持ち、実装定数で同時実行1,024・待機4,096です。async.* を増やしてもManagedExecutorの枠は変わりません。

管理サービスは JNDIの既定名 で取得します。アプリからコンテナ管理Executorの shutdown() を呼ぶ運用にしないでください。トランザクションはタスクへそのまま持ち越されず、タスク内の開始・完了はタスク側で処理します。

WebSocket

src/main/java/example/EchoEndpoint.java
package example;

import javax.websocket.OnMessage;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/echo")
public class EchoEndpoint {
    @OnMessage
    public String echo(String message) {
        return message;
    }
}

sample.war なら接続先は ws://127.0.0.1:8080/sample/echo、TLSでは wss:// です。クライアントAPIは ContainerProvider.getWebSocketContainer() から取得します。最新の実装ではwebapp所有のクライアント接続も撤去・停止で回収し、サーバの websocket.* 設定がContainerProvider経由にも反映されます。

接続上限はHTTP枠とWebSocket枠の両方を考慮します。超過はハンドシェイク503、サイズ超過はclose 1009、レート違反等は1008です。WebSocket Sessionのidle期限は http.upgradeIdleTimeoutMillis と独立です。