JSP(JavaServer Pages)はServletと同じようにサーバ上で動作するJavaプログラムです。 JSPの仕様書には「最大の記述力と柔軟性を保ったまま動的コンテンツが簡単に作成できる」と書かれています。 実際、JSPはServletより簡単で、しかもServletと同等のことができるのです。 この章では、このようなJSPの特徴と使い方について説明します。

ServletとJSPの比較

初めにこれまで何度も取り上げた、Servletのサンプルソースを示します。 これは yourName="tanaka" というパラメーターを持つHTTPリクエストに対して「こんにちはtanakaさん」と表示させるものでした。

図解: サンプルソースコード

これと同じ機能を果たすコードをJSPで記述すると次のようになります(本来はheadタグなども出力すべきですが省略しています)(注10)が入ります。

図解: サンプルソースコード

HTTP(HyperText Transfer Protocol)


どうでしょうか、JSPの方がずっと短いですね。 そして、ServlerはJavaのプログラムそのものであるのに対し、JSPはHTMLにプログラムを埋め込んだものであることが、おわかりいただけるかと思います。 特に文字を出力する部分が、ServletはJavaのprint文でいちいち書かねばならないのに、JSPではそのまま書けば良いので非常にスッキリしています。

上の例でHTMLの仕様と異なるものは(a)(d)(e)の部分です。 これらでは通常のHTMLタグと区別するために "<" の直後に % を書いています。 そして % の次の @ や = でさらにJSPコードの働きを決めています(これらの文字の間に空白を入れてはいけません)。 これらの要素の使い方を覚えて行くことがJSPの学習になります。

(注10) このサンプルも Servletのサンプル と同じようにセキュリティ上の問題があります。

ServletとJSPの相違点と類似点

JSPは機能的にはServletと殆ど変わりません。 そして、上の例ではServletに比べてずっと簡単なように見えます。 ではServletは使わずに全部JSPで済ますべきでしょうか。 いいえ、もちろんそうではありません。 JSPにも欠点があるのです。 それは複雑なロジックの記述が苦手なことです。 特に業務アプリケーションに必須である詳細な例外処理やログ処理を書こうとするとかなり大変です。 この点ではServletの方が優れています。

実は論理に強いServletと表現に強いJSPを組み合わせ、それぞれの長所を活かして使うのが良いとされています。 それはMVCモデルという考え方です。MVCとはシステム全体をModel(データの処理)、View(データの表示)、およびController(入力処理)の3つの部分に分けて構築する方式です。データの処理と表示とを切り離すことで、互いに影響を受けにくい柔軟な構造が実現できます。

ServletとJSPには上述のような相違もありますが、似ている点もたくさんあります。 先に示した例でも、contentTypeの指定やgetParameterメソッドで入力パラメーターを受け取るところなどはServletとそっくりです。

それもそのはず、JSPとServletは親子の関係にあるのです。 と言うのはJSPはいったんServletに変換してから実行されるからです。 SunがJSPエンジンを開発するときServletはすでに存在していました。 そこでSunのエンジニア達はJSP固有のエンジンを作る代わりにServletへの変換プログラムを作り、実際の処理はServletのエンジンにまかせたのです。

それでは上の例のJSPはどんなServletに変換されるのでしょうか。 じつは Tomcat のフォルダの中を探していくと変換されたServletを見つけることができます。 それを章末の 変換結果 に示します。 もとのJSPと比較して見てください。

JSPの構文要素

JSPを理解するにはまずその文法を知らねばなりません。 JSPで使われる構文の要素を挙げてみましょう。

名称 形式 説明
ディレクティブ <%@ ~ %> JSPに係わる情報を設定する
式(expression) <%= ~ %> 出力用の簡易表示形式
宣言 <%! ~ %> メソッドや変数を宣言する
スクリプトレット <% ~ %> Javaのプログラムコードを記述
アクション <jsp:~ /> 別に定義した処理を呼ぶ
コメント文 <%-- ~ --%> JSPプログラムのコメントを記述

以上の6種です。 繰り返しになりますが、これらの機能と使い方を覚えることがJSP理解につながります。 以下、これらの要素を順に見て行きましょう。

ディレクティブ

ディレクティブはJSPに関する指示を記述するところです。 directiveには「指令する」と言う意味があります。 ディレクティブには次の3種類があります。

名称 説明
pageディレクティブ JSP全体に関わる様々な属性を指定します
includeディレクティブ 外部ファイルの内容を取り込みます
taglibディレクティブ JSPが使用するタグライブラリを宣言します

ディレクティブはJSPに固有のもので、それなりに覚えるべきことがたくさんあります。 以下に項を改めて説明します。

pageディレクティブ

pageディレクティブはJSPの属性の指定に使われます。 以下に主なpageディレクティブを示します。

属性 説明
import そのJSPがインポートして使用するパッケージを指定する
buffer そのJSPが出力時に使用するバッファのサイズを指定する
autoFlush バッファフル時に強制送信(true)か例外発生(false)かを指定する
errorPage 例外発生時にジャンプするページのURLを指定する
isErrorPage 現在のページが例外を処理するページか否かを示す
contentType JSPが出力する応答のMIMEタイプと文字セットを指定する
pageEncoding JSPページを生成する際の文字セットを指定する

各属性は 属性="属性値" と言う形式で指定します。 属性値は必ずダブルクオーテーション(")で囲まねばなりません。 空白で区切ることで複数の属性が指定できます。

図解: サンプルソースコード

以下にpageディレクティブのそれぞれの属性の意味と使用例を示します。

import属性

import属性はJavaのインポートと同じ意味を持ちます(注11)。 すなわちこれから使用するパッケージ名をあらかじめ宣言しておくことにより、そのパッケージ内のクラスをクラス名だけで使用できます。 宣言しておかないと長い正式な名前(完全限定名)で指定する必要があったのでした。 インポートするパッケージ名はカンマで区切って複数指定できます。

図解: サンプルソースコード

ただし、JSPでよく使う以下の3つのパッケージはすでに指定されているのであえて指定する必要はありません。

図解: サンプルソースコード

章末の 変換結果 を見てください。 3~5行目に上記のパッケージのインポート文が書かれているのがわかります。 つまりimport属性で何も指定しなくてもこれらのインポート文はServletへの変換の際に自動的に生成されるのです。

(注11) Javaのインポートについては「Web開発のためのJava入門 5章:ソースの構造」の『インポート文』をご覧ください。

buffer属性

JSPではhtmlで書いた内容とプログラムが生成した内容とが組み合わされて出力されます。 その内容はそのつどクライアントに出力されるのではなく、いったん出力バッファに格納され、JSPのページが最後まで実行されたときにまとめて出力されます。

buffer属性ではこのバッファのサイズをKB単位で指定します。 特別な値としてnoneを指定するとバッファは使われません。 サイズを指定するときには数値の後ろにkbを付けます。 buffer属性を明に指定しないときのデフォルト値は8KBです。

以下はbuffer属性に16KBを指定する例です。

図解: buffer属性

章末の 変換結果 を見てください。 35行目に8192の数字が見えます。 ここではgetPageContextメソッドの引数としてバッファサイズをセットしているのです。 サンプルソースではbuffer属性を指定していないので、デフォルト値の8KBが指定されているのです。

バッファの内容がいったん出力されてしまうと、その後にエラーが発生しても、その情報はクライアントに伝わりません。 このことは5章の エラーページ で説明しました。 したがって、処理の後半でエラーが発生する可能性があるときは、出力データの大きさを予測し、それに合わせてバッファサイズを大きくとらねばなりません。

autoFlush属性

出力バッファが一杯になった時に強制的に出力(フラッシュ)するか(true)、または例外を投げるかどうか(false)、を指定します。 デフォルト値はtrueです。 bufferがnoneに指定されている場合はautoFlashはfalseにできません。

図解: サンプルソースコード

errorPage属性

そのJSPで処理されなかった例外を処理するページのURLを指定します。 例外を処理するページはpageディレクティブでisErrorPage属性をtrueに設定します。 これについてはすぐ次の項で述べます。

図解: サンプルソースコード

isErrorPage属性

別のJSPからの例外を処理するかどうかを指定します。 trueの場合は別のJSPページで発生した例外を参照するexecptionオブジェクトが暗黙的に宣言されます。 デフォルト値はfalseです。 サンプルソースではこの属性を指定していないので、デフォルトのfalseが働いて章末の 変換結果 ではexecptionオブジェクトが宣言されていません。

図解: サンプルソースコード

contentType属性

JSPが出力する応答のMIMEタイプと文字セットを指定します。 この属性は2章で説明したServletの setContentTypeメソッド と同じ働きをします。 日本語の文字を使う応答を出力するときは必ず以下のように日本語文字セットを指定する必要があります。

図解: サンプルソースコード

pageEncoding属性

上述のcontentType属性がJSPが出力する応答の文字セットを指定するのに対して、pageEncoding属性はJSPページを生成する際の文字セットを指定するものです。 特に次に述べるincludeディレクティブや、後にアクションの項で説明するincludeアクション、forwardアクションで別のページを指定する場合に有効です。 これらの別ページで日本語の文字を使うときは必ず以下のように日本語文字セットを指定する必要があります。

図解: サンプルソースコード

includeディレクティブとtaglibディレクティブ

pageディレクティブの属性の説明をしてきましたが、JSPのディレクティブにはpage以外にincludeとtaglibがあります。 これら2つはともにJSPの部品化や再利用に使われます。

includeディレクティブ

その位置に別のファイルを取り込むことを指示します。 以下の例ではheader.htmlと言うファイルをこのディレクティブが記述された位置に取り込みます。

図解: サンプルソースコード

taglibディレクティブ

taglibディレクティブはカスタムタグと呼ばれる自作の処理ルーチンと、それを呼び出す接頭辞を関連づけるものです。 以下、例1はtaglibディレクティブ、例2はそこで定義された接頭辞utlを使ったカスタムタグの例です。

図解: サンプルソースコード

カスタムタグの話は後のアクションの項でも出てきます。

生成されるServlet

先にJSPはServletに変換されて実行されるとお話ししました。 次の宣言とスクリプトレットに入る前にJSPから生成されるServletの構造を説明しておきます。 章末の 変換結果 を見てください。 全体として次のような構造をしていることがわかります。 つまりfoo_jspと言うクラスの中に_jspServiceと言うメソッドがあり、その中にjavaのプログラムが書かれているのです。

図解: サンプルソースコード

_jspServiceメソッドは頭に_jspがついているので、気づきにくいかもしれませんが、これは2章の Servletの起動から終了まで で説明したserviceメソッドに相当するものです。 つまりクライアントからのリクエストのたびにこのメソッドが呼び出されます。

宣言

宣言ではJSPで使用する変数とメソッドを記述します。 変数の初期値を設定することも可能です。 以下ではint型の変数cを定義して初期値10を代入しています。 宣言で定義された変数は最初の一度だけ初期化されます。

図解: サンプルソースコード

宣言の中にはJavaの文をそのまま書きます。 したがって行末にセミコロン";"を必ず付ける必要があります。 宣言では上の例のような変数だけでなく、次のようにメソッドも宣言して実装することができます。

図解: サンプルソースコード

宣言はServletに変換されるときに前項で説明した_jspServiceメソッドの外側に配置されます。 また、宣言で記述した変数とメソッドは基本的には次項で述べるスクリプトレットから呼び出されるだけで、それだけで単独に実行されることはありません。 ただし、例外が2つあります。 1つは変数の初期化です。 先に述べたように変数の初期化は最初に一度だけ実行されます。

2つ目は特殊メソッドです。 jspInitとjspDestroyと言う名前のメソッドを宣言しておくとそれらは、それぞれ初期化時と破棄時に呼ばれます。 お気づきのようにこれらはそれぞれServletのinitとdestroyに相当するものです。 呼ばれるタイミングについては後述のJSPのライフサイクルのところで説明します。

スクリプトレット

スクリプトレットにはJavaのプログラムを記述します。 スクリプト(script)とは元々は手書きの文字のことですが、ソフトウェアの世界ではあまり本格的ではないプログラムのことを指すのに使われます。 スクリプトレットは小さいスクリプトと言うことで、HTMLに埋め込まれたJavaプログラムの断片というニュアンスを良く表しています。

スクリプトレットは_jspServiceメソッドの中に埋め込まれます。 この埋め込みはhtmlの地(じ)の文も含めて記述順に行われます。 例を見てみましょう。

図解: サンプルソースコード

この例は次のように変換されます。

図解: サンプルソースコード

スクリプトレットは宣言と同じようにJavaの構文そのものなので文の末尾には必ずセミコロン";"が必要なことに注意してください。 スクリプトレットで宣言した変数は_jspServiceメソッドのローカル変数(注12)として宣言されます。 したがって、初期値をセットせずに使うとコンパイルエラーになります。 これに対し「宣言」で宣言した変数はインスタンス変数となりデフォルト値で初期化されています。

以下の例はあまり現実的ではありませんが、JSPの仕様を理解するのに役立ちます。 これを実行するとどうなるでしょうか。

図解: サンプルソースコード

01行目で型が定義されていない i を使ったのでコンパイルエラーになると考えた方、着想はするどいですが、正しくはありません。 なぜなら、01行目のスクリプトレットより先に03行目の宣言がまず実行されるからです。 その後_jspServiseメソッドが呼ばれ01行目が実行されて、その i に5が代入されます。 この i はインスタンス変数です。

次に02行目で再度 i が宣言されますが、これは_jspServiceメソッドのローカル変数であり、01行目の i とは別ものになります。 04行目で単に i とするとローカル変数の i が呼ばれ、this.iとするとインスタンス変数の i が呼ばれます。 したがって9,5と表示されるのが正解です。

(注12) ローカル変数とはメソッドの中で宣言された変数のことです。 「Web開発のためのJava入門 4章:メソッド」の『変数のスコープと初期化』を参考にしてください。

式(Expression)

式は出力文の中にJavaの出力結果を埋め込む時に使います。 式の構文は次の通りです。 スクリプトレットは文末に必ずセミコロン";"が必要でしたが、式はJavaの構文ではないのでセミコロンを付けてはいけません。

図解: サンプルソースコード

この章の最初にServletとの比較で提示したJSPのサンプルソースでは、式は次のように使われていました。

図解: サンプルソースコード

式はスクリプトレットの出力文の代わりなので、式の部分は必ずスクリプトレットで置き換えることができます。 この例は全部をスクリプトレットにして次のように記述することもできます。


図解: サンプルソースコード

もちろん次のように書いてもかまいません。


図解: サンプルソースコード

アクション

HTTP(HyperText Transfer Protocol)


これまで述べた宣言、スクリプトレット、式はJavaのプログラムを1行ずつ記述するものでした。 これに対しアクションはひとつのまとまった処理を実行させることができます。 この意味ではサブルーチンに似ています。 ここではJSPが標準的に提供するアクションのうちincludeとforwardについて説明します。

include

別のページを呼び出して実行することを指示します。 以下の例ではheader.htmlと言うページを呼び出して実行します。

図解: サンプルソースコード

アクションの構文はこれまでの % を使った構文とは異なり、XMLの仕様に従っています。 そこで終了タグかまたはそれに代わる最後の / が必要になります。 以下は呼び出すページにパラメーターを与える例です。

図解: サンプルソースコード

1行目のjsp:includeは3行目に終了タグがあるので行末には / が無く、2行目のjsp:paramは独立した終了タグが無いので行末に / が付いていることに注意してください。 パラメーターはパラメーター名(name)とその値(value)のペアで記述します。 上の例ではtitleと言う名前のパラメーターに"JSP入門"と言う値がセットされてheader.htmlに渡されます。

includeアクションの機能は先に説明したincludeディレクティブに似ています。 includeディレクティブはその位置に指定されたファイルを読み込み、全体をServletに変換して実行されます。 これに対しincludeアクションはクライアントからリクエストが来てJSPが実行されるたびに呼び出されて実行されます。

forward

forwardアクションも他のページと協力して処理を行う仕組みです。 includeとの相違はincludeが、処理が終わると元のページに制御が戻ってくるのに対し、forwardは行ったきり戻ってこないことです。 これは5章で説明したリクエストディスパッチャのforwardメソッドとincludeメソッドの関係と同じです。

カスタムタグ

標準提供のアクションではなく、ユーザーが独自に定義したアクションを呼び出せるものがあります。 これがカスタムタグと言われるものです。 カスタムタグとそれを呼び出す接頭辞を関連づけるのがtaglibディレクティブであることは、ディレクティブの項で説明しました。

JSPにはJavaのプログラムを埋め込むことができますが、そうするとJSP自身が見通しの悪いものになってしまいます。 カスタムタグを使ってプログラムをJSPの外に追い出すことによってJSPの可読性を上げることができます。

カスタムタグは自分で作ることもできますが、Sun自身や他の会社、団体が有償または無償で様々なカスタムタグを公開しています。 またアプリケーションサーバのメーカーが他社との差別化のために独自のカスタムタグを提供しています。

このようにカスタムタグはJSPの可能性を大きく広げるものです。 しかし、一般の業務アプリ開発者がカスタムタグを作るケースは少ないと思いますので、ここではこれ以上説明しません。 ただし、提供されたものを活用していく機会は多くあります。 使い方はそれぞれのカスタムタグによって異なるので、必要になったときに学習してください。

JSTL

JSTL(JavaServer Pages Standard Tag Library)は、JSPでよく利用される標準的なカスタムタグをまとめたものです。JSTLにはいくつかの種類がありますが、ここではその中のcoreタグを紹介します。カスタムタグを使用するにはtaglibディレクトリでの定義が必要です。coreタグを定義するtaglibディレクトリは以下のようになります。

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

主なcoreタグとその使用例を示します。

タグ 説明 使用例
<c:out> 出力 <c:out value="${age}" />
<c:if> 単一条件分岐 <c:if test="${18<=age}"> 成人 </c:if>
<c:choose>
<c:when>
<c:otherwise>
複数条件分岐 <c:choose>
 <c:when test="${20<=age}">20才以上</c:when>
 <c:when test="${10<=age}">10才代</c:when>
 <c:otherwise>9才以下</c:otherwise>
</c:choose>
<c:forEach> 繰返し <c:forEach var="処理で使う変数名" items="配列やリスト名" >
 処理
</c:forEach>

使用例にある${…}はEL式です。EL式についてはこの章の最後の説明をご覧ください。ifタグではtest属性で評価する条件を指定します。testの結果がtrueのときのみifブロック内の表示が行われます。つまり上の例ではageが18以上のときにのみ「成人」が表示されるのです。chooseブロック内では上から順にwhenタグのtest条件を評価しtrueならばwhenブロックの内の表示をしてchooseブロックから抜けます。forEachの具体的な使用例はEL式のところをご覧ください。

JSPのライフサイクル

HTTP(HyperText Transfer Protocol)

JSPにもライフサイクルがあります。 図を見てください。 何度か説明しましたが、JSPはServletに変換されて実行されます。 プログラマーが書いたJSPに対して、最初のリクエストが来ると、JSPコンテナはServletソースに変換するのです。

そして次にそれをコンパイルします。 Servletではプログラマーがコンパイルしなければならなかったのに対し、JSPコンテナは自動変換の後、コンパイルも自動的にやってくれるのです。 そしてそれがメモリにロードされます。 もしjspInitメソッドが宣言されていればまずそれが実行され、次に_jspServiceメソッドが実行されます。 jspInitメソッドが宣言されていなければ、直ちに_jspServiceメソッドが実行されます。 これらの実行の結果、クライアントにレスポンスが返ります。

2度目のリクエストからはメモリ上にある_jspServiceメソッドがすぐに実行され、レスポンスが返ります。 したがって、最初のリクエストだけはレスポンスが出るまでに少し時間が多くかかります。 必要なら事前にコンパイル&ロードしておくことも可能です。

JSPコンテナの消滅時にはjspDestroyが宣言されていれば、それが呼ばれます。

JSPのスコープ

HTTP(HyperText Transfer Protocol)

JSPにもServletと同じように スコープ があります。 スコープとはデータが有効な範囲のことでした。 Servletにはリクエスト、セッション、アプリケーションの3種のスコープがあり、用途に応じて選択していました。 JSPではこれに加えてページというスコープがあります。 ページはリクエストよりさらに小さい範囲になります。

ページスコープのオブジェクトはPageContextインターフェースを実体化したものです。 各スコープのオブジェクトと対応するインターフェースをまとめておきます。 ページスコープ以外はServletと同じです。

(a)ページスコープのオブジェクト PageContextインターフェース
(b)リクエストスコープのオブジェクト ServletRequestインターフェース
(c)セッションスコープのオブジェクト HttpSessionインターフェース
(d)アプリケーションスコープのオブジェクト ServletContextインターフェース

ページスコープの有効範囲はJSPの1ページ、すなわち <http> から </http> までです。 これは普通1つのJSPとして記述されます。 こんなものにどうしてわざわざ共有データ領域などが必要なのでしょうか。 それはincludeディレクティブやカスタムタグで述べたようなJSPの部品化した時に、それらの各コンポーネント間でデータを共有するために使われるからです。

暗黙オブジェクト

この章の最初にServletとの比較で提示したJSPのサンプルソースではServletのオブジェクト名でreqだったところがrequestになっていたのに気づかれたでしょうか。

図解: サンプルソースコード

HTTP(HyperText Transfer Protocol)

ServletのサンプルソースではdoPostメソッドの引数としてreqを定義していたので、その名前が使われました(Servletのサンプルソースの(2)行目)。 ところが、JSPではそのような定義がどこにもありません。 どうなっているのでしょうか。

実はJSPではServletに変換するときHttpServletRequestインターフェースのオブジェクトにはrequestという名が付けられます。 章末の 変換結果 の16行目を見てください。 これを暗黙オブジェクトと言います。 JSPには9種の暗黙オブジェクトがあります。 以下にその名称と概要を説明します。

名称 スコープ オブジェクトの内容(変数の型)
request request 現ページへのリクエスト情報(HttpServletRequest)
response page レスポンス送信のための情報(HttpServletResponse)
session session セッション情報(HttpSession)
application application Webアプリケーション環境(ServletContext)
config page Servletの設定情報(ServletConfig)
out page クライアントへの出力情報(JspWriter)
page page このページ自身(this)
pageContext page pageスコープ情報/ページの環境情報(PageContext)
exception page 例外処理のための情報(Throwable)

ページスコープの情報を扱うオブジェクトはpageではなく、pageContextですので注意してください。

章末の 変換結果 でこれらの変数が宣言され初期化されているのを確認してください。 ただし変数exceptionは宣言されていません。 pageディレクティブのisErrorPageがデフォルトのfalseのままだからです。

EL式

JSP2.0からEL式が使えるようになりました。ELはExpression Languageの略です。EL式を使うと画面への表示がとても簡単になります。クラスオブジェクトのリストからデータを取り出して表を作成することもできます。ここではEL式の基本的な機能を紹介します。EL式の書式は次の通りです。

    ${式やオブジェクト名}

たとえば以下のようなEL式を書くと、ブラウザには式の値である36が表示されます。

    ${3*12}

このような単純な式だけでなくオブジェクトの内容も表示できます。オブジェクトとはデータに名前を付けたものです。JSPではオブジェクトはセッションスコープやリクエストスコープなどのスコープのデータとして記憶させることができます。例えば3章セッションデータの格納と取り出しで説明したように、セッションスコープへのデータの格納は以下で行えます。

    ses.setAttribute("id", "PDG00072");

ここでsesはセッションオブジェクトの名前です。これは"PDG00072"というオブジェクトをidという名前でセッションオブジェクトへ格納することを指示しています。Servletに上のプログラムを書いておくと、JSPで以下のようなEL式を書くだけで PDG00072 と表示されます。

    ${id}

セッションスコープのデータを取り出すEL式を厳密に書くと ${sessionScope.id} なのですが、スコープ名の sessionScope は省略できます。それはJSPが各スコープで id という名前のオブジェクトを順次探してくれるからです。探す順序はページスコープ→リクエストスコープ→セッションスコープ→アプリケーションスコープと狭い順です。ですからもしリクエストスコープに id という別のオブジェクトがあればその内容が表示されてしまい、セッションスコープの id は表示されません。指定したオブジェクトがどのスコープにも無い場合は何も表示されません。

複数データの表示

EL式では単一のデータだけでなく、配列やコレクション(ListやMap)、およびクラス(インスタンス)のような複数のデータも表示できます。例えばnameという配列(Listでもよい)にデータを格納し、Servletで次のようにスコープに格納しておきます。ここではセッションスコープではなくリクエストスコープに格納しました。

    request.setAttribute("list", name);

配列やListのデータはその名前の後に[n]を付けて指定します。nはインデックスを指定する数字です。例えば ${list[3]} とするとname[3]の要素が表示されます。

クラスの例も見てみましょう。まずPersonというクラスに氏名nameと年齢ageという変数、コンストラクター、および2つの変数のゲッターを定義しておきます。

  class Person { 
    private String name; 
    private int age; 
    public Person(String n, int a) {name = n; age = a;} 
    public String getName() {return name;} 
    public int getAge() {return age;} 
  } 

次にServletでこのPersonクラスをnewしてtanakaというオブジェクトを生成し、それをリクエストスコープにpersonという名前で格納します。

  Person tanaka = new Person("田中", 28); 
  request.setAttribute("person", tanaka); 

EL式でクラスオブジェクトの内容を表示するには、「オブジェクト名.変数名」のように記述します。オブジェクト名はスコープに格納されているデータ名ですからtanakaではなくpersonです。なおこのように記述できるためにはPersonクラス定義した変数のゲッターが欠かせません。

  氏名:${person.name} 
  年齢:${person.age} 

すると画面には次のように表示されます。

  氏名:田中 
  年齢:28 

クラスのリストの表示

最後にクラスのデータが複数ある場合です。まず以下のようにPersonクラスのオブジェクトを複数作ってpersonsというArrayListに格納し、それをplistという名前でリクエストスコープにセットします。

  List<Person> persons = new ArrayList<>(); 
  persons.add(new Person("田中", 28)); 
  persons.add(new Person("山田", 45)); 
  persons.add(new Person("高橋", 20)); 
  request.setAttribute("plist", persons); 

JSPではJSTLで提供されているforEachを使って繰り返し表示のプログラムを書きます。forEachはこの章の中程のJSTLの項で紹介しました。var属性で繰り返し処理の中で使う変数名を指定し、items属性で繰り返し対象データを保持している配列やList名を指定します。

  <c:forEach var="per" items="${plist}"> 
    ${per.name} ${per.age}<br> 
  </c:forEach> 

こうすると画面には以下のように3人の氏名と年齢が表示されます。ここでは説明を分かりやすくするためデータの部分だけを示しましたが、実際にはテープルタグなどを活用してきれいに仕上げましょう。

  田中 28 
  山田 45 
  高橋 20 

この例では各変数の対応が明確になるように、あえてplistやperのような中途半端な名前にしました。実際にはplistは元のリストデータと同じpersonsとし、perはPersonクラスのオブジェクトであることを明確に示すpersonとした方が良いでしょう。

確認問題

(1) 以下の説明でJSPのことを述べているものを全部挙げてください。

a.HTMLにプログラムコードを埋め込んだ形式をしている。
b.ロジックの記述が得意である。
c.文字の出力部分の記述が得意である。
d.Servletと組み合わせて使わない方がよい。
e.Servletに変換されて実行される。
(2) JSPの構文要素とその形式で対応するものを選んでください。

[構文要素]
1.ディレクティブ
2.式
3.宣言
4.スクリプトレット

[形式]
a.<% ~ %>
b.<%! ~ %>
c.<%@ ~ %>
d.<%= ~ %>
(3) pageディレクティブでbufferがnoneに指定されている場合はautoFlashはfalseにできない理由は何ですか。
(4) 次のうち式として正しいのはどれですか。 またスクリプトレットとして正しいのはどれですか。

a.<% mydata(); %>
b.<%= mydata(); %>
c.<%= mydata() %>
d.<% mydata() %>
(5) 次のJSPを実行するとどうなりますか。

<html><body>
<%! int a; %>
<% int b; %>
<%= a+b %>
</body></html>
(6) JSPのライフサイクルで実行される順序に並べてください。

a.コンパイル
b.メモリにロードして実行
c.Servletに変換
d.クラスファイルの生成
(7) JSPのスコープを小さい順にすべて挙げてください。
(8) 前問の各スコープに対応する暗黙オブジェクトを挙げてください。

解答

(1) 正しいのはa、c、e
(2) 1-c、2-d、3-b、4-a
(3) bufferがnoneに指定されていると出力データはすぐに送信されてしまうが、このときautoFlashがfalseになっていると例外が発生してしまうから
(4) 正しい式はc、正しいスクリプトレットはa
(5) コンパイルエラー(bが初期化されていない)
(6) c、a、d、b
(7) page、request、session、application
(8) pageContext、request、session、application

変換結果

図解: サンプルソースコード
ページの先頭へ