アットマーク・アイティ @IT@IT自分戦略研究所QA@ITイベントカレンダー+ログ
 @IT > Webアプリケーション構築の最適解 > JSPカスタムタグ徹底入門(1)
 
@IT[FYI]

 
Webアプリケーション構築の最適解“JSPカスタムタグとは?”
JSPカスタムタグ徹底入門

第1回 JSPカスタムタグの仕組みを知ろう

JavaServer Pages(JSP)1.1では、「カスタムタグ」という機能が導入された。最新のJSP 1.2でいくらか拡張されてはいるものの、そのコアとなる機能は、JSP 1.1でほぼカバーされていると言える。本稿では、JSP 1.1におけるカスタムタグについて、簡単なカスタムタグを作りながら、その特徴やアーキテキクチャについて説明しよう。 (2001/12/19)

カスタムタグ登場の背景

 J2EEアプリケーションの生産性を高め、メンテナンスや拡張を容易にするためには、機能や役割に基づいてうまく「部品化」(コンポーネント化、モジュール化)を行い、コンポーネントの再利用性や移植性を高めていく必要があります。改めて言うまでもなく、ビジネスロジック層でのコンポーネントとしては、Enterprise JavaBeans(EJB)が用意されています。

 それでは、プレゼンテーション層ではどうでしょうか? サーブレットやJSPをWebモジュール(Webアプリケーション)としてモジュール化することはできますが、これが再利用性の高い「コンポーネント」だと考える人は、いないでしょう。

 ここで、J2EEによるWebアプリケーション開発の現状を考えてみましょう。EJBを使うにせよ使わないにせよ、そして、J2EEアプリケーションモデルのMVCアーキテクチャを採用するにせよしないにせよ、ほとんどの場合、クライアントへのレスポンスの生成(MVCアーキテクチャの「ビュー」)には、JSPを利用していることでしょう。

 思いつくままにJSPページを開発していくと、条件分岐やループ、処理フローの制御、データベースアクセスなどを実現するために、おそらく(“<%と“%>””に囲まれたJavaコードである)スクリプトレットを多用してしまうことでしょう。この場合、同じようなJavaコードを、多数のJSPページのあちらこちらに繰り返し書くことになってしまいます。また、JSPページのデザインをWebデザイナに任せる場合には、JSPやJavaのシンタックスを理解し開発することを、彼らに求めるのは酷でしょう。

 JSPでは、<jsp:useBean>を用いて「再利用可能なコンポーネント」と言われるJavaBeansを使えるのでは、と思うかもしれません。ですが、サーバサイドにおけるJavaBeansは、データ中心のコンポーネントとしては使いやすいものの、それ以外の用途にはあまり向いていないでしょう。<jsp:setProperty>および<jsp:setProperty>を用いて、データの設定と取得は簡単に行えます。MVCアーキテクチャのコントローラとビューの間や、HTTPセッション内で、データを受け渡したり共有したりする場合には、JavaBeansは非常に便利でしょう(<jsp:useBean>のscope属性の値には、page、request、session、またはapplicationを指定できたことを思い出してください)。

 それでは、上で述べたようなスクリプトレットの問題を回避するためには、どうしたらよいのでしょうか? まさに、この問題の解決策が、カスタムタグのメカニズムなのです。

カスタムタグとは?

 JSPでは、<jsp:useBean>や<jsp:include>、<jsp:forward>などのアクションが、標準のアクションとして定義されています。カスタムタグとは、JSPページ内で利用可能なカスタムのアクションを定義するものです。関連する一連のカスタムタグは、後述するタグハンドラ(TLD)というファイルを用いてタグライブラリとして定義されます。

 カスタムタグは、名前空間接頭辞を持つXMLの要素と同様のシンタックスを採用しています。単純なアクションは、次のように空要素で指定できます。

<my:myaction myattr="abc" />

 より複雑なアクションは、次のように、空でない要素として指定できます。要素の内容(開始タグと終了タグとの間)は、ボディ(本体)と呼ばれます。ボディには、通常のJSPページのフラグメントを含めることができ、ほかのカスタムタグをネストさせることも可能です。

<my:myaction myattr="xyz">
アクションのボディ
</my:myaction>

 カスタムタグ開発者は、カスタムタグが提供する機能の実装に集中します(ビジネスロジックを実装する開発者が、これを兼ねる場合が多いかもしれません)。JSP開発者(Webデザイナ)は、大量のスクリプトレットを書くことなく、カスタムタグの仕様(機能、要素名、属性名とその値の意味など)のみを理解しておけば、ページデザインを進められます。つまり、明確に役割の分担ができるわけです。

■カスタムタグの種類

 タグライブラリには、大きく分けて、次の4種類があります。

(1) JSPコンテナベンダ(アプリケーションサーバベンダ)が提供するタグライブラリ
(2) オープンソースの、あるいはサードパーティが提供するタグライブラリ
(3) JSP Standard Tag Library(JSTL)
(4) 独自に開発したタグライブラリ

(1)JSPコンテナベンダ(アプリケーションサーバベンダ)が提供するタグライブラリ
 ほとんどのアプリケーションサーバベンダは、競合他社との差別化を図るため、そのJSPコンテナで利用可能なタグライブラリ群を提供しています。詳細は、各アプリケーションサーバのマニュアル等を参照してください。JRunの場合は、「JRunタグライブラリリファレンス」を参照しましょう。

 タグライブラリはポータブル(移植可能)ですので、任意のJSPコンテナで動作するはずです。が、アプリケーションサーバベンダは、自社のJSPコンテナ以外での動作はサポートしないでしょう。

(2)オープンソースの、あるいはサードパーティが提供するタグライブラリ
 
タグライブラリはポータブル(移植可能)ですので、オープンソースのタグライブラリや、サードパーティが提供するタグライブラリを利用することも可能です。オープンソースのタグライブラリとしては、Jakarta Projectの「Jakarta Taglibs」が有名です。また、JSPTags.comには、さまざまなタグライブラリへのリンクが掲載されています。

 また、当コーナーで近日公開予定の「JSPカスタムタグ・ディレクトリ」にも、多数のタグライブラリへの情報をまとめる予定です。

(3)JSP Standard Tag Library(JSTL)
 (1)や(2)のタグライブラリには、類似した機能を提供するものが多数あります。タグライブラリに求められる機能は、データベースアクセスやループ処理など、共通したものが多いためです。

 現在、JSR-052において、このような共通した機能を持つタグライブラリ「JSP Standard Tag Library (JSTL)」の標準化作業が進行中です。なお、JSTLのリファレンス実装は、Jakarta Projectが行っています。

(4)独自に開発したタグライブラリ
 ドメインに特化した機能が必要な場合など、(1)-(3)では要件が満たせない場合には、独自にカスタムタグを実装することになります。

 例えば、J2EE BruePrintsのサンプルアプリケーション「Java Pet Store」でも、タグライブラリが多用されています。

JSPカスタムタグの仕組み

 ここでは、簡単なサンプルコードを使って、カスタムタグのアーキテクチャを説明していきましょう。カスタムタグの開発者が作成するのは、個別のカスタムタグの機能を実装したタグハンドラ、そして、カスタムタグの構成情報を指定するタグライブラリディスクリプタ(TLD)です。

 例として、「こんにちは」と出力するだけの単純なカスタムタグを実装することにしましょう。

■タグライブラリディスクリプタ(TLD)

 タグハンドラのソースコードは、以下のようになります。

タグハンドラ HelloTag.java
package mytaglib;

import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;

public class HelloTag extends TagSupport {

  public int doStartTag() throws JspException {
    try {
      pageContext.getOut().print("こんにちは");
    } catch ( Exception ex ) {
      throw new JspException("HelloTag: " + e.getMessage());
    }

    return SKIP_BODY;
  }

  public int doEndTag() {
    return EVAL_PAGE;
  }
}

 ここで、タグハンドラに関連するインターフェイスやクラスを説明しておきましょう。カスタムタグに関連するインターフェイスやクラスは、javax.servlet.jsp.tagextパッケージに含まれています。

 タグハンドラは、Tagインターフェイス、またはBodyTagインターフェイスのいずれかをimplementsする必要があります。タグがボディを持たない場合や、ボディを持ち、ボディを操作しない(ボディを、JSPの一部としてそのままインクルードする)場合、タグハンドラは、Tagインターフェイスをimplementsします。タグがボディを持ち、ボディを操作する場合には、タグハンドラは、BodyTagインターフェイスをimplementsします。

ボディ ボディの操作 implementsするインターフェイス
持たない - Tag
持つ 不要 Tag
持つ 必要 BodyTag

 実際には、これら2つのインターフェイスのベース実装クラスとして、TagSupportクラスとBodyTagSupportクラスが用意されていますので、タグハンドラは、これらをextendsして、いくつかのメソッドをオーバライドするケースが、ほとんどでしょう。以下のクラス図は、タグハンドラに関連するインターフェイスやクラスの間の関係を示しています。

タグハンドラに関連するインターフェイスやクラス

 JSP 1.1でのjavax.servlet.jsp.tagextパッケージのJavaDocも、参照してください。また、Ja-Jakartaプロジェクトは、JSP 1.2のJavaDocを翻訳していますので、こちらも参照してください。

 TagSupportクラスのメソッドの中で、開発者がしばしばオーバライドするものは、開始タグを処理するdoStartTag()メソッド、および終了タグを処理するdoEndTag()メソッドです。サンプルコードでも、この2つのメソッドをオーバライドしていますね。

 このサンプルでは登場しませんが、カスタムタグが属性をもつ場合には、その属性値を設定・取得するsetter/getterメソッドも必要です。例えば、カスタムタグがname属性をもつ場合には、setName()とgetName()メソッドを実装します。実は、タグハンドラは、属性をプロパティとしてもつJavaBeansなのです。

 さて、サンプルコードでdoStartTag()メソッドやdoEndTag()メソッドの戻り値、SKIP_BODYやEVAL_PAGEは、何を意味するのでしょうか? これらの戻り値は、その後の処理を指定するために使われるものです。

.....
<my:myaction myattr="abc"> <-- doStartTag()メソッド
  ★ ボディ
</my:myaction> <-- doEndTag()メソッド
  ★ 終了タグ以降のJSPページ

メソッド 戻り値 意味
doStartTag() SKIP_BODY ボディを無視する
EVAL_BODY_INCLUDE ボディをJSPとして評価する (Tagインターフェイスの場合)
EVAL_BODY_TAG ボディをJSPとして評価する (BodyTagインターフェイスの場合)
doEndTag() SKIP_PAGE 終了タグ以降のJSPページを評価する
EVAL_PAGE 終了タグ以降のJSPページを評価せずに、 リクエスト処理を完了する

  JSPページをシリアルに評価していくステップで、これらの戻り値が、その後の処理を決定するために使われることが分かるでしょう。

 次の図は、TagSupportクラスをextendsしたカスタムタグの、典型的なシーケンス図です。

 サンプルコードでは、doStartTag()メソッドで「こんにちは」を出力してからSKIP_BODYを返し、doEndTag()メソッドでは単にEVAL_PAGEを返しています(TagSupportクラスのdoEndTag()メソッドは、単にEVAL_PAGEを返すものなので、サンプルコードのdoEndTag()メソッドはなくても構いません)。

 今回のサンプルのように、ボディをもたないタグの場合、doStartTag()メソッドでは単にSKIP_BODYを返し、doEndTag()メソッドで「こんにちは」を出力してからEVAL_PAGEを返すようにしても、結果はまったく同じになることが分かるでしょう(TagSupportクラスのdoStartTag()メソッドは、単にSKIP_BODYを返すものなので、この場合はdoStartTag()メソッドはなくても構いません)。

 サンプルコードでは、TagSupportクラスのpageContextフィールドを用いて、カレントのJspWriterを取得し、そこに「こんにちは」を出力しています。

pageContext.getOut().print("こんにちは");

 setPageContext()メソッドによって設定されるpageContextフィールドは、javax.servlet.jsp.PageContextクラスのインスタンスです。PageContextクラスのgetRequest()、getResponse()、getSession()、getServletContext()などのメソッドを利用することにより、セッション情報へのアクセスや、HTTPレスポンスヘッダの操作など、さまざまな情報にアクセスしそれらを操作することが可能となります。

■タグライブラリディスクリプタ (TLD)

 タグハンドラを実装しただけでは、まだカスタムタグとして使うことはできません。タグライブラリディスクリプタ(TLD)と呼ばれるXML文書を作成する必要があります。TLDは、その名の通り(1つ以上のカスタムタグである) タグライブラリの構成情報を記述するものです。今回は、次のようなTLDファイルmytaglib.tldを作成します。

タグライブラリディスクリプタ mytaglib.tld
<?xml version="1.0" encoding="Shift_JIS" ?>
<!DOCTYPE taglib
          PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" 
          "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">

<taglib>
  <tlibversion>1.0</tlibversion>
  <jspversion>1.1</jspversion>
  <shortname>Introduction</shortname>
  <info>JSPカスタムタグ徹底入門</info>

  <tag>
    <name>HelloTag</name>
    <tagclass>mytaglib.HelloTag</tagclass>
    <bodycontent>empty</bodycontent>
    <info>「こんにちは」を出力</info>
  </tag>
</taglib>

 <taglib>要素は、タグライブラリ全体の構成情報を表す要素と、1つ以上の<tag>要素を子要素としてもちます。

要素 意味
<tlibversion> このタグライブラリのバージョン
<jspversion> JSPのバージョン (1.1または1.2)
<shortname> このタグライブラリの名前
<info> このタグライブラリの情報

 <tag>要素は、各カスタムタグの構成情報を表す要素を子要素としてもちます。

要素 意味
<name> このカスタムタグの名前
<tagclass> タグハンドラの完全修飾クラス名
<bodycontent> ボディの内容を指定。次の3つのいずれか
empty ボディを持たない場合 (空要素の場合)
JSP ボディがJSPフラグメントの場合
tagdependent ボディがJSPフラグメントでない場合
(例えば、SQL文など)
<info> このカスタムタグの情報

 カスタムタグが属性を持つ場合、<tag>要素には、各属性ごとに<attribute>子要素を指定します。詳細は、次のURLで取得できるDTDや、JSP仕様などを参照してください。

http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd


カスタムタグの利用

 タグハンドラとTLDができれば、カスタムタグは完成です。では、カスタムタグを使うには、どうすればいいのでしょうか?

 タグハンドラも、Webモジュールが使用するクラスですから、WebモジュールのWEB-INF/classes以下にクラスファイルとして配置する、またはJARファイルとしてWEB-INF/lib以下に配置する必要があります。今回は、タグハンドラHelloTag.classを次の位置に配置します。

WEB-INF/classes/mytaglib/HelloTag.class

 TLDは、通常、WEB-INF/以下に配置します。

WEB-INF/mytaglib.tld

 そして、Webモジュールのデプロイメントディスクリプタ WEB-INF/web.xmlに<taglib>要素を追加します。

Webモジュールのデプロイメントディスクリプタ web.xml
<?xml version="1.0" encoding="Shift_JIS" ?>
<!DOCTYPE web-app 
          PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" 
          "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">

<web-app>
.....
  <taglib>
    <taglib-uri>http://mycompany.com/my-taglib_1_0</taglib-uri>
    <taglib-location>/WEB-INF/tlds/PRlibrary_1_4.tld</taglib-uri>
  </taglib>
.....
</web-app>

要素 意味
<taglib-uri> このタグライブラリを識別するURI
<taglib-location> このタグライブラリのTLDの位置

 URIは、タグライブラリを識別するためだけに使われますので、有効なURLである必要はありません。

 JSPページでは、taglibディレクティブを用いて、利用するタグライブラリのURIを接頭辞にバインドします。次の例では、mytaglibという接頭辞を指定しています。

<%@ taglib uri="http://mycompany.com/my-taglib_1_0" 
           prefix="mytaglib" %>
.....
<mytaglib:HelloTag />
.....

 簡単なサンプルコードを用いて、タグハンドラの実装、TLDの作成、デプロイメントディスクリプタの設定、JSPページのカスタムタグの利用を、一連の流れに沿って見てきました。

 本稿では、カスタムタグの極めて基本的な部分しか説明していません。もし、カスタムタグに興味を持たれたならば、Webページや書籍などでより詳しい情報を集めることをお勧めします。

記事INDEX
 

対談 JSPの活用がこれからのWeb開発の鍵

「JSPカスタムタグ徹底入門」
第1回 JSPカスタムタグの仕組みを知ろう
  「JSPカスタムタグ徹底入門」
第2回  実践!JSPカスタムタグ活用術
  JSPカスタムタグ・ライブラリ
 


</comment> <tr> <td bgcolor="#EEEEEE"><font size="2"><a href="javascript:KeepIt();"> <img src="/club/keepoint/images/ico_kpt.gif" alt="kee&lt;p&gt;oint保存" border="0" align="absmiddle" width="24" height="18">kee&lt;p&gt;ointで保存</a></font></td> </tr> <comment>

 
@ITトップ@IT Special インデックス会議室利用規約プライバシーポリシーサイトマップ