この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:8
ページ更新者:guest
更新日時:2026-06-11 07:29:05

タイトル: JSP
SEOタイトル: JSP (JavaServer Pages) の構文と現代的な使い方(EL / JSTL / Thymeleaf 移行)

この記事の要点
  • JSP (JavaServer Pages) = HTML 内に Java を埋め込めるテンプレート。実態はServlet にコンパイルされる
  • 主な構文: <%@ page %> ディレクティブ、<%= expr %> 式、<% Java %> スクリプトレット
  • EL (Expression Language) ${user.name}JSTL <c:if> / <c:forEach> でスクリプトレット禁止が現代スタイル
  • Jakarta EE 10+ でパッケージが javax.servletjakarta.servlet に変更
  • 新規プロジェクトでは Thymeleaf 推奨。JSP は保守案件に残る程度の位置づけ

JSP とは

JSP (JavaServer Pages) は、HTML 内に Java コードや EL 式を埋め込んで動的ページを生成するサーバサイドテンプレート技術です。実行時にはサーブレットに変換され、JVM 上で動きます。Java EE (現 Jakarta EE)の標準仕様で、Servlet とセットで使われてきました。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head><title>Hello JSP</title></head>
<body>
    <h1>Welcome, ${user.name}!</h1>
    <ul>
        <c:forEach var="item" items="${items}">
            <li>${item.title} - ${item.price}円</li>
        </c:forEach>
    </ul>
</body>
</html>

主な構文要素

構文意味
<%@ page %>ページディレクティブ文字コード・import など
<%@ include %>静的 includeコンパイル時に取り込み
<%@ taglib %>タグライブラリ宣言JSTL / カスタムタグ
<%! ... %>宣言 (Servlet クラスのフィールド/メソッド)<%! int counter = 0; %>
<% ... %>スクリプトレット (Java 文)<% int n = 10; %>
<%= expr %>式 (出力)<%= user.getName() %>
<%-- comment --%>JSP コメント (出力されない)HTML コメント は出る
${expr}EL 式${user.name}
<c:if> / <c:forEach>JSTL コアタグ条件分岐・繰り返し

ページディレクティブと文字コード

<%@ page language="java"
         contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"
         import="java.util.*, com.example.model.User"
         session="true"
         errorPage="/WEB-INF/error.jsp" %>

<%-- import を複数 --%>
<%@ page import="java.util.List" %>
<%@ page import="java.util.Map" %>

<%-- 別ファイルを静的に取り込み (コンパイル時) --%>
<%@ include file="header.jsp" %>

<%-- 動的 include (実行時) --%>
<jsp:include page="header.jsp" />

スクリプトレットと式 (旧スタイル)

<%@ page contentType="text/html;charset=UTF-8" %>
<%@ page import="java.util.*" %>

<%-- 宣言: クラスのフィールドになる --%>
<%! private int hitCounter = 0; %>

<%-- スクリプトレット: _jspService メソッド内のローカル --%>
<%
    String name = (String) request.getAttribute("name");
    List<String> items = (List<String>) request.getAttribute("items");
    hitCounter++;
%>

<h1>Hello, <%= name %></h1>
<p>このページの表示回数: <%= hitCounter %></p>

<ul>
<% for (String item : items) { %>
    <li><%= item %></li>
<% } %>
</ul>

<%-- ❌ ロジックが散らかる。現代では避ける --%>

EL (Expression Language) と JSTL (推奨スタイル)

スクリプトレットを書かず、EL + JSTL で表現するのが現代の JSP の作法です。テンプレートとロジックを分離できます。

<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="c"   uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn"  uri="http://java.sun.com/jsp/jstl/functions" %>

<%-- EL でリクエスト属性 / セッション / プロパティアクセス --%>
<h1>Hello, ${user.name}!</h1>
<p>年齢: ${user.age}</p>
<p>住所: ${user.address.city}</p>

<%-- 条件分岐 --%>
<c:if test="${user.admin}">
    <p>管理者です</p>
</c:if>

<c:choose>
    <c:when test="${user.age >= 20}">大人</c:when>
    <c:when test="${user.age >= 13}">中高生</c:when>
    <c:otherwise>子供</c:otherwise>
</c:choose>

<%-- 繰り返し --%>
<ul>
<c:forEach var="item" items="${items}" varStatus="s">
    <li>${s.count}: ${item.title} - <fmt:formatNumber value="${item.price}" type="currency"/></li>
</c:forEach>
</ul>

<%-- 関数 --%>
<p>アイテム数: ${fn:length(items)}</p>
<p>大文字: ${fn:toUpperCase(user.name)}</p>

<%-- 日付フォーマット --%>
<p>登録日: <fmt:formatDate value="${user.createdAt}" pattern="yyyy/MM/dd HH:mm"/></p>

EL のスコープ参照

EL は名前の前に明示しなくても各スコープを順に探します(pageScope → requestScope → sessionScope → applicationScope):

<%-- 任意のスコープから自動探索 --%>
${user.name}

<%-- スコープ明示 --%>
${requestScope.user.name}
${sessionScope.cart.items}
${applicationScope.config.title}

<%-- リクエストパラメータ --%>
${param.q}                  <%-- ?q=xxx --%>
${paramValues.tags[0]}      <%-- 配列 --%>

<%-- Cookie / Header --%>
${cookie.JSESSIONID.value}
${header['User-Agent']}
${initParam.appName}        <%-- web.xml の init-param --%>

サーブレット側との連携

// MVC: Servlet がコントローラ、JSP がビュー
@WebServlet("/users")
public class UserListServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

        // モデル
        List<User> users = userService.findAll();

        // リクエストスコープに格納
        req.setAttribute("users", users);
        req.setAttribute("title", "ユーザ一覧");

        // JSP に転送
        req.getRequestDispatcher("/WEB-INF/views/user-list.jsp")
           .forward(req, resp);
    }
}

カスタムタグ (Tag File)

<%-- /WEB-INF/tags/userCard.tag --%>
<%@ tag pageEncoding="UTF-8" %>
<%@ attribute name="user" required="true" type="com.example.User" %>

<div class="user-card">
    <strong>${user.name}</strong>
    <span>${user.email}</span>
</div>
<%-- 使う側 --%>
<%@ taglib prefix="my" tagdir="/WEB-INF/tags" %>

<c:forEach var="u" items="${users}">
    <my:userCard user="${u}" />
</c:forEach>

Jakarta EE への移行

Jakarta EE 9(2020 年)から名前空間が javax.*jakarta.* に変わり、JSP は 3.0 → 3.1 になりました。Tomcat 10+ は jakarta 系のみ対応。

項目Java EE / Tomcat 9Jakarta EE / Tomcat 10+
パッケージjavax.servlet.*jakarta.servlet.*
JSTL taglib URIhttp://java.sun.com/jsp/jstl/corejakarta.tags.core
JSP 仕様2.33.1

Thymeleaf への移行が主流

Spring Boot 系で新規に JSP を採用する理由はほとんどありません。以下の理由で Thymeleaf が標準的に使われます:

  • JSP はSpring Boot の自動設定対象外(追加設定が必要)
  • JSP はブラウザで直接プレビューできない(独自タグでデザイナとの分業しづらい)
  • Thymeleaf は <h1 th:text="${title}">サンプル</h1> のようにHTML として有効
  • セキュリティ(XSS)デフォルト挙動が Thymeleaf の方が安全

FAQ

Q: スクリプトレットを禁止するには?
A: web.xml<scripting-invalid>true</scripting-invalid> を追加。チームの規約として強制できる。

Q: EL で出力すると XSS は大丈夫?
A: ${...}エスケープしない。安全に出すには <c:out value="${...}"/> または fn:escapeXml()

Q: JSP のホットリロード
A: Tomcat 等は JSP を変更すれば自動再コンパイル。本番では development=false でビルド時のみコンパイルにする方が高速。