Java入門 / Web入門

【Java Web入門 #8】JSPを利用した動的な表示(3)|EL式の利用

2025.01.31

JSP2.0からは、JSP上で利用できる記述方式の1つとして「EL式」が導入されました。当記事では、簡潔な記述でページ出力が可能で、標準アクションや各種タグと組み合わせて利用することもできる、JSPの利用時には欠かすことのできない「EL式」の利用方法について説明します。

◆Java Web入門の過去記事はこちら
◆Java入門 記事一覧はこちら

EL式とは

EL式(Expression Language)は、定められた書式の中に短いプログラムコードを記述して、処理の実行や、その結果および変数等の出力などを行うことができる技術であり、式言語、ELなどとも呼ばれます。

JSP2.0からJSPにもEL式が準備され、簡易な書式でページの出力を行ったり、同時に簡単な演算を行うことができます。JSPのスクリプトレットや式(<%= %>)に比べ、簡潔で分かりやすい記述でさまざまな出力に対応することができます。

Java EE 6以降のバージョンでは、EL式の中でメソッドの呼び出しが可能となったことで、さらに利用の幅も広がっており、JSP上でもっとも頻繁に利用される記述方式の一つとなっています。

JSPでのEL式の利用

JSPのEL式の利用方法について説明します。
※以降、当記事内で「EL式」と記述した場合は、「JSPのEL式」のことを示すものとします。

EL式に利用できる項目

EL式の中では、以下の項目を利用することができます。

  • 変数
    スコープ内に設定された変数を利用できます。
    暗黙オブジェクトと呼ばれるオブジェクトの他、各スコープ内に保持されたオブジェクト、さらにそれらのプロパティ、メソッドへのアクセスが可能です。

  • リテラル、文字列
    数値、真偽値などのリテラルを利用できます。
    また、シングルクォートまたはダブルクォートで囲んだ文字列(String)も利用することが可能です。

  • 演算子
    算術演算子 (+, -, *, /, div, mod)、関係演算子 (==, !=, >, <, >=, <=, eq, ne, gt, lt, ge, le)、論理演算子 (&&, ||, !, and, or, not) および「empty」演算子が利用できます。

    HTMLやJSPで利用される記号(「/」「<」など)との混同を避けるために、mod、eq、gt などの演算子が用意されています。これらの演算子を使用することで、コードの可読性を高めることができますので、なるべくこちらの演算子を使うのが良いと思います。

  • その他の記号
    プロパティやメソッドの呼び出しには「.」(ドット)を利用します。
    また、オブジェクトが配列の場合はインデックスを指定するための大括弧[ ] 、メソッドの呼び出しには括弧( )を利用します。

EL式の書式と出力の例

EL式は以下の書式で記述します。

書式:
 ${ EXPRESSION }

#{ EXPRESSION } 書式を用いた記述について

JSPでは ${ EXPRESSION } 以外に、#{ EXPRESSION } の書式でEL式を記述できるケースがあります。

これは式の評価が行われるタイミングが異なり、${ EXPRESSION } の書式で記述した場合「即時評価」、#{ EXPRESSION }の書式で記述した場合は「遅延評価」となります。

カスタムタグの属性(の一部)に対して利用することで、評価のタイミングを指定することができますが、当記事ではEL式の利用方法の説明を目的としていますので、即時評価の書式のみ説明し、詳細はカスタムタグの記事で説明します。

オブジェクトの値の出力

オブジェクト自身が文字列などの出力対象の場合は、オブジェクト名を記述することで出力できます。

オブジェクトのプロパティやメソッドにアクセスする場合は、ドットで連結して記述します。さらに子要素(子プロパティ)にアクセスする場合は、さらにその後ろにドットで連結して記述します。

書式:
 ${ [スコープ名.] オブジェクト名 }
 ${ [スコープ名.] オブジェクト名.プロパティ名 }

スコープを指定する暗黙オブジェクト以外では、オブジェクト名の後ろに記述したプロパティの「(引数無しの)getterメソッド」が自動的に呼び出されるため、メンバ変数の名前を直接記述することで、簡潔なコードが実現できます。

例えばsampleというオブジェクトが「name」という変数と「getName」というgetterメソッドを持つ場合、getNameメソッドを利用せずに「sample.name」と記述することができます。このとき、getterメソッドが存在しないプロパティ名を指定した場合は実行時に例外が発生します。

Java
<%
  String helloStr = "こんにちは";
  request.setAttribute("hello", helloStr);

 SampleData sampleData = new SampleData(); // nameプロパティを持つJavaBeans
  sampleData.setName("knovus");
  request.setAttribute("sample", sampleData ); 
%>

${hello}、${sample.name}さん  <- 「こんにちは、knovusさん」と出力


setAttributeメソッドや jsp:useBean アクションなどで各スコープ内に保持したオブジェクトは、保持先のスコープを省略して記述することが可能です。省略した場合は、全てのスコープの中から指定された名前のオブジェクトを見つけて取得します。

このとき、複数のスコープに同じ名前でデータが設定されていた場合は、範囲の狭いスコープから優先となり「ページ」⇒「リクエスト」⇒「セッション」⇒「アプリケーション」の優先順位でデータを取得します。

特定のスコープを指定してオブジェクトにアクセスしたい場合は、後述する「EL式の暗黙オブジェクト」を利用して指定します。

数式の結果の出力

EL式に数式を記述した場合は、数式の処理結果が出力されます。

書式:
 ${ 数式 }

数式には変数、リテラル、演算子を記述することができます。
利用できる演算子は、算術演算子、関係演算子 、論理演算子およびempty演算子です。ビット演算はできないため、^ (排他的論理和) などの記号は利用できません。

Java
/* リテラル値を出力 */
${ true }    <- true が出力される
/* 計算結果を出力 */
${ 3 * 5 }   <- 15 が出力される

/* 判定値を出力 */
// 以下は同じ比較
${ 5 > 10 }  <- false が出力される
${ 5 gt 10 } <- false が出力される


empty演算子はコレクションや文字列が空であるかどうかを判定します。

Java
<%
  String[] strArray = {"aaa", "bbb"};
  request.setAttribute("strArray", strArray);
%>
/*  判定値を出力 */
${ empty "" }        <-  true が出力される
${ empty strArray }  <- false が出力される


Javaのコードとは異なり、「+」演算子で文字列を連結することができないことにご注意ください。
文字列を連結して出力したい場合、最も簡単なのはEL式を並べて出力することです。

連結した文字列を引数として渡したい、などの理由で、どうしてもEL式の中での連結が必要な場合は、Stringインスタンスのconcatメソッドを利用したり、連結のためのクラスメソッドを準備したりすることで実現は可能です。

メソッドの呼び出しと結果の出力

EL式ではインスタンスメソッド、クラスメソッドのどちらも呼び出すことができます。EL式にメソッドの呼び出しを記述した場合、メソッドからの戻り値が出力されます。戻り値の無いメソッド(void)の呼び出しや、メソッドからの戻り値がnullの場合は何も出力されません。

インスタンスメソッドの書式:
 ${ [スコープ名.] オブジェクト名.メソッド名( [引数1, 引数2...] ) }

メソッドを呼び出すときは、Javaのコードと同様にメソッド名の後ろにカッコを付け、必要な場合は引数を指定します。以下の例では、Stringクラスのインスタンスに対して concat メソッドを繰り返し実行しています。

Java
/* インスタンスメソッドの呼び出し */
${ "X".concat("Y").concat("Z") }  <- 「XYZ」が出力される


クラスメソッドの書式:
 ${ クラス名.メソッド名( [引数1, 引数2...] ) }

クラスメソッドを利用する場合は、Javaのコード同様にクラス名から記述します。以下の例では、Stringクラスのクラスメソッドである isEmpty メソッドをEL式の中で実行しています。

Java
/* クラスメソッドの呼び出し */
${ String.isEmpty("") }  <- true が出力される


java.langパッケージ以外のクラスに定義されているクラスメソッドを利用する場合は、pageディレクティブでインポート宣言が必要となります。

標準アクションと連携した出力

JavaBeansの値

EL式では、jsp:useBean アクションで保持したJavaBeansに対して、名前を指定してアクセスすることができます。指定する名前は jsp:useBean アクションで id に指定した値です。

書式:
 ${JavaBeansのid . プロパティ名}

プロパティにアクセスする際は、対象のJavaBeansに対し、getterメソッドを持つプロパティの名前を直接記述します。

以下のサンプルコードでは、セッションスコープ上にJavaBeans「uInfo」を保持して(2~4行目)、EL式を用いた出力(12~13行目)とJSPの式を用いた出力(16~17行目)を行っています。
同じ項目の出力を比較しても、EL式を用いたほうが、スクリプトレットや式のように型のキャストなどを行う必要がなく、簡潔に記述できることがわかります。

Java
<%@ page contentType="text/html; charset=UTF-8" import="site.knovus.beans.UserInfo"%>
<jsp:useBean id="uInfo" class="site.knovus.beans.UserInfo" scope="session" />
<jsp:setProperty name="uInfo" property="userName" value="knovus" />
<jsp:setProperty name="uInfo" property="age" value="21" />
<html>
  <head>
    <meta charset="UTF-8">
    <title>EL式でJavaBeansの値を出力</title>
  </head>
  <body>
    <p>【EL式を用いた出力】</p>
    <p>uInfoから取得したuserNameの値: ${uInfo.userName}</p>
    <p>uInfoから取得したageの値: ${uInfo.age}</p>
    <hr/>
    <p>【JSPの式を用いた出力】</p>
    <p>uInfoから取得したuserNameの値: <%= ((UserInfo)session.getAttribute("uInfo")).getUserName() %></p>
    <p>uInfoから取得したageの値: <%= ((UserInfo)session.getAttribute("uInfo")).getAge() %></p>
  </body>
</html>


(UserInfo.java)

Java
import java.io.Serializable;

public class UserInfo implements Serializable{
	private static final long serialVersionUID = 1L;
	
	/* ユーザー名 userName */
	private String userName;
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}

	/* 年齢 age */
	private Integer age;
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
}


表示結果:


また、上記の例ではJavaBeans「uInfo」はセッションスコープ上に保持されていますが、前述の通り他のスコープに同じ名前のオブジェクトがなければ、スコープの指定は省略できます。スコープを指定する必要がある場合は以下のように記述します。

Java
// スコープを省略する場合
${uInfo.userName}
// スコープを指定したい場合    
${sessionScope.uInfo.userName}    

属性値への出力

EL式による出力は、ページのコンテンツとしての出力以外にも、HTMLや標準アクションなどのタグの属性の値に出力することも可能です。ただし、標準アクションやカスタムタグなどの属性の値に出力する場合は、EL式での出力が可能な項目はタグによって限定されます。

以下の例では、HTMLタグと標準アクションの1つである jsp:setProperty アクションの属性に対して、それぞれEL式による出力を行っています。

Java
<%
  String style = "color: red; font-weight: bold;";
  session.setAttribute("styleRedBold", style);
  
  String str = "dummyData";
  session.setAttribute("dummy", str);
%>

<%-- HTMLタグの属性に出力 --%>
<p style="${styleRedBold}">contents</p>

<%-- 標準アクション(setProperty)のvalueに出力 --%>
<jsp:setProperty name="beanName" property="data" value="${dummy}" />


属性値への出力はJSTLやカスタムタグでも利用できるため、EL式による出力を判定条件として利用したりすることもでき、EL式が多用される理由の1つでもあります。

EL式の暗黙オブジェクト

EL式の暗黙オブジェクト

JSPでは、EL式の中でのみ利用可能な暗黙オブジェクトが準備されています。このEL式の暗黙オブジェクトは、特に宣言などを行わずにEL式の中で利用することができます。

この「EL式の暗黙オブジェクト」は「JSPの暗黙オブジェクト」とは別のものとして定義されており、EL式の中でJSPの暗黙オブジェクトを利用することはできません。同様に、スクリプトレットやJSPの式の中で、EL式の暗黙オブジェクトを利用することもできません。

EL式の暗黙オブジェクトの一覧

EL式で利用できる暗黙オブジェクトは以下の通りです。

オブジェクト名提供される機能※1
(キャプション参照)
pageScopeページスコープに保持したオブジェクトへのアクセスpageContext
(#getAttribute)
requestScopeリクエストスコープに保持したオブジェクトへのアクセスrequest
(#getAttribute)
sessionScopeセッションスコープに保持したオブジェクトへのアクセスsession
(#getAttribute)
applicationScopeアプリケーションスコープに保持したオブジェクトへのアクセスapplication
(#getAttribute)
paramリクエストパラメーターへのアクセスrequest
(#getParameter)
paramValuesリクエストパラメーター(配列値)へのアクセスrequest
(#getParameterValues)
headerヘッダー要素へのアクセスrequest
(#getHeader)
headerValuesヘッダー要素(配列値)へのアクセスrequest
(#getHeaders)※2
cookieクッキーオブジェクトへのアクセスrequest
(#getCookies)※3
pageContextページコンテキスト(そのもの)へのアクセスpageContext
initParamweb.xmlに定義された初期パラメーターへのアクセスapplication
(#getInitParameter)
※1 相当するJSPの暗黙オブジェクトと#メソッド名
※2 request.getHeadersではEnumerationが返されるが、この暗黙オブジェクトからは配列が返される
※3 request.getCookiesではの全てのクッキーオブジェクトの配列が返されるのに対し、この暗黙オブジェクトからは指定した名前のクッキーオブジェクトが返される


通常のオブジェクトと異なる点として、EL式の暗黙オブジェクトではオブジェクト名+ドット以降に記述した名前に対し、それぞれの暗黙オブジェクトの定義に従ったオブジェクトが返されます。(pageContext を除く)

例えば「${requestScope.XXX}」と記述した場合は、リクエストスコープ内に「XXX」という名で保持されたオブジェクトが取得されます。これは、JSPの式に「<%= request.getAttribute("XXX") %>」と記述することで取得されるオブジェクトと同じです。


これに対し、「${param.AAA}」と記述した場合は、「AAA」という名で送信されたリクエストパラメーターが取得されます。これは「<%= request.getParameter("AAA") %>」と同じです。


「pageContext」のみ、暗黙オブジェクト以外のオブジェクトと同様に、メソッドを直接呼び出す場合を除き、ドットに続けて指定した名前のgetterメソッドが呼び出されます。

暗黙オブジェクトを利用したアクセス例

EL式の暗黙オブジェクトは、JSPページ上で利用する頻度が高いオブジェクトが揃っており、スクリプトレットや式による出力や標準アクションと比較しても、シンプルな記述が可能となっています。

各スコープに保持したオブジェクト(attribute)

各スコープに保持したオブジェクトには、オブジェクトの名前のみでアクセスすることができます。同じ名前のオブジェクトがで異なるスコープにも保持されている場合は、スコープに続けて記述することで、指定したスコープに保持されているオブジェクトにアクセスすることができます。

書式:
 ${ [pageScope./requestScope./sessionScope./applicationScope.] オブジェクト名 }

以下のサンプルでは、各スコープに対して同じ名前(scopeName)でオブジェクトを保持させ、EL式で各スコープのオブジェクトを出力しています。スコープの指定を省略した場合は、優先順位に従いページスコープからオブジェクトが取得されていることがわかります。

Java
<%@ page contentType="text/html; charset=UTF-8" %>
<%
  pageContext.setAttribute("scopeName", "ページスコープ");
  request.setAttribute("scopeName", "リクエストスコープ");
  session.setAttribute("scopeName", "セッションスコープ");
  application.setAttribute("scopeName", "アプリケーションスコープ");
%>
<html>
  <head>
    <meta charset="UTF-8">
    <title>スコープを指定して属性オブジェクトを取得</title>
  </head>
  <body>
    <p>pageScope.scopeNameの値: ${pageScope.scopeName}</p>
    <p>requestScope.scopeNameの値: ${requestScope.scopeName}</p>
    <p>sessionScope.scopeNameの値: ${sessionScope.scopeName}</p>
    <p>applicationScope.scopeNameの値: ${applicationScope.scopeName}</p>
    <p>(スコープを省略した)scopeNameの値: ${scopeName}</p>
  </body>
</html>

表示結果:

リクエストパラメーターへのアクセス

param オブジェクトを利用してリクエストパラメーターを取得できます。また、同じパラメーター名で複数の値が送られた場合は、paramValues オブジェクトを利用して配列として取得することもできます。

書式:
 ${param.パラメーター名}
 ${paramValues.パラメーター名} (配列)

同じ名前で複数のパラメーターが送信されている場合に、param オブジェクトでパラメーターを取得した場合は、先頭で送られたパラメーター(paramValuesで取得できる配列の先頭)の値が返されます。

クエリストリングで同じ名前のパラメーターを複数回渡すことで、簡単にパラメーターが配列の場合の動作が確認できます。以下はクエリストリングを「?p=AAA&p=BBB&p=CCC」としてアクセスした場合の動作の例です。

Java
/* param */
${ param.p }  <- 「AAA」が出力される
/* paramValues */
${ paramValues.p[0] }  <- 「AAA」が出力される
${ paramValues.p[1] }  <- 「BBB」が出力される
${ paramValues.p[2] }  <- 「CCC」が出力される


(JSPの式を利用して同じ内容の出力を行う場合)

Java
<%= request.getParameter("p") %>  <- 「AAA」が出力される

<%= request.getParameterValues("p")[0] %>  <- 「AAA」が出力される
<%= request.getParameterValues("p")[1] %>  <- 「BBB」が出力される
<%= request.getParameterValues("p")[2] %>  <- 「CCC」が出力される

その他のオブジェクトへのアクセス

HTTPヘッダー項目には暗黙オブジェクト「header」または「headerValues」を利用してアクセスします。「param」と「paramValues」と同様に、「header」は1つの値、「headerValues」は配列の値を返します。以下の例では、ヘッダーの「host」に設定されている値を出力しています。

Java
/* ヘッダー */
${header.host}  <-「localhost:8080
${headerValues.host[0]} <-「localhost:8080


クッキーには暗黙オブジェクト「cookie」を利用してアクセスします。スクリプトレットでrequest.getCookiesを利用して取得する場合と異なり、名前を指定してクッキーオブジェクトを取得することができます。以下の例では、クッキー「JSESSIONID」の値を出力しています。

Java
/* クッキー */
${cookie.JSESSIONID.value}  <-  セッションIDの値が出力される


暗黙オブジェクト「initParam」からは、web.xmlに定義された、アプリケーションの初期化パラメーターを取得することができます。初期パラメーターは、Webアプリケーションのweb.xmlで<web-app>内の要素として定義できます。

XML
  <context-param>
    <param-name>sampleParam</param-name>
    <param-value>sample-value</param-value>
  </context-param>


上記のサンプルでは「sampleParam」という名前でパラメーターを定義しています。この初期化パラメーターには、以下のように「initParam」を利用してアクセスできます。

Java
/* 初期パラメーター */
${initParam.sampleParam}  <-  「sample-value」出力される

EL式の予約語

予約語の一覧

EL式では、以下の単語は予約語となっているため、EL式の中では変数・プロパティ名としての利用ができません。これらの予約語は、instanceof を除き、数式の中で真偽値のリテラル(true / false)や演算子として利用される文字列となっています。(カッコ内の記号は対応するJavaの演算子)

  • and (&&)
  • or( || )
  • not( ! )
  • empty
  • eq(==)
  • ne( !=)
  • true
  • false
  • ge(>=)
  • gt(>)
  • le(<=)
  • lt(<)
  • div( / )
  • mod(%)
  • instanceof

各スコープやJavaBeansに、これらの予約語と同じ名前のオブジェクトやプロパティがある場合、名前を指定しても値を取得することができません。(EL式の中でこれらの名前を指定した場合、実行時にエラーとなります)

プロパティの場合は、対象のgetterメソッドを直接呼び出して取得することができますが、一部だけ書式が統一されなくなるため、EL式で利用する可能性があるプロパティに対しては、これらの変数名を付けるのをなるべく避けた方が良いでしょう。

NG例)

Java
// JavaBeans
private String eq;      // eqプロパティ
public String getEq(){  // getterメソッド
  return this.eq;
} 

// JSP(EL式)
<jsp:useBean id="bean" class="JavaBeansのクラス名"/>
${bean.eq} 
 ↑ この行の実行時にエラー発生(予約語のeqがプロパティ名として指定されているため)


getterを用いる例) 

Java
// JSP(EL式)
<jsp:useBean id="bean" class="JavaBeansのクラス名"/>
${bean.getEq()} 
 ↑ getterメソッドを意図的に呼び出して、bean内のeqの値を取得

まとめ

スクリプトレットや標準アクションとともに、EL式はJSPの利用には欠かせない記述方式です。特に、JSTLをはじめとしたJSPのタグライブラリとの相性は非常によく、条件分岐などを含めた動的な表示を行うJSPを簡潔な記述内容で実現できます。

次回の記事では、このJSTL(JSP 標準タグライブラリ)の利用方法について説明します。タグ内でのEL式の利用についても説明しますので、興味のある方は是非お読みください。

株式会社GSI 採用サイト

新しいこと、始めよう

あなたとともに歩を進めるWEBメディア

広告

広告