サーブレット&JSPの基本|JSPを簡潔にするEL式

JSPからJavaコードを減らして、画面表示をもっと読みやすくする。EL式でJavaBeansの値をすっきり出力しよう

JSPは、Webアプリケーションのビューとして画面表示を担当するファイルです。

サーブレットやモデルで処理した結果を受け取り、HTMLとしてブラウザに表示する役割を持っています。

これまでの学習では、リクエストスコープ、セッションスコープ、アプリケーションスコープなどにJavaBeansインスタンスを保存し、JSP側でその値を取り出して表示してきました。

たとえば、スコープに保存されたJavaBeansをJSPで表示するとき、次のような処理を書いていました。

まず、pageディレクティブでJavaBeansのクラスをimportします。

次に、getAttributeでスコープからインスタンスを取得します。

さらに、取得したObject型のインスタンスを本来の型にキャストします。

最後に、getterメソッドを呼び出してプロパティの値を表示します。

この書き方は、Javaの処理としては自然です。しかし、画面表示を担当するJSPの中にJavaコードが増えてしまうため、JSPが読みにくくなりやすいという問題があります。

そこで役立つのが、EL式です。

EL式は、Expression Languageの略で、JSPの中でスコープに保存された値やJavaBeansのプロパティを簡潔に取り出すための記法です。

たとえば、sessionスコープにmemberという属性名で保存されたJavaBeansのnameプロパティを表示したい場合、EL式では次のように書けます。

${member.name}

とても短く、HTMLの中にも自然に書きやすい形です。

この記事では、EL式の基本的な書き方、スコープとの関係、EL式の暗黙オブジェクト、JavaBeansのプロパティ取得、演算子、コレクションの扱い、そしてスクリプト要素との関係について学習していきます。

EL式とは

EL式は、JSPの中で値を簡潔に出力するための書き方です。

スコープに保存されたインスタンスや、そのインスタンスが持つプロパティを、短い記述で取り出せます。

基本形は、ドル記号と中カッコを使って書きます。

${式}

中カッコの中に書く内容が、EL式として評価されます。

たとえば、memberという属性名でスコープに保存されているインスタンスを取得したい場合は、次のように書きます。

${member}

memberインスタンスのnameプロパティを表示したい場合は、次のように書きます。

${member.name}

このように、属性名とプロパティ名をドットでつなぐことで、JavaBeansのgetterメソッドを自動的に呼び出せます。

これまでのJSPの書き方

EL式を使わない場合、JSPでJavaBeansの値を表示するには、いくつかの手順が必要でした。

たとえば、セッションスコープにmemberという属性名でMemberインスタンスが保存されているとします。

そのnameプロパティを表示する場合、従来の書き方では次のような流れになります。

<%@ page import="model.Member" %>
<%
Member member =
        (Member) session.getAttribute("member");
%>
<%= member.getName() %>

この書き方では、JSPの中にJavaの処理が入っています。

従来の書き方で必要な処理

処理内容
importJSPでMemberクラスを使えるようにする
getAttributeセッションスコープからmemberを取得する
キャストObject型をMember型に変換する
getter呼び出しgetNameでnameプロパティを取得する
スクリプト式取得した値をHTML内に出力する

このように、1つの値を表示するだけでも、JSP内にJavaコードが増えてしまいます。

JSPを画面表示中心のファイルとして見やすく保つには、もう少し簡潔な書き方が望ましいです。

EL式を使った書き方

EL式を使うと、先ほどの処理は次のように書けます。

${member.name}

これだけで、スコープに保存されたmemberインスタンスを探し、そのnameプロパティを取得して出力できます。

従来の書き方とEL式の違い

内容従来の書き方EL式
クラスのimport必要不要
getAttribute必要不要
キャスト必要不要
getterメソッドの呼び出し必要自動で行われる
表示用の記述<%= member.getName() %>${member.name}

EL式を使うと、JSP内のJavaコードを大きく減らせます。

その結果、JSPがHTMLに近い見た目になり、画面の構造を読み取りやすくなります。

図1:EL式でJavaBeansのプロパティを簡潔に表示する

この図から分かること

EL式を使うと、JSP内でJavaBeansのプロパティを簡潔に表示できます。

従来は、クラスのimport、getAttributeによる取得、キャスト、getterメソッドの呼び出し、スクリプト式による出力が必要でした。

EL式では、${member.name}のように書くだけで、スコープに保存されたmemberインスタンスを探し、nameプロパティのgetterメソッドを自動的に呼び出して値を出力できます。

EL式の基本文法

EL式は、属性名やプロパティ名を使って値を取得します。

基本的な書き方は、次の2つです。

スコープに保存されたインスタンスを利用するEL式

書き方内容
${属性名}スコープに保存されているインスタンスを取得する
${属性名.プロパティ}スコープに保存されているインスタンスのプロパティ値を取得する

たとえば、memberという属性名で保存されたMemberインスタンスがあるとします。

そのインスタンス自体を参照する場合は、${member}と書きます。

そのインスタンスのnameプロパティを表示する場合は、${member.name}と書きます。

プロパティ名を指定すると、対応するgetterメソッドが自動的に実行されます。

プロパティ名とgetterメソッドの関係

EL式では、プロパティ名を指定すると、自動的にgetterメソッドが呼び出されます。

たとえば、次のEL式を考えます。

${member.name}

この場合、memberインスタンスのgetNameメソッドが呼び出されます。

EL式とgetterメソッドの対応

EL式自動的に呼び出されるgetter
${member.name}getName
${member.age}getAge
${studyPace.goalHours}getGoalHours
${studyPace.actualHours}getActualHours

ここで指定するのは、フィールド名そのものというより、JavaBeansのプロパティ名です。

たとえば、getNameというgetterがある場合、EL式ではnameと書きます。

getGoalHoursというgetterがある場合、EL式ではgoalHoursと書きます。

もし、指定したプロパティに対応するgetterメソッドが存在しない場合は、PropertyNotFoundExceptionが発生することがあります。

EL式とスコープの関係

EL式では、スコープに保存されたインスタンスを自動的に探してくれます。

たとえば、${member.name}と書いた場合、EL式はmemberという属性名のインスタンスをスコープから探します。

このとき、検索するスコープには順番があります。

EL式が検索するスコープの順番

順番スコープ
1ページスコープ
2リクエストスコープ
3セッションスコープ
4アプリケーションスコープ

EL式は、まずページスコープを探します。

見つからなければリクエストスコープを探します。

そこにもなければセッションスコープを探します。

最後にアプリケーションスコープを探します。

この順番で属性名を探し、最初に見つかったインスタンスを利用します。

ページスコープとは

ページスコープは、JSPファイルだけが持つスコープです。

ページスコープに保存したインスタンスは、そのJSPファイルの中でだけ利用できます。

4種類のスコープ

スコープ主な用途
ページスコープそのJSP内だけで使う情報
リクエストスコープフォワード先まで一時的に渡したい情報
セッションスコープログイン中のユーザー情報など、利用者ごとに保持したい情報
アプリケーションスコープ全ユーザーで共有したい情報

これまでよく使ってきたのは、リクエストスコープ、セッションスコープ、アプリケーションスコープです。

EL式では、これらに加えてページスコープも検索対象になります。

属性名が見つからない場合

EL式で指定した属性名が、どのスコープにも存在しない場合があります。

たとえば、memberという属性名でどのスコープにもインスタンスが保存されていない状態で、次のように書いたとします。

${member.name}

この場合、例外が発生せず、何も出力されないことがあります。

属性名が見つからない場合の注意

状況結果
指定した属性名がスコープにない何も表示されない
例外が出るか基本的には例外が出ず、気づきにくい
注意点属性名の書き間違いや保存漏れに気づきにくい

何も表示されないだけだと、画面の作り方が間違っているのか、サーブレット側でsetAttributeを忘れているのか、属性名がずれているのかが分かりにくくなります。

EL式を使うときは、サーブレット側で保存した属性名と、JSP側で指定する属性名が一致しているかを丁寧に確認しましょう。

同じ属性名が複数のスコープにある場合

EL式は、ページスコープ、リクエストスコープ、セッションスコープ、アプリケーションスコープの順に属性を探します。

そのため、複数のスコープに同じ属性名のインスタンスが保存されている場合、先に見つかったものが使われます。

たとえば、リクエストスコープとセッションスコープの両方にmsgという属性名のインスタンスが保存されているとします。

この状態で次のように書くと、リクエストスコープのmsgが優先されます。

${msg}

セッションスコープのmsgを使いたい場合は、検索するスコープを明示します。

${sessionScope.msg}

同じ属性名がある場合の動き

状態${msg}で取得されるもの
リクエストスコープにmsgがあるリクエストスコープのmsg
リクエストスコープになく、セッションスコープにmsgがあるセッションスコープのmsg
セッションスコープになく、アプリケーションスコープにmsgがあるアプリケーションスコープのmsg

同じ属性名を複数のスコープで使うと、どの値が表示されているのか分かりにくくなることがあります。

必要に応じて、EL式の暗黙オブジェクトを使い、検索対象のスコープを明示しましょう。

図2:EL式がスコープを探す順番

この図から分かること

EL式でスコープを指定しない場合、ページスコープ、リクエストスコープ、セッションスコープ、アプリケーションスコープの順に属性名を探します。

同じ属性名が複数のスコープにある場合は、先に見つかったインスタンスが利用されます。

特定のスコープから取得したい場合は、sessionScopeやrequestScopeのようなEL式の暗黙オブジェクトを使って、検索対象を明示できます。

EL式の暗黙オブジェクト

EL式には、スコープやリクエスト情報を扱うための暗黙オブジェクトが用意されています。

これは、JSPの暗黙オブジェクトとは別物です。

JSPの暗黙オブジェクトには、request、response、session、applicationなどがあります。

一方、EL式の暗黙オブジェクトには、requestScope、sessionScope、paramなどがあります。

主なEL式の暗黙オブジェクト

暗黙オブジェクト名説明
pageScopeページスコープを表す
requestScopeリクエストスコープを表す
sessionScopeセッションスコープを表す
applicationScopeアプリケーションスコープを表す
paramリクエストパラメータの名前と値を対応させたMapオブジェクト
headerリクエストヘッダーの名前と値を対応させたMapオブジェクト
cookieクッキーの名前と値を対応させたMapオブジェクト

たとえば、セッションスコープに保存されたloginUserを明示的に取得したい場合は、次のように書けます。

${sessionScope.loginUser.name}

リクエストスコープに保存されたerrorMsgを明示的に取得したい場合は、次のように書けます。

${requestScope.errorMsg}

スコープを明示すると、どのスコープの値を表示しているのか分かりやすくなります。

JSPの暗黙オブジェクトとの違い

EL式の暗黙オブジェクトと、JSPの暗黙オブジェクトは名前が似ているものがあります。

しかし、同じものではありません。

JSPの暗黙オブジェクトとEL式の暗黙オブジェクト

用途JSPの暗黙オブジェクトEL式の暗黙オブジェクト
セッションを扱うsessionsessionScope
リクエストを扱うrequestrequestScope
アプリケーションを扱うapplicationapplicationScope

JSPのスクリプトレット内で使う場合は、session.getAttributeのようにJSPの暗黙オブジェクトを使います。

EL式の中で使う場合は、${sessionScope.loginUser}のようにEL式用の暗黙オブジェクトを使います。

表記が異なるため、混同しないようにしましょう。

EL式でJSPを改良する

ここからは、EL式を使ってJSPを簡潔にする例を見ていきます。

今回は、学習ペース診断の結果画面を表示するJSPを例にします。

サーブレット側で、診断結果を表すStudyPaceインスタンスを作成し、studyPaceという属性名でリクエストスコープに保存しているとします。

StudyPaceインスタンスには、次のようなプロパティがあるものとします。

StudyPaceインスタンスのプロパティ

プロパティ内容対応するgetter
goalHours目標学習時間getGoalHours
actualHours実際の学習時間getActualHours
achievementRate達成率getAchievementRate
judgment判定getJudgment

EL式を使うと、これらのプロパティをJSPで簡潔に表示できます。

EL式を使用したJSPファイルの例

ファイル名: studyCheckResult.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>学習ペース診断</title>
</head>
<body>
<h1>学習ペース診断の結果</h1>
<p>
目標学習時間:${studyPace.goalHours}時間<br>
実際の学習時間:${studyPace.actualHours}時間<br>
達成率:${studyPace.achievementRate}%<br>
判定:${studyPace.judgment}
</p>
<a href="StudyCheck">戻る</a>
</body>
</html>

studyCheckResult.jspは、src/main/webapp/WEB-INF/jspディレクトリに配置する想定です。

このJSPでは、JavaBeansのクラスをimportしていません。

また、request.getAttributeでstudyPaceを取得していません。

それでも、${studyPace.goalHours}のように書くことで、スコープに保存されたStudyPaceインスタンスのプロパティを表示できます。

ブラウザの表示例

http://localhost:8080/study/studyCheckResult.jsp

EL式を使うと不要になる記述

EL式を使うと、JSP内のJavaコードをかなり減らせます。

先ほどのstudyCheckResult.jspでは、次のような記述が不要になっています。

EL式によって不要になるもの

従来必要だったものEL式で不要になる理由
StudyPaceクラスのimportEL式ではクラスを直接指定しないため
request.getAttributeEL式がスコープから属性名を探すため
StudyPace型へのキャストEL式が取得したインスタンスのプロパティを扱うため
getGoalHoursなどのgetter呼び出しプロパティ名を書くとgetterが自動実行されるため
スクリプト式EL式をHTML内に書くだけで出力されるため

JSPは画面表示を担当するファイルです。

EL式を使うことで、Javaの処理を減らし、HTMLに近い形で画面を作成しやすくなります。

EL式のプロパティ取得で注意すること

EL式では、プロパティ名を書くとgetterメソッドが自動的に呼び出されます。

たとえば、次のEL式では、StudyPaceインスタンスのgetGoalHoursメソッドが呼び出されます。

${studyPace.goalHours}

ここで大切なのは、StudyPaceクラスにgetGoalHoursメソッドが存在することです。

もし、プロパティ名に対応するgetterメソッドが存在しない場合、PropertyNotFoundExceptionが発生することがあります。

注意したい例

EL式必要なgetter
${studyPace.goalHours}getGoalHours
${studyPace.actualHours}getActualHours
${studyPace.achievementRate}getAchievementRate
${studyPace.judgment}getJudgment

EL式でうまく表示されない場合は、サーブレット側でスコープに保存している属性名、JavaBeansのプロパティ名、getterメソッドの名前を確認しましょう。

図3:EL式で診断結果画面をすっきり表示する

この図から分かること

サーブレット側でStudyPaceインスタンスをstudyPaceという属性名でリクエストスコープに保存しておくと、JSP側ではEL式で簡潔に表示できます。

studyCheckResult.jspでは、${studyPace.goalHours}のように書くだけで、StudyPaceインスタンスのgetterメソッドが自動的に呼び出されます。

これにより、JSP内にimport、getAttribute、キャスト、getter呼び出し、スクリプト式を書かずに済みます。

EL式の特徴

EL式には、JSPを簡潔にするための便利な特徴があります。

EL式の主な特徴

特徴内容
スコープを自動検索する属性名を指定すると、複数のスコープから探してくれる
importが不要JavaBeansのクラスをJSPでimportしなくてもよい
getAttributeが不要EL式がスコープから属性を探す
getterを自動実行するプロパティ名を書くと対応するgetterが呼び出される
HTML内に直接書けるテンプレートに書くだけで結果が出力される

この特徴により、JSPはより画面表示に集中したファイルになります。

Javaの処理をなるべくサーブレットやモデルに寄せ、JSPではEL式で値を表示する、という役割分担がしやすくなります。

EL式の演算子

EL式では、値を表示するだけでなく、演算子も使えます。

多くの演算子はJavaに近い感覚で利用できます。

たとえば、年齢に1を足したり、数値を比較したりできます。

通常の演算子の例

EL式結果の例
${member.age + 1}ageが23なら24
${member.age >= 18}ageが23ならtrue
${studyPace.achievementRate >= 80}達成率が80以上ならtrue

演算子を使うことで、JSP内で簡単な計算や比較ができます。

ただし、複雑な業務処理をJSPに書きすぎると、画面と処理の役割が混ざってしまいます。

本格的な計算や判定は、できるだけサーブレットやモデルで行い、JSPでは表示に必要な簡単な式にとどめると整理しやすくなります。

empty演算子

EL式には、Javaにはない便利な演算子もあります。

その代表がempty演算子です。

empty演算子は、対象が空かどうかを判定します。

基本形は次のように書きます。

${empty 対象}

対象が空の場合、trueを返します。

empty演算子がtrueになる主な条件

対象の状態結果
スコープに保存されていないtrue
nulltrue
空文字true
要素数が0の配列true
要素を1つも持たないListやMapなどのコレクションtrue

たとえば、errorMsgがリクエストスコープに存在しない場合、次のEL式はtrueになります。

${empty errorMsg}

逆に、errorMsgが存在していて空でない場合はfalseになります。

not empty演算子

empty演算子の結果を反転したい場合は、not empty演算子を使います。

${not empty errorMsg}

これは、errorMsgが存在し、空でない場合にtrueになります。

emptyとnot emptyの例

EL式意味
${empty member}memberが存在しない、または空ならtrue
${not empty member}memberが存在し、空でなければtrue
${empty errorMsg}errorMsgがない、または空ならtrue
${not empty errorMsg}errorMsgがあるならtrue

empty演算子は、次に学習する条件分岐と組み合わせると便利です。

たとえば、エラーメッセージがある場合だけ表示する、といった処理でよく使います。

EL式とコレクション

Webアプリケーションでは、リストやマップをスコープに保存して、JSPで表示することがあります。

たとえば、投稿一覧、商品一覧、検索結果、利用者一覧などです。

EL式では、リストやマップの中にある要素を取り出せます。

コレクションを利用するEL式

対象書き方
リスト内のインスタンスを取得する${属性名[インデックス]}
リスト内のインスタンスのプロパティを取得する${属性名[インデックス].プロパティ}
マップ内のインスタンスを取得する${属性名["キー"]}
マップ内のインスタンスのプロパティを取得する${属性名["キー"].プロパティ}

たとえば、memberListという属性名でListがスコープに保存されているとします。

0番目のMemberインスタンスのnameプロパティを表示したい場合は、次のように書けます。

${not empty errorMsg}

0番目のMemberインスタンスのageプロパティを表示したい場合は、次のように書けます。

${memberList[0].age}

リストをEL式で扱うイメージ

リストは、0番目、1番目、2番目というように、インデックス番号で要素を管理します。

EL式では、角カッコを使ってインデックスを指定できます。

memberListの例

インデックスnameage
0山田23
1青山22
2佐藤25

このmemberListがスコープに保存されている場合、次のEL式で値を取り出せます。

EL式表示される値
${memberList[0].name}山田
${memberList[0].age}23
${memberList[1].name}青山
${memberList[2].name}佐藤

リスト内のインスタンスも、JavaBeansであればドットでプロパティを指定できます。

マップをEL式で扱うイメージ

Mapをスコープに保存している場合は、キーを指定して値を取得できます。

たとえば、scoreMapという属性名でMap<String, Integer>が保存されているとします。

キーmathに対応する値を表示する場合は、次のように書けます。

${scoreMap["math"]}

Mapの例

キー
java85
jsp90
servlet88

このscoreMapがスコープに保存されている場合、次のように取得できます。

EL式表示される値
${scoreMap["java"]}85
${scoreMap["jsp"]}90
${scoreMap["servlet"]}88

Mapは、キーを使って値を取得するコレクションです。

EL式でも、キーを指定して値を取り出せます。

EL式はスクリプト要素の中では使えない

EL式は便利ですが、どこにでも書けるわけではありません。

注意したいのは、スクリプトレットやスクリプト式の中ではEL式を使えないという点です。

たとえば、次のような書き方はできません。

<% for (int i = 0; i < ${memberList.size()}; i++) { %>
    <p>${memberList[i].name}</p>
<% } %>

また、次のように拡張for文の対象にEL式を書くこともできません。

<% for (Member member : ${memberList}) { %>
    <p>${member.name}</p>
<% } %>

このような書き方はエラーになります。

EL式は、JSPのテンプレート部分に書いて値を出力するためのものです。

Javaのスクリプトレット内に埋め込んで使うものではありません。

繰り返しや条件分岐でEL式を使いたい場合

リストに入っているインスタンスを先頭から順に表示したい場合、for文を使いたくなります。

しかし、スクリプトレットのfor文の中でEL式を使うことはできません。

繰り返しや条件分岐でEL式を活用したい場合は、JSTLを使います。

JSTLを使うと、JSP内でJavaのfor文やif文を書かずに、タグ形式で繰り返しや条件分岐を表現できます。

EL式とスクリプト要素の関係

書き方使えるか
HTML内に${member.name}を書く使える
pタグの中に${member.name}を書く使える
スクリプトレットのJavaコード内にEL式を書く使えない
for文の条件にEL式を書く使えない
JSTLのタグとEL式を組み合わせる使える

EL式は、JSPからJavaコードを減らすための技術です。

そのため、スクリプトレットと無理に組み合わせるより、JSTLなどのタグと組み合わせて使うほうが自然です。

EL式を使うときに意識したいこと

EL式を使うと、JSPをかなり簡潔に書けます。

ただし、正しく使うには、スコープに保存した属性名、JavaBeansのプロパティ名、getterメソッドの対応を理解しておく必要があります。

確認したいポイント

ポイント内容
属性名が一致しているかサーブレットのsetAttributeとJSPのEL式で同じ名前を使う
getterが存在するかプロパティ名に対応するgetterメソッドを用意する
同名属性が複数スコープにないか必要ならrequestScopeやsessionScopeで明示する
空の場合の表示を考えるかemptyやnot emptyを使う場面を検討する
スクリプトレット内で使っていないかEL式はスクリプト要素の中では使えない

JSPは画面表示を担当するファイルです。

EL式を使うことで、JSP内のJavaコードを減らし、画面の構造を見やすくできます。

JavaBeansの値を表示するときは、まずEL式で表せないかを考えると、JSPをよりすっきり保てます。