式言語 (Expression Language, EL) とは JSP 2.0 から導入された埋め込み型言語です。
元々は <%= %> の代わりに属性値を記述できるよう JSTL
で規定されたものでしたが、Java EE 5 での JSTL 標準化により JSP の標準機能となりました。
JSP 内の静的なテキストの中や拡張タグに渡す属性値の部分に以下の形式で記述することが出来ます。
${expression}
expression 部分には foo, foo.bar などの変数や
後述の演算子を用いた簡単な演算、ユーザ定義の関数などを記述することが出来ます。
web.xml を Servlet API 2.3 以前のバージョンで宣言している場合、JSP 内の EL
が評価されなので注意してください。
<!DOCTYPE
web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
...
上記のような DTD での宣言が行われているなら Servlet API 2.4 の Schema を使用した宣言に変更する必要があります。
<web-app
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
...
EL では以下の暗黙オブジェクト (Implicit Object) を使用することが出来ます。
pageContext.servletContext |
Bean |
この JSP のサーブレットが所属するコンテキスト。 |
pageContext.session |
Bean |
クライアントに対するセッションオブジェクト。 |
pageContext.request |
Bean |
JSP の実行を行っているリクエスト。 |
pageContext.response |
Bean |
JSP から返すレスポンス。 |
param |
Map |
リクエストパラメータのマップ。 |
paramValues |
Map |
リクエストパラメータのマップ (配列値)。 |
header |
Map |
リクエストヘッダのマップ。 |
headerValues |
Map |
リクエストヘッダのマップ (配列値)。 |
cookie |
Map |
Cookie のマップ。 |
initParam |
Map |
コンテキストの初期化パラメータのマップ。 |
pageScope |
Map |
ページスコープ変数のマップ。 |
requestScope |
Map |
リクエストスコープ変数のマップ。 |
sessoinScope |
Map |
セッションスコープ変数のマップ。 |
applicationScope |
Map |
アプリケーションスコープ変数のマップ。 |
EL における変数は 「親コンテキストに従属する識別子」という形式で表現されます。
これは parent.identifier あるいは parent['identifier']
と記述します (foo.bar は foo['bar'] と同じです)。
| 親コンテキスト | 識別子 | 識別子の型 | 例 |
| Bean |
プロパティ名 |
文字列 |
foo.bar, foo['bar'] (foo.getBar() と等価) |
Map |
キー |
任意 |
map.key, map['key'] (map.get("key") と等価) |
List, 配列 |
インデックス |
int |
list[1], array[1] (list.get(1), array[1] と等価) |
いくつかの状況では [] でしか識別子を指定できません。
- 識別子を動的に指定したい (×
foo.(bar+i) → ○foo['bar'+i])
- 識別子を EL の変数として記述できない (×
foo.(biz.moyo.lab.user-list) → ○foo['biz.moyo.lab.user-list'])
- 親コンテキストがリストまたは配列 (×
foo.0 → ○foo[0])
暗黙オブジェクト以外のオブジェクトは JSP で定義されている 4 つのスコープから
page, request, session, application
の順序で検索されます。
EL で使用できるリテラルと演算子を以下に記述します。
演算子の優先順位は Java でのそれと同じです。
| 数値 |
Integer, Double 等の valueOf() が認識できる形式 |
文字列 |
" または ' で囲み (エスケープ文字は \", \', \\)。 |
null |
null 値 |
true |
ブール代数 true |
false |
ブール代数 false |
[], . |
フィールドアクセス |
() |
括弧 |
empty |
右辺値の文字列,コレクション,配列が null または長さ 0 の場合 true |
+, -, *, /, div, %, mod |
四則演算子と余剰演算子 |
- |
単項マイナス演算子 |
&&, and, ||, or, !, not |
論理演算子 |
==, eq, !=, ne, <, lt, >, gt, <=, le, >=, ge |
比較演算子 |
A? B: C |
3項条件演算子 |
instanceof |
予約のみ? |
TLD (タグライブラリ記述子) で定義した関数を EL で使用することが出来ます。
JSTL 標準の functions でもいくつか簡単な関数が用意されていますが、ここでは
自分で作成した機能を関数として使用する方法を記述します。
関数と言っても単に Java の static メソッドを作成するだけで、
特別なクラスやインターフェースの知識は必要はありません。
例として IP アドレスと本日日付に基づいた 8 桁の文字列を返すメソッドを作成します。
package biz.moyo.lab.app.func;
import sun.misc.BASE64Encoder;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MyELFunctions{
private static String getRemoteHash(String addr){
try{
addr += new SimpleDateFormat("yyyyMMdd").format(new Date());
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] binary = md.digest(addr.getBytes("UTF-8"));
BASE64Encoder e = new BASE64Encoder();
return e.encode(binary).substring(0, 8);
} catch(Exception ex){/* */}
return "--------";
}
}
次に、TLD ファイル /WEB-INF/tld/myfunc.tld (場所や名前は何でもいい)
に 「makeRemoteHash() が呼ばれたら
MyELFunctions#getRemoteHash() を実行する」 と
定義します (同じ名前でなくても良いことを示すためにあえて名前は変えてあります)。
<function>
<name>makeRemoteHash</name>
<function-class>biz.moyo.lab.app.func.MyELFunctions</function-class>
<function-signature>
java.lang.String getRemoteHash(java.lang.String)
</function-signature>
</function>
最後に JSP 内で <%@taglib%> を使用して前述の TLD で定義した関数を使用します。
<%@ taglib prefix="mf" uri="/WEB-INF/tld/myfunc.tld"%>
...
<c:out value="${mf:makeRemoteHash(request.remoteAddr)}" />
page スコープに設定されている foo という名前のオブジェクトを出力します。
<c:set var="foo" value="hello, world" />
<c:out value="${foo}" /> |
→ hello, world |
<c:out> を用いなくても出力を行うことは出来ますが HTML エスケープが行われません。
この使い方は値に <, > のような文字が含まれないことが
確実な場合 (例えば結果が int 型など) のみにし、それ以外は <c:out>
か JSTL functions の escapeXml() 関数を使用してください。
<c:set var="foo" value="<b>hello, world☠</b>" />
${foo}
<c:out value="${foo}" />
${fn:escapeXml(foo)} |
→ hello, world☠
→ <b>hello, world☠</b>
→ <b>hello, world☠</b> |
演算子を用いて簡単な演算を行うことが出来ます。
<% pageContext.setAttribute("foo", new String[]{"A","B","C"}); %>
1 + 1 := <c:out value="${1 + 1}" />
<span style="font-weight:${empty foo?'normal;':'bold'};">hello,world</span>
${fn:length(foo)} |
→ 1 + 1 := 2
→ hello,world
→ 3 |