
サーブレット&JSPの基本|JSTLの基本と使い方
EL式だけでは書きにくい分岐と繰り返しを、JSTLでタグ化する。ひとこと広場のJSPからJavaコードをなくして、画面をもっと読みやすくしよう
前回は、EL式を使ってJSPを簡潔にする方法を学習しました。
EL式を使うと、スコープに保存されたJavaBeansのプロパティを、短い記述で画面に表示できます。
たとえば、セッションスコープにloginUserという属性名でUserインスタンスが保存されている場合、利用者名は次のように表示できます。
${loginUser.name}従来のように、Userクラスをimportし、session.getAttributeで取得し、User型にキャストし、getNameメソッドを呼び出す必要がありません。
このように、EL式はJSPをすっきり書くためにとても便利です。
ただし、EL式だけでは、条件分岐や繰り返しの処理を書くには限界があります。
たとえば、ひとこと広場のloginResult.jspでは、ログイン成功時と失敗時で表示内容を切り替える必要があります。
また、main.jspでは、messageListに入っている投稿を先頭から順番に表示する必要があります。
これまでのJSPでは、このような分岐や繰り返しにスクリプトレットを使っていました。
しかし、JSPの中にJavaのif文やfor文が増えると、画面表示のためのHTMLとJavaの処理が混ざり、読みづらくなってしまいます。
そこで使うのが、JSTLです。
JSTLを使うと、条件分岐や繰り返しをタグとして書けます。
つまり、JSPの中にJavaのコードを書かなくても、ログイン成功時と失敗時の分岐や、投稿一覧の繰り返し表示を表現できます。
この記事では、JSTLの基本、taglibディレクティブの書き方、Coreタグライブラリの代表的なタグ、そしてひとこと広場のloginResult.jspとmain.jspをEL式とJSTLで書き直す方法を学習します。
JSTLとは
JSTLは、Jakarta Standard Tag Libraryの略です。
JSPでよく使う処理を、タグとして利用できるようにまとめたタグライブラリです。
JSPには、jsp:includeやjsp:forwardのような標準アクションタグが用意されています。
これらはJSPに最初から用意されているタグです。
一方、JSTLは、条件分岐、繰り返し、変数出力など、JSPでよく使う処理をカスタムタグとしてまとめたライブラリです。
JSTLでできること
| 処理 | 内容 |
|---|---|
| 変数の出力 | 値を安全に画面へ表示する |
| 条件分岐 | 条件に応じて表示内容を切り替える |
| 多分岐 | 複数の条件を順番に判定する |
| 繰り返し | リストや配列の内容を順番に表示する |
| リダイレクト | 指定したURLへ移動する |
JSTLを使うと、Javaのスクリプトレットを書かずに、タグ形式で分岐や繰り返しを表現できます。
そのため、JSPをHTMLに近い見た目で保ちやすくなります。
カスタムタグとタグライブラリ
JSPでは、あらかじめ用意されている標準アクションタグのほかに、独自のタグを作成することもできます。
このようなタグをカスタムタグと呼びます。
作成したカスタムタグをまとめたものが、タグライブラリです。
JSTLは、よく使われるカスタムタグをまとめた代表的なタグライブラリです。
標準アクションタグとカスタムタグ
| 種類 | 例 | 内容 |
|---|---|---|
| 標準アクションタグ | jsp:include、jsp:forward | JSPに標準で用意されているアクションタグ |
| カスタムタグ | c:if、c:forEach、c:out | タグライブラリとして提供されるタグ |
| JSTL | Core、I18N、Functionsなど | よく使うカスタムタグをまとめたライブラリ |
カスタムタグは自分で作ることもできますが、実際の開発では、まず既存のタグライブラリを使う場面が多くなります。
JSTLはその代表であり、JSPを簡潔にするうえでとても重要です。
図1:EL式とJSTLでJSPからJavaコードを減らす

この図から分かること
EL式は、スコープに保存されたインスタンスやJavaBeansのプロパティを簡潔に取得するために使います。
JSTLは、条件分岐や繰り返しなど、EL式だけでは書きにくい処理をタグで表現するために使います。
この2つを組み合わせると、JSPからJavaのスクリプトレットやスクリプト式を大きく減らせます。
ひとこと広場のloginResult.jspやmain.jspも、EL式とJSTLを使うことで、Javaコードをほとんど書かずに同じ画面表示を実現できます。
JSTLを使うための準備
JSTLは、JSPに最初から何もしなくても使えるものではありません。
JSTLを使うには、必要なJARファイルをダウンロードし、動的Webプロジェクトに配置します。
ここでは、Jakarta版のJSTLを利用します。
必要なJARファイル
| 種類 | 役割 |
|---|---|
| JSTL API | JSTLのインタフェースを提供する |
| JSTL 実装 | JSTLの実際の処理を提供する |
JSTLを使うには、APIと実装の両方が必要です。
どちらか一方だけでは、JSPでJSTLタグを正しく使えません。
JSTL APIをダウンロードする
まず、JSTL APIのJARファイルをダウンロードします。
Maven RepositoryのJSTL APIのページにアクセスし、Filesのjarをクリックしてダウンロードします。
https://mvnrepository.com/artifact/jakarta.servlet.jsp.jstl/jakarta.servlet.jsp.jstl-api/3.0.2

今回の範囲では、次のJSTL APIを使います。
jakarta.servlet.jsp.jstl-api 3.0.2
JSTL APIは、JSTLの機能を使うためのインタフェースを提供します。
ただし、APIだけでは実際の処理は動きません。
次に、JSTLの実装もダウンロードします。
JSTLの実装をダウンロードする
次に、JSTLの実装のJARファイルをダウンロードします。
Maven RepositoryのJSTL実装のページにアクセスし、Filesのjarをクリックしてダウンロードします。
https://mvnrepository.com/artifact/org.glassfish.web/jakarta.servlet.jsp.jstl/3.0.1

今回の範囲では、次のJSTL実装を使います。
jakarta.servlet.jsp.jstl 3.0.1
この実装JARがあることで、JSTLタグの処理が実際に動作します。
JSTL APIとJSTL実装の2つを用意したら、次にプロジェクトへ配置します。
JARファイルをWEB-INF/libに配置する
ダウンロードした2つのJARファイルは、動的WebプロジェクトstudyのWEB-INF/libフォルダに配置します。
配置場所は次の通りです。
src/main/webapp/WEB-INF/lib
このlibフォルダにJARファイルをコピーすると、WebアプリケーションからJSTLを利用できるようになります。
保存した2つのJARファイルを Eclipse の動的Webプロジェクト内の src/main/webapp/WEB-INF/lib フォルダにドラッグアンドドロップします。

下図のダイアログが表示されたら「ファイルをコピー」を選択して「OK」をクリックします。

配置時の注意
| 項目 | 内容 |
|---|---|
| 配置先 | src/main/webapp/WEB-INF/lib |
| 配置するJAR | JSTL APIとJSTL実装の2つ |
| 注意点 | WEB-INF直下ではなく、WEB-INF/libに配置する |
| Eclipseでの操作 | ドラッグアンドドロップ時はファイルをコピーを選ぶ |
WEB-INFに直接置くのではなく、WEB-INF/libに置く点に注意しましょう。
JARファイルを配置したら、Eclipse上でsrc/main/webapp/WEB-INF/libに2つのJARファイルが入っていることを確認します。

JSTLのタグライブラリ
JSTLは、複数のタグライブラリで構成されています。
それぞれ役割が異なります。
JSTLのタグライブラリ一覧
| タグライブラリ | 内容 |
|---|---|
| Core | 変数、条件分岐、繰り返しなどの基本的な処理に関するタグ |
| I18N | 数値や日付のフォーマット、国際化対応に関するタグ |
| Database | データベース操作に関するタグ |
| XML | XML操作に関するタグ |
| Functions | コレクションや文字列を操作する関数 |
この中で、ServletとJSPの入門で特によく使うのがCoreタグライブラリです。
Coreタグライブラリには、変数出力、条件分岐、繰り返しなど、JSPでよく使う基本的なタグが含まれています。
ひとこと広場のJSPを書き直すときも、Coreタグライブラリを使います。
taglibディレクティブとは
JSPでJSTLを使うには、taglibディレクティブを書きます。
taglibディレクティブは、このJSPファイルでどのタグライブラリを使うのかを指定するための記述です。
基本形は次の通りです。
<%@ taglib prefix="接頭辞" uri="タグライブラリのURI" %>prefix属性には、JSP内でタグを書くときの接頭辞を指定します。
uri属性には、使用するタグライブラリのURIを指定します。
Coreタグライブラリを使う場合は、次のように書きます。
<%@ taglib prefix="c" uri="jakarta.tags.core" %>この指定により、JSP内でc:out、c:if、c:choose、c:forEachなどのタグを使えるようになります。
prefix属性とuri属性
taglibディレクティブでは、prefix属性とuri属性を指定します。
taglibディレクティブの属性
| 属性 | 内容 |
|---|---|
| prefix | JSP内でタグを書くときの接頭辞 |
| uri | 使用するタグライブラリを識別するURI |
prefix属性は、タグライブラリに付ける短い名前のようなものです。
Coreタグライブラリでは、一般的にcを使います。
そのため、Coreタグライブラリのoutタグは、c:outと書きます。
I18Nタグライブラリではfmt、Functionsタグライブラリではfnがよく使われます。
JSTLタグライブラリのtaglibディレクティブ
| タグライブラリ | taglibディレクティブ |
|---|---|
| Core | <%@ taglib prefix="c" uri="jakarta.tags.core" %> |
| I18N | <%@ taglib prefix="fmt" uri="jakarta.tags.fmt" %> |
| Database | <%@ taglib prefix="sql" uri="jakarta.tags.sql" %> |
| XML | <%@ taglib prefix="x" uri="jakarta.tags.xml" %> |
| Functions | <%@ taglib prefix="fn" uri="jakarta.tags.functions" %> |
今回の記事では、Coreタグライブラリを使うため、JSPの先頭付近に次の1行を追加します。
<%@ taglib prefix="c" uri="jakarta.tags.core" %>図2:taglibディレクティブでCoreタグライブラリを使えるようにする

この図から分かること
JSTLを使うには、まず必要なJARファイルをWEB-INF/libに配置します。
そのうえで、JSPファイルにtaglibディレクティブを書き、使用するタグライブラリを指定します。
Coreタグライブラリを使う場合は、prefixにc、uriにjakarta.tags.coreを指定します。
これにより、JSP内でc:out、c:if、c:choose、c:forEachなどのCoreタグを利用できるようになります。
Coreタグライブラリでよく使うタグ
Coreタグライブラリには、JSPでよく使う基本的な処理を行うタグが用意されています。
Coreタグライブラリの主なタグ
| タグの機能 | タグ | 内容 |
|---|---|---|
| 変数設定 | c:set | 変数を設定する |
| 変数削除 | c:remove | 変数を削除する |
| 変数出力 | c:out | 値を出力する |
| 2分岐 | c:if | 条件がtrueのときだけ処理する |
| 多分岐 | c:choose、c:when、c:otherwise | 複数条件で表示を切り替える |
| 繰り返し | c:forEach | リストや配列などを繰り返し処理する |
| リダイレクト | c:redirect | 指定したURLへリダイレクトする |
今回のひとこと広場では、主に次のタグを使います。
| タグ | 使う場面 |
|---|---|
| c:out | 利用者名、エラーメッセージ、投稿者名、投稿内容を出力する |
| c:choose | ログイン成功と失敗を分岐する |
| c:when | ログイン成功時の表示を書く |
| c:otherwise | ログイン失敗時の表示を書く |
| c:if | エラーメッセージがあるときだけ表示する |
| c:forEach | 投稿一覧を繰り返し表示する |
これらを使うことで、ひとこと広場のJSPからJavaのスクリプトレットをなくせます。
カスタムタグの基本文法
JSTLのタグは、次のような形式で使います。
<接頭辞:タグ名 属性名="値">内容</接頭辞:タグ名>また、内容を持たないタグは、次のように書けます。
<接頭辞:タグ名 属性名="値" />
Coreタグライブラリでは、taglibディレクティブでprefixにcを指定することが多いため、次のようなタグになります。
| 書き方 | 内容 |
|---|---|
| <c:out value="${loginUser.name}" /> | loginUserのnameを出力する |
| <c:if test="${not empty errorMsg}"> | errorMsgが空でないときだけ処理する |
| <c:forEach var="message" items="${messageList}"> | messageListを順番に取り出す |
接頭辞は、taglibディレクティブのprefix属性で指定した値です。
Coreタグライブラリにcを指定した場合、c:outやc:forEachのように書きます。
c:outで値を安全に出力する
c:outは、値を画面に出力するためのタグです。
基本形は次の通りです。
<c:out value="出力する値" />value属性には、EL式を指定できます。
たとえば、ログイン中の利用者名を出力する場合は、次のように書きます。
<c:out value="${loginUser.name}" />EL式だけでも、${loginUser.name}のように値を出力できます。
しかし、ユーザーが入力した内容を表示する場合は、c:outを使うほうが安全です。
c:outを使う理由
| 項目 | 内容 |
|---|---|
| 値を出力できる | EL式で取得した値を画面に表示する |
| エスケープできる | HTMLとして意味を持つ記号を無害化して出力する |
| XSS対策につながる | ユーザー入力をそのままHTMLとして解釈させにくくする |
たとえば、投稿内容に<や>が含まれている場合、そのまま出力するとHTMLタグとして解釈される可能性があります。
c:outは、そのような特殊な記号をエスケープして出力します。
ひとこと広場では、利用者が投稿したtextを画面に表示するため、c:outを使うのが適しています。
c:ifで条件に合うときだけ表示する
c:ifは、条件がtrueのときだけ中身を実行するタグです。
基本形は次の通りです。
<c:if test="条件式">
条件式がtrueなら実行される処理
</c:if>test属性には、EL式を使った条件を書けます。
たとえば、エラーメッセージがあるときだけ表示したい場合は、次のように書きます。
<c:if test="${not empty errorMsg}">
<c:out value="${errorMsg}" />
</c:if>errorMsgが存在し、空でなければ、中のpタグが出力されます。
errorMsgがない場合は、何も表示されません。
c:ifが向いている場面
| 場面 | 例 |
|---|---|
| メッセージがあるときだけ表示する | errorMsgがある場合だけ表示する |
| 条件を満たした場合だけ案内を出す | 投稿数が0のときだけ案内を出す |
| 特定状態のときだけリンクを表示する | 管理者のときだけ管理画面リンクを表示する |
c:ifは、シンプルな条件分岐に向いています。
ただし、falseの場合にも別の処理をしたいときは、c:chooseを使います。
c:chooseで成功と失敗を分岐する
c:chooseは、Javaのif、else if、elseのような多分岐を表現するタグです。
c:chooseの中に、c:whenとc:otherwiseを書きます。
基本形は次の通りです。
<c:choose>
<c:when test="条件式">
条件式がtrueなら実行される処理
</c:when>
<c:otherwise>
すべての条件がfalseなら実行される処理
</c:otherwise>
</c:choose>c:whenは複数書けます。
c:otherwiseは、どのc:whenにも当てはまらなかった場合の処理です。
ひとこと広場のloginResult.jspでは、ログイン成功時と失敗時で表示内容を切り替えます。
ログイン成功時は、Login.javaでセッションスコープにloginUserが保存されています。
そのため、JSTLでは次のように判定できます。
<c:when test="${not empty loginUser}">loginUserが空でなければログイン成功、空であればログイン失敗として表示を分けられます。
c:forEachで繰り返し表示する
c:forEachは、繰り返し処理を行うタグです。
通常のfor文のように、回数を指定して繰り返すこともできます。
基本形は次の通りです。
<c:forEach var="カウンタ変数" begin="最初の値"
end="最後の値" step="増加値">
繰り返し実行する処理
</c:forEach>たとえば、0から9まで表示する場合は、次のように書きます。
<c:forEach var="i" begin="0" end="9" step="1">
<c:out value="${i}" />
</c:forEach>var属性で指定したiは、ページスコープに保存されます。
そのため、タグの中では${i}として参照できます。
通常のfor文との対応
| JSTL | Javaのイメージ |
|---|---|
| var="i" | int i |
| begin="0" | i = 0 |
| end="9" | i <= 9 |
| step="1" | i++ |
end属性に指定した値まで繰り返す点に注意しましょう。
beginが0、endが9、stepが1の場合、0から9までの10回繰り返します。
リストをc:forEachで表示する
c:forEachは、拡張for文のようにも使えます。
リストや配列などの集合をitems属性に指定すると、その中の要素を先頭から順に取り出せます。
基本形は次の通りです。
<c:forEach var="変数名" items="インスタンスの集合">
繰り返し実行する処理
</c:forEach>items属性には、EL式でリストを指定します。
ひとこと広場では、投稿一覧がmessageListという属性名でアプリケーションスコープに保存されています。
そのため、main.jspでは次のように書けます。
<c:forEach var="message" items="${messageList}">
<c:out value="${message.userName}" />:
<c:out value="${message.text}" />
</c:forEach>この書き方により、messageListに入っているShortMessageインスタンスを先頭から順番に取り出し、投稿者名と投稿内容を表示できます。
c:forEachで投稿一覧を表示する流れ
| 順番 | 内容 |
|---|---|
| 1 | items属性でmessageListを指定する |
| 2 | messageListの先頭からShortMessageを1つ取り出す |
| 3 | var属性で指定したmessageに代入する |
| 4 | message.userNameとmessage.textをc:outで出力する |
| 5 | リストの要素数だけ繰り返す |
Javaの拡張for文で書くと、for (ShortMessage message : messageList)のようなイメージです。
JSTLを使うと、これをJSP上でタグとして表現できます。
図3:c:choose、c:if、c:forEachでひとこと広場のJSPを改良する

この図から分かること
ひとこと広場では、ログイン結果画面とメイン画面でJSTLが役立ちます。
loginResult.jspでは、c:choose、c:when、c:otherwiseを使うことで、ログイン成功時と失敗時の表示をタグで分けられます。
main.jspでは、c:ifでエラーメッセージがあるときだけ表示し、c:forEachでmessageListに入っている投稿を繰り返し表示できます。
また、利用者名や投稿内容の出力にはc:outを使うことで、安全に値を表示できます。
ひとこと広場のloginResult.jspをJSTLで改良する
ここからは、ここまで作成してきたひとこと広場のJSPを、EL式とJSTLを使って書き直します。
まずは、ログイン結果画面のloginResult.jspです。
これまでのloginResult.jspでは、セッションスコープからloginUserを取得するためにスクリプトレットを使っていました。
JSTL版では、Javaコードを書かずに、c:chooseでログイン成功と失敗を分岐します。
ログイン成功の判定には、EL式のnot emptyを使います。
loginUserが存在すればログイン成功、存在しなければログイン失敗として表示します。
ひとこと広場のログイン結果画面の例
ファイル名: loginResult.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="jakarta.tags.core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ひとこと広場</title>
</head>
<body>
<h1>ひとこと広場ログイン</h1>
<c:choose>
<c:when test="${not empty loginUser}">
<p>ログインに成功しました</p>
<p>ようこそ<c:out value="${loginUser.name}" />さん</p>
<a href="Main">ひとこと投稿・閲覧へ</a>
</c:when>
<c:otherwise>
<p>ログインに失敗しました</p>
<a href="index.jsp">トップへ</a>
</c:otherwise>
</c:choose>
</body>
</html>このJSPは、src/main/webapp/WEB-INF/jspディレクトリに配置します。
JSTLを使うため、pageディレクティブの下にtaglibディレクティブを追加しています。
<%@ taglib prefix="c" uri="jakarta.tags.core" %>これにより、c:choose、c:when、c:otherwise、c:outを使えるようになります。
loginResult.jspの改良ポイント
このloginResult.jspでは、Javaのスクリプトレットを使っていません。
変更された考え方
| 従来の処理 | JSTL版 |
|---|---|
| session.getAttributeでloginUserを取得する | EL式でloginUserを参照する |
| if文でloginUser != nullを判定する | c:when test="${not empty loginUser}"で判定する |
| loginUser.getNameで利用者名を取得する | c:out value="${loginUser.name}"で出力する |
| スクリプトレットで分岐する | c:chooseで分岐する |
Login.javaでログイン成功時にloginUserをセッションスコープへ保存しているため、JSP側では${loginUser}として参照できます。
EL式は、ページスコープ、リクエストスコープ、セッションスコープ、アプリケーションスコープの順に属性名を探します。
loginUserはセッションスコープに保存されているため、${loginUser.name}で利用者名を取得できます。
c:chooseでログイン結果を分ける
loginResult.jspでは、次の構成でログイン結果を分けています。
<c:choose>
<c:when test="${not empty loginUser}">
ログイン成功時の表示
</c:when>
<c:otherwise>
ログイン失敗時の表示
</c:otherwise>
</c:choose>分岐の内容
| 条件 | 表示内容 |
|---|---|
| loginUserが空でない | ログインに成功しました、ようこそ利用者名さん、ひとこと投稿・閲覧へ |
| loginUserが空 | ログインに失敗しました、トップへ |
このように、JSTLを使うと、if文を書かずにタグで分岐を表現できます。
画面表示の中にJavaコードが入り込まないため、JSPが読みやすくなります。
ひとこと広場のmain.jspをJSTLで改良する
次に、ひとこと広場のメイン画面であるmain.jspを改良します。
main.jspでは、次の処理を行います。
main.jspで行う処理
| 処理 | JSTLで使うタグ |
|---|---|
| ログイン中の利用者名を表示する | c:out |
| エラーメッセージがあるときだけ表示する | c:if |
| 投稿一覧を繰り返し表示する | c:forEach |
| 投稿者名と投稿内容を安全に出力する | c:out |
これまでのmain.jspでは、User、ShortMessage、Listをimportし、session.getAttributeやapplication.getAttributeを使ってインスタンスを取得し、拡張for文でmessageListを表示していました。
JSTL版では、これらのJavaコードをJSPに書かず、EL式とJSTLタグで表現します。
ひとこと広場のメイン画面の例
ファイル名: main.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="jakarta.tags.core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ひとこと広場</title>
</head>
<body>
<h1>ひとこと広場メイン</h1>
<p>
<c:out value="${loginUser.name}" />さん、ログイン中
<a href="Logout">ログアウト</a>
</p>
<p><a href="Main">更新</a></p>
<form action="Main" method="post">
<input type="text" name="text">
<input type="submit" value="投稿">
</form>
<c:if test="${not empty errorMsg}">
<p><c:out value="${errorMsg}" /></p>
</c:if>
<c:forEach var="message" items="${messageList}">
<p>
<c:out value="${message.userName}" />:
<c:out value="${message.text}" />
</p>
</c:forEach>
</body>
</html>このJSPも、src/main/webapp/WEB-INF/jspディレクトリに配置します。
JSTLを使うために、taglibディレクティブを追加しています。
このmain.jspでは、Javaのスクリプトレットを使っていません。
画面表示に必要な値はEL式で取得し、出力や分岐、繰り返しはJSTLタグで行っています。
main.jspの改良ポイント
JSTL版のmain.jspでは、Javaのimportが不要になっています。
また、session.getAttributeやapplication.getAttributeをJSP内に書いていません。
従来のmain.jspとJSTL版の違い
| 従来の処理 | JSTL版 |
|---|---|
| User、ShortMessage、Listをimportする | importしない |
| session.getAttributeでloginUserを取得する | ${loginUser.name}で参照する |
| application.getAttributeでmessageListを取得する | ${messageList}で参照する |
| request.getAttributeでerrorMsgを取得する | ${errorMsg}で参照する |
| if文でerrorMsgを判定する | c:ifで判定する |
| 拡張for文でmessageListを繰り返す | c:forEachで繰り返す |
| スクリプト式で値を出力する | c:outで出力する |
loginUserはセッションスコープ、messageListはアプリケーションスコープ、errorMsgはリクエストスコープに保存されています。
EL式はこれらのスコープから属性名を探してくれるため、JSP側ではシンプルに書けます。
c:ifでエラーメッセージを表示する
main.jspでは、空の投稿が送信された場合だけエラーメッセージを表示します。
Main.javaでは、空投稿時にerrorMsgという属性名でリクエストスコープにメッセージを保存しています。
JSTL版では、次のように書きます。
<c:if test="${not empty errorMsg}">
<c:out value="${errorMsg}" />
</c:if>c:ifの動き
| errorMsgの状態 | 表示 |
|---|---|
| errorMsgがある | ひとことが入力されていませんを表示する |
| errorMsgがない | 何も表示しない |
not emptyは、EL式で使える便利な判定です。
errorMsgが存在し、空でない場合だけtrueになります。
c:forEachで投稿一覧を表示する
ひとこと広場の投稿一覧は、messageListに保存されています。
messageListには、ShortMessageインスタンスが複数入っています。
JSTL版では、次のようにc:forEachを使って表示します。
<c:forEach var="message" items="${messageList}">
<c:out value="${message.userName}" />:
<c:out value="${message.text}" />
</c:forEach>c:forEachの属性
| 属性 | 内容 |
|---|---|
| var | 取り出した要素を入れる変数名 |
| items | 繰り返し対象のリストや配列 |
itemsに${messageList}を指定すると、messageListの要素が先頭から順に取り出されます。
取り出されたShortMessageインスタンスは、varで指定したmessageに入ります。
そのため、ループ内では${message.userName}や${message.text}でプロパティを取得できます。
c:outで投稿内容を表示する理由
投稿者名や投稿内容は、利用者が入力した値です。
そのため、画面に表示するときは、できるだけc:outを使うのが安全です。
たとえば、投稿内容にHTMLタグのような文字列が入力された場合、そのまま出力すると、ブラウザがHTMLとして解釈してしまう可能性があります。
c:outを使うと、HTMLとして特別な意味を持つ記号をエスケープして出力できます。
ひとこと広場でc:outを使う場所
| 表示内容 | 書き方 |
|---|---|
| ログイン中の利用者名 | <c:out value="${loginUser.name}" /> |
| エラーメッセージ | <c:out value="${errorMsg}" /> |
| 投稿者名 | <c:out value="${message.userName}" /> |
| 投稿内容 | <c:out value="${message.text}" /> |
特に投稿内容は、利用者が自由に入力できる値です。
安全に表示するためにも、EL式だけで出力するより、c:outを使う意識を持っておくとよいです。
動作確認の前に確認すること
JSTL版のJSPを動かす前に、JSTLのJARファイルが正しく配置されているか確認します。
確認ポイント
| 確認すること | 内容 |
|---|---|
| JARファイル | JSTL APIとJSTL実装の2つがあるか |
| 配置場所 | src/main/webapp/WEB-INF/libに入っているか |
| taglibディレクティブ | JSPにCoreタグライブラリの指定があるか |
| URI | jakarta.tags.coreになっているか |
| prefix | cになっているか |
JARファイルを配置し忘れると、JSPでc:outやc:forEachを使ったときにエラーになります。
また、taglibディレクティブのuriを間違えると、JSTLタグが認識されません。
ひとこと広場で動作確認する
JSPを書き換えたら、ひとこと広場をトップ画面から実行します。
プロジェクト名はstudyなので、URLは次のようになります。
動作確認の手順
| 手順 | 内容 |
|---|---|
| 1 | 動的プロジェクト「Hiroba」へ JSTLのJARファイルをsrc/main/webapp/WEB-INF/libに配置する |
| 2 | loginResult.jspをEL式とJSTL版に書き換える |
| 3 | main.jspをEL式とJSTL版に書き換える |
| 4 | studyをTomcat11_Java25に追加する |
| 5 | サーバを起動または再起動する |
| 6 | ブラウザでhttp://localhost:8080/Hiroba/へアクセスする |
| 7 | 任意の利用者名とパスワード1234でログインする |
| 8 | ログイン結果画面が正しく表示されることを確認する |
| 9 | ひとこと投稿・閲覧へをクリックする |
| 10 | メイン画面が正しく表示されることを確認する |
| 11 | ひとことを投稿し、一覧に表示されることを確認する |
| 12 | 空投稿でエラーメッセージが表示されることを確認する |
※注意:動的プロジェクトの「Hiroba」のsrc/main/webapp/WEB-INF/lib に JSTL APIとJSTL 2つを配置します。
JSPの書き方は変わりましたが、実行結果はこれまでと同じです。
大切なのは、画面の動きは変えずに、JSPの中からJavaコードを減らしている点です。
ブラウザの表示例

EL式とアクションタグの関係
EL式は、スコープに保存されたインスタンスや、そのプロパティを簡潔に参照するための書き方です。
JSTLのタグは、EL式を属性値として受け取ることができます。
たとえば、c:outのvalue属性にEL式を書けば、その値を出力できます。
<c:out value="${loginUser.name}" />c:ifのtest属性にEL式を書けば、その結果がtrueかfalseかで表示を分岐できます。
<c:if test="${not empty errorMsg}">c:forEachのitems属性にEL式を書けば、スコープに保存されたリストを繰り返し対象にできます。
<c:forEach var="message" items="${messageList}">このように、EL式とJSTLは組み合わせて使うと力を発揮します。
EL式とJSTLの役割分担
| 技術 | 役割 |
|---|---|
| EL式 | スコープの値やJavaBeansのプロパティを取得する |
| JSTL | 分岐、繰り返し、出力などをタグで表現する |
| HTML | 画面の構造を作る |
EL式で値を取り出し、JSTLで条件分岐や繰り返しを行い、HTMLで画面として表示する。
この流れを意識すると、JSPをきれいに整理しやすくなります。
JSPからJavaコードをなくすメリット
EL式とJSTLを使うと、JSPの中からJavaのスクリプトレットを減らせます。
これは、単にコードが短くなるだけではありません。
Webアプリケーションの開発では、画面の見た目をWebデザイナーが調整し、サーブレットやモデルの処理をJava開発者が担当することがあります。
JSPにJavaコードが多いと、画面修正のときにJavaの処理まで誤って変更してしまう可能性があります。
一方、JSPがHTMLタグ、JSTLタグ、EL式を中心に書かれていれば、画面構造を把握しやすくなります。
JSPをタグ中心にするメリット
| メリット | 内容 |
|---|---|
| 読みやすくなる | HTMLに近い形で画面を確認できる |
| 分業しやすくなる | 画面担当者が編集しやすい |
| Javaコードの誤編集を減らせる | スクリプトレットを触る機会を減らせる |
| 表示処理が整理される | 値の取得はEL式、分岐や繰り返しはJSTLに分けられる |
| 保守しやすくなる | 画面表示の意図が分かりやすくなる |
ひとこと広場のJSPも、EL式とJSTLを使うことで、Javaコードを書かずに同じ表示を実現できました。
JSTLを使うときに意識したいこと
JSTLを使うと、JSPをかなり読みやすくできます。
ただし、JSTLの役割は、あくまで画面表示に必要な分岐や繰り返しをタグで表現することです。
複雑な業務処理や計算処理をJSPに詰め込むのは避けましょう。
意識したいポイント
| ポイント | 内容 |
|---|---|
| JSTLは画面表示の補助に使う | 複雑な処理はサーブレットやモデルに任せる |
| ユーザー入力はc:outで出力する | エスケープされるため安全性が高い |
| taglibディレクティブを忘れない | JSTLタグを使うJSPには必要 |
| JARファイルの配置を確認する | WEB-INF/libにAPIと実装を配置する |
| EL式と組み合わせる | 値の取得はEL式、分岐や繰り返しはJSTLで行う |
JSTLは、EL式と組み合わせることで、JSPをタグ中心の読みやすいファイルにできます。
ひとこと広場のloginResult.jspでは、c:chooseでログイン成功と失敗を分岐しました。
main.jspでは、c:ifでエラーメッセージを表示し、c:forEachで投稿一覧を繰り返し表示しました。
これにより、画面の動きはそのままに、JSPからJavaのスクリプトレットをなくすことができました。
