Section10: カスタムタグライブラリの構築

タグハンドラ
tldファイルの要素
要素多重度説明
taglib1ルート要素
tlib-version1カスタムタグのバージョン
short-name1カスタムタグの略称
uri?このタグライブラリに設定するURI。taglibディレクティブのuri属性で指定される。
tag*タグに関する設定。
name1タグの名前。
tag-class1タグハンドラクラスの完全修飾名。
tei-class?タグの検証を行うTagExtraInfoを継承したクラスの完全修飾名。タグの属性の組み合わせや、属性の値に制約を設ける場合などに使用する。
body-content1ボディ部のタイプを指定。JSP, scriptless, empty, tagdependentのいずれかを指定する。
valiable*スクリプティング変数に関する設定。
name-given |
name-from-attribute
1name-given: スクリプティング変数の名前を固定的に指定。
name-from-attribute: スクリプティング変数の名前を、カスタムタグの属性の値で指定する場合に使用。属性名を指定する。
variable-class?スクリプティング変数の型の完全修飾名。省略時のデフォルトはjava.lang.String。
declare?スクリプティング変数を新たに定義するかどうかをtrueまたはfalseで指定。すでに定義されている変数を使う場合はfalseを指定する。省略時のデフォルトはtrue。
scope?スクリプティング変数の有効範囲を以下の3つから指定。
AT_BEGIN: 開始タグ以降で有効。
AT_END: 終了タグ以降で有効。
NESTED: カスタムタグのボディ部内のみで有効。省略時のデフォルトはNESTED。
attribute*タグの属性に関する設定。
name1属性名。
required?必須の属性かどうかをtrueまたはfalseで指定する。省略時のデフォルトはfalse。
rtexprvalue?属性に式が使用できるかどうかをtrueまたはfalseで指定。省略時はfalse。fragmentと同時使用不可。
type?属性値の型の完全修飾名。省略時はjava.lang.String。rtexprvalueとセットで使用する。
fragment?属性がJSPフラグメントかどうかをtrueまたはfalseで指定。省略時のデフォルトはfalse。JspFragment型を受け取るsetterを定義する必要がある。フラグメント内にはスクリプト要素を書くことはできない(EL式は評価される)。rtexprvalue, type, deferred-value, deferred-methodと同時使用不可。
deferred-value?EL式の遅延評価に関する設定。fragment, deferred-methodと同時使用不可。
type?評価結果の型の完全修飾名。省略時のデフォルトはjava.lang.Object。
deferred-method?EL式の遅延評価によるメソッド呼び出しの設定。fragment, deferred-valueと同時使用不可。
method-signature?メソッドのシグネチャ。
dynamic-attributes?動的属性の使用するかどうかをtrueまたはfalseで指定。省略時のデフォルトはfalse。
function*EL式でstaticメソッド呼び出しを行うための設定。
name1Functionの名前。
function-class1メソッドが定義されたクラスの完全修飾名。
function-signature1メソッドのシグネチャ。引数や戻り値の型は完全修飾名を使用すること。
例: java.lang.String testFunc(java.lang.String, int)
  • 以下のタグおよびその子タグは省略した
    • display-name
    • icon
    • description
    • validator
    • listener
    • example
    • tag-extension
    • tag-file
    • taglib-extension
    • function-extension
タグハンドラのクラス構成
継承関係: JspTag(interface) ← Tag(interface), SimpleTag(interface). Tag(interface) ← IterationTag(interface) ← BodyTag(interface). IterationTag(interface) ← TagSupport. BodyTag(interface) ← BodyTagSupport. SimpleTag(interface) ← SimpleTagSupport
カスタムタグの種類
種類説明
クラシックタグハンドラJSP1.1から導入されているタグハンドラ。実装がやや煩雑だが、ボディにスクリプトレットまたは式を書く場合はこれを使う必要がある。
シンプルタグハンドラJSP2.0から導入されたシンプルなタグハンドラ。ボディにはEL式を使用できるが、スクリプトレット、式は使用不可能。
タグファイルJSPまたはXMLを使用してカスタムタグを作成する。タグハンドラクラスは記述しない。
クラシックタグハンドラ
TagのAPI
シグネチャ説明
public int doStartTag()開始タグの処理を行う。
public int doEndTag()終了タグの処理を行う。
public void release()タグハンドラが解放状態に移る際に実行される。
public void setPageContext(PageContext pc)PageContextオブジェクトをセットする。タグ実行前に自動的に呼び出される。
public void setParent(Tag t)親タグをセットする。タグ実行前に自動的に呼び出される。
public Tag getParent()親タグを取得する。親タグがない場合はnull。
  • Tagが継承しているJspTagインターフェースはマーカーインターフェースなのでメソッドはない。
Tagの定数
定数を返却するメソッド定数説明
doStartTag()static int EVAL_BODY_INCLUDEボディ部を評価する。
doStartTag()static int SKIP_BODYボディ部をスキップする。
doEndTag()static int EVAL_PAGEタグ以降のページを評価する。
doEndTag()static int SKIP_PAGEタグ以降のページをスキップする。
IterationTagのAPI
シグネチャ説明
public int doAfterBody()ボディ部の評価終了後に呼び出される。
IterationTagの定数
定数を返却するメソッド定数説明
doStartTag()static int EVAL_BODY_INCLUDEボディ部を評価する。
doStartTag()static int SKIP_BODYボディ部をスキップする。
doAfterBody()static int EVAL_BODY_AGAINボディ部を再度評価する。
doAfterBody()static int SKIP_BODYボディ部の評価を終了する。
doEndTag()static int EVAL_PAGEタグ以降のページを評価する。
doEndTag()static int SKIP_PAGEタグ以降のページをスキップする。
TagSupportのprotectedフィールド
フィールド説明
protected String idid属性の値を格納するためのフィールド。
protected PageContext pageContextPageContextを格納するためのフィールド。
  • privateなフィールドといては以下が定義されている。privateなため、使用する場合はgetterから取得する。
    • Tag parent
    • Hashtable<java.lang.String,java.lang.Object> values
TagSupportのAPI
シグネチャ説明
public static Tag findAncestorWithClass(Tag from, Class klass)第1引数で指定されたタグから見て、第2引数で指定されたクラスに対応する先祖タグを検索する。複数候補がある場合は、タグから最も近いものが返される。該当するタグがない場合はnullを返す。
public void setId(String id)id属性をセットする。
public String getId()id属性を返す。セットされていない場合はnullを返す。
public void setValue(String k, Object o)keyにオブジェクトを関連づける。
public Object getValue(String k)keyに関連付けられたオブジェクトを取得する。
public Enumeration<String> getValues()setValue(String k)メソッドで関連付けられたkeyのEnumerationを返す。
public void removeValue(String k)keyに関連付けられたオブジェクトを削除する。
  • getValues()が返すのはvalueではなくkeyのEnumerationなので注意。
  • setPageContext, setParent, getParentのデフォルト実装も用意されているので、開発者が実装する必要はない。
  • pageContextはフィールドから取得、parentはgetterを通じて取得する。
BodyTagのAPI
シグネチャ説明
public void doInitBody()ボディ部での処理の初期化が必要な場合はこのメソッド内に記述する。ボディ部が初めて評価されるときに呼ばれる。
public void setBodyContent(BodyContent b)bodyContentをセットする。
  • setBodyContent(b) → doInitBody() の順番で呼び出される。
BodyTagの定数
定数を返却するメソッド定数説明
doStartTag()static int EVAL_BODY_BUFFEREDボディ部をBodyContentを使って評価する。この定数が返されるときだけdoStartTagメソッドの後に、setBodyContentメソッド、doInitBodyメソッドがこの順番で呼ばれる。
doStartTag()static int EVAL_BODY_INCLUDEボディ部を評価する。
doStartTag()static int SKIP_BODYボディ部をスキップする。
doAfterBody()static int EVAL_BODY_AGAINボディ部を再度評価する。
doAfterBody()static int SKIP_BODYボディ部の評価を終了する。
doEndTag()static int EVAL_PAGEタグ以降のページを評価する。
doEndTag()static int SKIP_PAGEタグ以降のページをスキップする。
BodyContentのAPI
シグネチャ説明
public void clearBody()ボディをクリアする。
public void flush()使用不可。呼び出すとIOExceptionが投げられる。
public JspWriter getEnclosingWriter()JspWriterを取得する。
abstract public Reader getReader()ボディ部を読み込むReaderを取得する。
abstract String getString()ボディ部の値をStringで取得する。
abstract void writeOut(Writer out)BodyContentの内容を指定されたWriterに書き出す。
  • doAfterBody()内では、BodyContent#getEnclosingWriter()で取得したJspWriterに出力しないと画面に表示できない。
シンプルタグハンドラ
SimpleTagのAPI
シグネチャ説明
public void doTag()タグの処理を行う。
public void setJspContext(JspContext pc)JspContextオブジェクトを設定する。タグ実行前に自動的に呼び出される。
public void setJspBody(JspFragment jspBody)ボディ部をJSPフラグメントとして設定する。タグ実行前に自動的に呼び出される。
public void setParent(JspTag parent)親タグを設定する。タグ実行前に自動的に呼び出される。
public JspTag getParent()親タグを取得する。
  • Tagインターフェースと違い、doTag()は定数を返さない。
  • TagインターフェースのAPIと比べて、引数や戻り値がTagではなくJspTagとなっていることに注意。
  • TagインターフェースのAPIと比べて、PageContextではなくJspContextとなっていることに注意。(JspContextはPageContextの親クラス)
  • クラシックタグハンドラはタグのインスタンスが使いまわされる可能性があるが、SimpleTagは1回の使用でインスタンスを破棄する。そのため、後処理はdoTag()の最後に記述すればよいので、release()メソッドは定義されていない。
SimpleTagSupportのAPI
シグネチャ説明
public static JspTag findAncestorWithClass(JspTag from, Class<?> klass)第1引数で指定されたタグから見て、第2引数で指定されたクラスに対応する先祖タグを検索する。複数候補がある場合は、タグから最も近いものが返される。該当するタグがない場合はnullを返す。
protected JspFragment getJspBody()ボディ部のJSPフラグメントを取得する。
protected JspContext getJspContext()JspContextを取得する。
  • setJspContext, setJspBody, setParent, getParentのデフォルト実装も用意されているので、開発者が実装する必要はない。
  • TagSupportと違い、id属性やkeyとvalueの関連付けなどは提供されない。
  • SimpleTagSupportでは全てのフィールド(jspBody, jspContext, parentTag)はprivateで保持されているため、必ずgetterを通じて取得する。
SimpleTagでのボディ部に関する制約
制約説明
ボディ部の制約スクリプト要素を記述することができない。スクリプト要素を記述する場合はクラシックタグハンドラを使う。
tldファイルの<body-content>タグの指定についてJSPは指定不可。empty, scriptless, tagdependentのいずれかを指定する。
SimpleTagでのボディ部の評価方法
SimpleTagのボディ部を評価する方法、および、tldファイルの<body-content>タグの値によって評価にどのような違いがあらわれるかを答えよ。
  • タグハンドラ内でgetJspBody().invoke(Writer out)メソッドを呼び出して評価する。引数には評価結果を出力するWriterを指定する。引数にnullを与えると、JspContext.getOut()を使用して評価結果を出力する。
  • tldファイルの<body-content>タグに応じた評価結果の違い
    • scriptlessの場合:
      ボディ部のEL式とアクションタグ(標準アクションタグおよびカスタムタグ)が評価され、それ以外はテンプレートテキストとしてそのまま出力される。スクリプト要素を記述するとエラーになる。
    • tagdependentの場合:
      ボディ部のテキストがそのまま出力される。EL式、アクションタグ、スクリプト要素を記述してもそのままテンプレートテキストとして出力される。
  • tldファイルの<body-content>タグがscriptlessの場合、子孫タグのボディ部にもスクリプト要素を記述することはできない。
SimpleTagで実行後に残りのJSPページをスキップする方法
  • doTag()メソッド内でSkipPageExceptionをスローすると、タグ以降のJSPページを評価しない。
タグハンドラ共通の設定・機能
動的属性の使用
動的属性を使用する際に必要な設定・実装作業
tldファイルの<tag>タグの下に<dynamic-attributes>タグを記述し、値をtrueにする。
タグハンドラクラスにjavax.servlet.jsp.tagext.DynamicAttributesインターフェースを実装し、属性の処理を記述する。
DynamicAttributesのAPI
シグネチャ説明
public void setDynamicAttribute(String uri, String localName, Object value)動的属性(attributeタグで指定されていない属性)が読み込まれるたびに実行されるメソッド。uri: 属性の名前空間。デフォルトの名前空間の場合はnull。localName: 属性名。value: 属性の値。
スクリプティング変数の使用
スクリプティング変数を使用する際に必要な設定・実装作業
tldファイルの<tag>タグの下に<variable>タグを記述し、その子タグとして<name-given>または<name-from-attribute>タグを記述して変数名を指定する。
タグハンドラ内のメソッド(doStartTag()など)で、PageContextにスクリプティング変数名をキーとして変数の値を格納する。例: pageContext.setAttribute(varName, "value");
  • <name-from-attribute>タグを使って変数名を指定する場合、<name-from-attribute>タグで指定した属性を省略するとスクリプティング変数が決定できずにエラーとなる。(Tomcat6.0で確認)
JSPフラグメント属性の使用
JSPフラグメントの属性に関して以下を答えよ。
-説明
定義方法
  • tldファイルの<attribute>タグの下に<fragment>タグを記述し、値をtrueにする。
  • タグハンドラクラスに属性のsetterメソッドを記述。引数の型をJspFragmentにする。
属性に値を指定する方法カスタムタグのボディ部に<jsp:attribute>タグを使って属性を記述する。このタグを使用する場合にボディ部を記述する場合は、必ず<jsp:body>タグを使用する。
記述できない要素スクリプト要素は記述不可。(EL式、アクションタグは記述可能)
評価方法タグハンドラ内でJspFragment#invoke(Writer out)メソッドを呼び出して評価する。引数には評価結果を出力するWriterを指定する。引数にnullを与えると、JspContext.getOut()を使用して評価結果を出力する。
親・先祖タグへのアクセス方法
検索対象方法
親タグ 以下のどちらかを使用。親がいない場合はnullが返される。
  • public Tag Tag#getParent()
  • public JspTag SimpleTag#getParent()
先祖タグ 以下のどちらかを使用。複数候補がある場合は、タグから最も近いものが返される。該当するタグがない場合はnullを返す。
  • public static Tag TagSupport#findAncestorWithClass(Tag from, Class klass)
  • public static JspTag SimpleTagSupport#findAncestorWithClass(JspTag from, Class klass)
タグファイル
タグファイルの制約
-説明
保存場所WEB-INF/tags、またはWEB-INF/lib/*.jar内のMETA-INF/tags。(どちらもサブディレクトリを許容する)
ファイル名xxx.tag、xxx.tagx(XML形式の場合)。xxxはタグ名として使用される。
JSPでの使用方法JSPのtaglibディレクティブを記述する。tagdir属性でタグファイル配置場所のディレクトリを、prefix属性でプレフィックスの指定を行う。(例: <%@ taglib tagdir="/WEB-INF/tags/" prefix="tags"%>)
(タグファイルはtldファイルを作成しなくても使えるが、タグファイルに対してtldファイルを作成してuri属性を設定することもできる。その場合は、通常のカスタムタグと同様に、tagdir属性の代わりにuri属性でタグファイルを指定することができる。)
タグのボディ部に関する制約スクリプト要素は記述不可能。(EL式、アクションタグは記述可能)
タグファイルで使用可能な暗黙オブジェクト
暗黙オブジェクト
jspContextjavax.servlet.jsp.JspContext
requestjavax.servlet.ServletRequest
sessionjavax.servlet.http.HttpSession
applicationjavax.servlet.ServletContext
responsejavax.servlet.ServletResponse
outjavax.servlet.jsp.JspWriter
configjavax.servlet.ServletConfig
  • pageContextではなくjspContextであることに注意。
  • page, exceptionはない
タグファイル専用のディレクティブタグ
種類JSP形式タグXML形式タグ説明
tagディレクティブ<%@ tag 属性="値" ... %><jsp:directive.tag 属性="値" ... />タグの設定全般を記述する。
attributeディレクティブ<%@ attribute 属性="値" ... %><jsp:directive.attribute 属性="値" ... />タグの属性に関する設定。
variableディレクティブ<%@ variable 属性="値" ... %><jsp:directive.variable 属性="値" ... />スクリプティング変数の設定。
  • taglib, includeディレクティブもタグファイル内で使用可能。
  • pageディレクティブのみタグファイル内では使用不可。
tagディレクティブの属性
属性デフォルト値説明
body-contentscriptlessボディ部のタイプを指定。empty, scriptless, tagdependentから指定する。
dynamic-attributes-動的属性を使用する場合に、動的属性の属性名と値を格納するMapの変数名を指定する。
importjava.lang.*, javax.servlet.*, javax.servlet.http.*, javax.servlet.jsp.*インポートするクラスの指定。カンマ区切りで複数記述可能。
isELIgnoredfalseEL式を無視するかどうか。
languagejava使用する言語。
pageEncodingISO-8859-1このタグファイルの記述に使用されている文字エンコーディング。
deferredSyntaxAllowedAsLiteralfalse遅延評価のEL式の記法 #{} をリテラル中でただの文字列とみなすかどうか。
trimDirectiveWhitespacesfalse通常ディレクティブ行は空行として出力されるが、この属性がtrueの場合、空行を出力しなくなる。
  • 属性は全て必須ではない。
  • 以下の属性もあるが省略した。
    • description
    • display-name
    • example
    • large-icon
    • small-icon
attributeディレクティブの属性
属性必須デフォルト値説明
name-属性名
required-false必須の属性かどうか。
fragment-false属性がJSPフラグメントかどうか。
rtexprvalue-true属性に式の記述を許すかどうか。
type-java.lang.String属性の型の完全修飾名。
deferredValue-trueEL式の遅延評価( #{} )を受け入れるかどうか。
deferredValueType-java.lang.StringEL式の遅延評価結果が属する型の完全修飾名。
deferredMethod-trueEL式の遅延評価によるメソッド呼び出しを受け入れるかどうか。
deferredMethodSignature--EL式の遅延評価によるメソッド呼び出しで使用されるメソッドのシグネチャ。
  • rtexprvalueは、tldファイルではデフォルトfalseだが、attributeディレクティブではデフォルトtrueなので注意。
  • 他にdescription属性もあるが省略した。
variableディレクティブの属性
属性必須デフォルト値説明
name-given-スクリプティング変数の名前を指定する。
name-from-attribute-スクリプティング変数の名前が格納された属性を指定する。name-givenとどちらかを指定する必要がある。このタグで指定する属性は rtexprvalue が false でなければならない(デフォルトでtrueなので、明示的にrtexprvalue="false"の指定が必要)
alias-タグファイル内でスクリプティング変数を扱う場合の変数の別名を定義する。name-from-attributeタグを使用する場合は必ず指定が必要。また、name-given属性と同時には使用できない。
variable-class-java.lang.Stringスクリプティング変数の型の完全修飾名。
declare-trueスクリプティング変数を新たに定義するかどうかをtrueまたはfalseで指定。すでに定義されている変数を使う場合はfalseを指定する。
scope-NESTEDスクリプティング変数の有効範囲を以下の3つから指定。AT_BEGIN: 開始タグ以降で有効。 AT_END: 終了タグ以降で有効。 NESTED: カスタムタグのボディ部内のみで有効。
  • 他にdescription属性もあるが省略した。
タグファイル用の標準アクション
タグ説明
<jsp:doBody>ボディ部の評価を行う。
<jsp:invoke>JSPフラグメント属性の評価を行う。
<jsp:doBody>タグの属性
属性必須デフォルト値説明
var--ボディの評価結果を格納する変数を指定する。
varReader--ボディの評価結果を読み込むReaderを格納する変数を指定。
scope-pagevarまたはvarReaderで指定した変数のスコープ。page, request, session, applicationから指定する。
  • varとvarReaderの両方が指定されない場合、タグの位置に評価結果が展開される。
<jsp:invoke>タグの属性
属性必須デフォルト値説明
fragment-JSPフラグメントを格納する属性名。
var--JSPフラグメントの評価結果を格納する変数を指定する。
varReader--JSPフラグメントの評価結果を読み込むReaderを格納する変数を指定。
scope-pagevarまたはvarReaderで指定した変数のスコープ。page, request, session, applicationから指定する。
  • varとvarReaderの両方が指定されない場合、タグの位置に評価結果が展開される。
inserted by FC2 system