2009年8月28日金曜日

タグファイル

http://lab.moyo.biz/recipes/java/jsp/tagfile.jsp

タグファイル は JSP 感覚で拡張タグを作成することの出来る JSP 2.0 の機能です。 いくつかの JSP で共用したい HTML スクラップや JSP 機能を、タグハンドラや TLD を作成するより 簡単に、スクリプトレットより可視性を損なわず部品化することが出来ます。

<%@page%> 宣言された JSP が内部でサーブレット クラスに変換されるのに対して <%@tag%> 宣言 されたタグファイルはタグハンドラへ変換されます。

使用に関してはいくつかの制約があります。

保存場所 タグファイルは /WEB-INF/tags の下に保存するか (サブディレクトリでも可)、あるいは JAR にまとめて /WEB-INF/lib の下に保存する必要があります。JAR にまとめる場合は TLD が必要です。
ファイル名 タグファイルの名前は JSP で使用するときのタグ名として使用されます。 例えば JSP で zip.tag というタグファイルを利用する場合は と記述します。
拡張子 タグファイルの拡張子は *.tag です。
スクリプト タグファイルの拡張タグで囲った Body 部分では <% %> や <%= %> などの JSP スクリプト構文を 記述できません (Body 部分がフラグメントで渡されるため)。これらは EL や JSTL などの拡張タグで実現する必要があります。
jspContext タグファイル内では暗黙変数 pageContext は提供されません。代わりに jspContext を使用する必要があります。
構文が JSP であることからタグファイルはプレゼンテーションベースの拡張タグを作成するのに 向いています。例えば:

サイト内でレイアウトを共通化したい。例えばページのヘッダ、フッタなど。
少々凝った HTML や JavaScript を JSP から分離したい。例えばページがロードされないと SUBMIT ボタンが有効にならないフォームなど。
配置調整のための透過画像 (いわゆるスペーサー) などの部品を簡略記述したい。
逆に複雑なデータベース処理や特定のライブラリに依存する処理などのロジカルな記述がメインになる場合は、 記述の容易さやメンテナンス性の観点から通常の Java コードで拡張タグとして作成する方が良いと言えます。

試行
まずタグファイルを作成してみます。このサンプルは属性 color に指定した色でテキストを 中央表示する HTML です。保存場所は /WEB-INF/tags/sample/foo.tag にしました。

<%@ tag language="java" pageEncoding="UTF-8" %>
<%@ attribute name="color" %>

作成したタグファイルを JSP から呼び出します。<%@taglib%> で指定するのはディレクトリまでです。ファイル名がタグ名に使用されている事に注意してください。

<%@ page language="java" ... %>
<%@ taglib prefix="sample" tagdir="/WEB-INF/tags/sample" %>

Hello, world
この出力結果は以下のようになります。

Hello, world

Hello, world
クラスファイルも TLD も記述しないで拡張タグを実装することが出来ました!

動的属性
JSP 1.x 時代のタグハンドラは属性名ごとに用意した setter で属性値を受け取るという仕組みでした。

これは Java Beans らしいようにも見えますが、現実に汎用的なカスタムタグを設計しようとすると、 タグの処理に必要な属性以外にも、指定可能な全ての HTML 属性に setter を用意する必要がありました。 id, lang, title, style, class などのから onmouseenter, onmousedown, onmouseclick, onclick, onselect, ... などなど 膨大な数の setter を作成し、同時に膨大な数の属性定義を TLD に記述する必要があったわけです (Struts の BaseHandlerTag クラスがまさにその患者です)。

JSP 2.0 では全ての属性についてタグクラスで setter を用意しなくても (タグファイルでは <%@attribute%> を定義しなくても) 任意の属性値を受け取れるようになりました。 <%@tag%> ディレクティブの dynamic-attributes に変数名 を指定した場合、全ての属性の名前-値セットが Map としてその変数に設定されます。

<%@ tag language="java" pageEncoding="UTF-8" dynamic-attributes="attr" %>

${entry.key}=""

>




フラグメント
JSP 2.0 からフラグメントという機能を使用することが出来ます。

カスタムタグで囲んだ内容 (以後 Body と言います) はフラグメントとしてタグファイルに 渡されています。そして Body を表すフラグメントは とすることで 実際の出力が行われます。フラグメントの登場によって Body 部分をいつ処理するかがタグハンドラ側で 自然に記述できるようになったわけです (以前は Body 部の 「前処理」 「後処理」 という記述でした)。

Body 部分を処理する前にタグファイル内で設定した変数を Body 内の EL やカスタムタグで 参照することが出来ます。


製品名: ${product.name}

価格: ${proeuct.price}

個数: ${proeuct.count}



--- writeProduct.tag の内容 ---
<%@ tag language="java" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>






--- 実行結果 ---
製品名: インスタントラーメン

価格: ¥98

個数: 12個

↓この JSP で実際に実行しています。
製品名: インスタントラーメン
価格: ¥98
個数: 12個
フラグメントを使用することで JSP のスクラップを未評価のままで渡すことが出来ます。 そしてタグファイル (タグハンドラ) 側で任意のタイミングで評価を行うことが出来ます。 出力結果ではなく出力処理そのものを渡しているという意味では、Java の匿名内部クラスや JavaScript のエンクロージャーに似ていると言えるかもしれません。

JSP 2.0 のカスタムタグは Body 部分だけではなく属性値もフラグメントとして渡すことが出来ます。 例として、タグファイル側で用意した時刻を呼び出し元の JSP の指定したフォーマットで 出力してみます。呼び出し側の JSP での記述は以下の通り。


${timestamp}

そしてタグファイル側は以下の通り。現在時刻をフォーマットして変数として設定した後に フラグメントとして渡された date 属性を評価しています。

<%@ tag language="java" pageEncoding="UTF-8" body-content="empty" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ attribute name="date" required="true" fragment="true" %>



この実行結果は以下のようになります。タグファイル側で用意した日時が JSP の指定した書式で 出力されました。

2007/12/08 23:54:55
↓この JSP で実際に実行しています。
2009/08/28 11:11:56


タグファイル は JSP 感覚で拡張タグを作成することの出来る JSP 2.0 の機能です。 いくつかの JSP で共用したい HTML スクラップや JSP 機能を、タグハンドラや TLD を作成するより 簡単に、スクリプトレットより可視性を損なわず部品化することが出来ます。

<%@page%> 宣言された JSP が内部でサーブレット クラスに変換されるのに対して <%@tag%> 宣言 されたタグファイルはタグハンドラへ変換されます。

使用に関してはいくつかの制約があります。

保存場所 タグファイルは /WEB-INF/tags の下に保存するか (サブディレクトリでも可)、あるいは JAR にまとめて /WEB-INF/lib の下に保存する必要があります。JAR にまとめる場合は TLD が必要です。
ファイル名 タグファイルの名前は JSP で使用するときのタグ名として使用されます。 例えば JSP で zip.tag というタグファイルを利用する場合は と記述します。
拡張子 タグファイルの拡張子は *.tag です。
スクリプト タグファイルの拡張タグで囲った Body 部分では <% %> や <%= %> などの JSP スクリプト構文を 記述できません (Body 部分がフラグメントで渡されるため)。これらは EL や JSTL などの拡張タグで実現する必要があります。
jspContext タグファイル内では暗黙変数 pageContext は提供されません。代わりに jspContext を使用する必要があります。
構文が JSP であることからタグファイルはプレゼンテーションベースの拡張タグを作成するのに 向いています。例えば:

サイト内でレイアウトを共通化したい。例えばページのヘッダ、フッタなど。
少々凝った HTML や JavaScript を JSP から分離したい。例えばページがロードされないと SUBMIT ボタンが有効にならないフォームなど。
配置調整のための透過画像 (いわゆるスペーサー) などの部品を簡略記述したい。
逆に複雑なデータベース処理や特定のライブラリに依存する処理などのロジカルな記述がメインになる場合は、 記述の容易さやメンテナンス性の観点から通常の Java コードで拡張タグとして作成する方が良いと言えます。

試行
まずタグファイルを作成してみます。このサンプルは属性 color に指定した色でテキストを 中央表示する HTML です。保存場所は /WEB-INF/tags/sample/foo.tag にしました。

<%@ tag language="java" pageEncoding="UTF-8" %>
<%@ attribute name="color" %>

作成したタグファイルを JSP から呼び出します。<%@taglib%> で指定するのはディレクトリまでです。ファイル名がタグ名に使用されている事に注意してください。

<%@ page language="java" ... %>
<%@ taglib prefix="sample" tagdir="/WEB-INF/tags/sample" %>

Hello, world
この出力結果は以下のようになります。

Hello, world

Hello, world
クラスファイルも TLD も記述しないで拡張タグを実装することが出来ました!

動的属性
JSP 1.x 時代のタグハンドラは属性名ごとに用意した setter で属性値を受け取るという仕組みでした。

これは Java Beans らしいようにも見えますが、現実に汎用的なカスタムタグを設計しようとすると、 タグの処理に必要な属性以外にも、指定可能な全ての HTML 属性に setter を用意する必要がありました。 id, lang, title, style, class などのから onmouseenter, onmousedown, onmouseclick, onclick, onselect, ... などなど 膨大な数の setter を作成し、同時に膨大な数の属性定義を TLD に記述する必要があったわけです (Struts の BaseHandlerTag クラスがまさにその患者です)。

JSP 2.0 では全ての属性についてタグクラスで setter を用意しなくても (タグファイルでは <%@attribute%> を定義しなくても) 任意の属性値を受け取れるようになりました。 <%@tag%> ディレクティブの dynamic-attributes に変数名 を指定した場合、全ての属性の名前-値セットが Map としてその変数に設定されます。

<%@ tag language="java" pageEncoding="UTF-8" dynamic-attributes="attr" %>

${entry.key}=""

>




フラグメント
JSP 2.0 からフラグメントという機能を使用することが出来ます。

カスタムタグで囲んだ内容 (以後 Body と言います) はフラグメントとしてタグファイルに 渡されています。そして Body を表すフラグメントは とすることで 実際の出力が行われます。フラグメントの登場によって Body 部分をいつ処理するかがタグハンドラ側で 自然に記述できるようになったわけです (以前は Body 部の 「前処理」 「後処理」 という記述でした)。

Body 部分を処理する前にタグファイル内で設定した変数を Body 内の EL やカスタムタグで 参照することが出来ます。


製品名: ${product.name}

価格: ${proeuct.price}

個数: ${proeuct.count}



--- writeProduct.tag の内容 ---
<%@ tag language="java" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>






--- 実行結果 ---
製品名: インスタントラーメン

価格: ¥98

個数: 12個

↓この JSP で実際に実行しています。
製品名: インスタントラーメン
価格: ¥98
個数: 12個
フラグメントを使用することで JSP のスクラップを未評価のままで渡すことが出来ます。 そしてタグファイル (タグハンドラ) 側で任意のタイミングで評価を行うことが出来ます。 出力結果ではなく出力処理そのものを渡しているという意味では、Java の匿名内部クラスや JavaScript のエンクロージャーに似ていると言えるかもしれません。

JSP 2.0 のカスタムタグは Body 部分だけではなく属性値もフラグメントとして渡すことが出来ます。 例として、タグファイル側で用意した時刻を呼び出し元の JSP の指定したフォーマットで 出力してみます。呼び出し側の JSP での記述は以下の通り。


${timestamp}

そしてタグファイル側は以下の通り。現在時刻をフォーマットして変数として設定した後に フラグメントとして渡された date 属性を評価しています。

<%@ tag language="java" pageEncoding="UTF-8" body-content="empty" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ attribute name="date" required="true" fragment="true" %>



この実行結果は以下のようになります。タグファイル側で用意した日時が JSP の指定した書式で 出力されました。

2007/12/08 23:54:55
↓この JSP で実際に実行しています。
2009/08/28 11:11:56

0 件のコメント:

マイブログ リスト


Jang ki hote

自己紹介