リファレンストップへ Java | カスタムタグの作成【基本】使用した環境 JDK 6 Update 11 Tomcat 6.0.18 JSPカスタムタグを自作する際のサンプルです。ボディ部を持つタグとボディ部を持たないタグでは、若干作成方法が異なります。ボディ部とは、ネストされるタグ要素を示します。 ボディ部なしのタグの例 <sample:abc attr="xxx" /> ボディ部ありのタグの例 <sample:abc attr="xxx"> body content<br /> </sample:abc> ボディ部を持たないタグの作成サンプルとして、パラメータで与えられた値を、String#toUpperCase()を使用して大文字に変換するタグを作成してみます。 まず、カスタムタグの処理を実施するタグハンドルクラスを作成します。 UpperTag.java package sample; import java.io.IOException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.tagext.TagSupport; /** * 大文字に変換を行うタグ */ public class UpperTag extends TagSupport { // (1) /** 処理対象のオブジェクト */ private Object value; // (2) @Override public int doStartTag() throws JspException { // (3) // パラメータがnullの場合は何も行わない if (value != null) { // 大文字に変換を行う。 String outValue = value.toString().toUpperCase(); // 出力を行う JspWriter out = pageContext.getOut(); try { out.write(); } catch (IOException e) { throw new JspException(e); } } return SKIP_BODY; // (4) } @Override public void release() { // クラス変数の開放を行う super.release(); value = null; } /** * 処理対象のオブジェクトを設定する * @param value */ public void setValue(Object value) { this.value = value; } } (1) javax.servlet.jsp.tagext.TagSupportを継承する事により、このクラスをタグとして実行可能にします。 (2) タグの属性として受け取るパラメータは、クラス変数として定義しsetterメソッドを作成しておきます。 (3) doStartTagメソッドは、開始タグの処理を記述するメソッドです。ボディ部を持たないタグの場合は、このメソッドのオーバーライドだけで実装できます。 (4) 定数「SKIP_BODY」を返すと、ボディ部の処理のスキップを指示できます。 次にtldファイルを作成します。 WEB-INFディレクトリ以下に、以下のようなファイルを作成します。 /WEB-INF/sample.tld <?xml version="1.0" encoding="UTF-8"?> <taglib xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xml="http://www.w3.org/XML/1998/namespace" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd" version="2.1"> <tlib-version>1.0</tlib-version> <uri>/sample</uri> <tag> <name>upper</name> <tagclass>sample.UpperTag</tagclass> <body-content>empty</body-content> <attribute> <name>value</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag> </taglib> <body-content>empty</body-content>とする事で、ボディ部を処理しないタグである事を定義しています。 tldファイルの詳細な情報についてはtldファイルを参照してください。 以上で自作したタグが使用可能となります。 JSPでは以下のようにして使用できます。 <%@ page contentType="text/html; charset=Windows-31J" pageEncoding="Windows-31J" %> <%@ taglib uri="/sample" prefix="sample" %> <% String value = "abcdef"; %> <sample:upper value="<%= value %>" /> このサンプルで出力されるhtmlは以下のようになります。 ABCDEF ボディ部を持つタグの作成サンプルとして、ボディ部の値を、String#toUpperCase()を使用して大文字に変換するタグを作成してみます。 まず、カスタムタグの処理を実施するタグハンドルクラスを作成します。 BodyUpperTag.java package sample; import java.io.IOException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.tagext.BodyTagSupport; /** * ボディ部の内容を大文字に変換を行うタグ */ public class BodyUpperTag extends BodyTagSupport { // (1) @Override public int doStartTag() throws JspException { // (2) return EVAL_BODY_BUFFERED; // (3) } @Override public int doEndTag() throws JspException { // (4) // ボディ部の値を取得 String value = bodyContent.getString(); // (5) // 大文字に変換 value = value.toUpperCase(); // 出力を行う JspWriter out = pageContext.getOut(); try { out.write(value); } catch (IOException e) { throw new JspException(e); } return EVAL_PAGE; // (6) } } (1) javax.servlet.jsp.tagext.BodyTagSupportを継承する事により、このクラスをボディ部をサポートするタグとして実行可能にします。 (2) doStartTagメソッドは、開始タグの処理を記述するメソッドです。<sample:bodyUpper>部分に相当する処理です。 (3) 定数「EVAL_BODY_BUFFERED」を返すと、ボディ部の内容をバッファリングし、その値を終了タグの処理で使用可能となります。 (4) doEndTagメソッドは、終了タグの処理を記述するメソッドです。</sample:bodyUpper>部分に相当する処理です。 (5) bodyContent.getString()とする事で、ボディ部の内容を取得する事が可能です。 (6) 定数「EVAL_PAGE」を返すと、その後のJSP処理が続行されます。 次にtldファイルを作成します。 WEB-INFディレクトリ以下に、以下のようなファイルを作成します。 /WEB-INF/sample.tld <?xml version="1.0" encoding="UTF-8"?> <taglib xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xml="http://www.w3.org/XML/1998/namespace" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd" version="2.1"> <tlib-version>1.0</tlib-version> <uri>/sample</uri> <tag> <name>bodyUpper</name> <tagclass>sample.BodyUpperTag</tagclass> <body-content>JSP</body-content> </tag> </taglib> <body-content>JSP</body-content>とする事で、ボディ部をJSPとして処理するタグである事を定義しています。 tldファイルの詳細な情報についてはtldファイルを参照してください。 以上で自作したタグが使用可能となります。 JSPでは以下のようにして使用できます。 <%@ page contentType="text/html; charset=Windows-31J" pageEncoding="Windows-31J" %> <%@ taglib uri="/sample" prefix="sample" %> <sample:bodyUpper> abcdef </sample:bodyUpper> このサンプルで出力されるhtmlは以下のようになります。 ABCDEF タグクラスのメソッドと戻り値TagSupportやBodyTagSupportがimplementsしているクラスjavax.servlet.jsp.tagext.Tag及びjavax.servlet.jsp.tagext.IterationTagが、カスタムタグの処理を定義しているインターフェイスになります。 実際にはTagSupportやBodyTagSupportを継承しなくてもTagをimplementsし、必要なメソッドを実装すればタグとして動作しますが、 TagSupportやBodyTagSupportを継承する事で実装量を軽減する事ができるようになっています。 タグハンドルのインターフェイスで定義されている各メソッドは以下のようになっています。
TagSupportやBodyTagSupportを継承してタグを作成する場合は setPageContext(), setParent(), getParent(), setBodyContent()メソッドについては既に実装されているので、オーバーライドして実装する必要は特にありません。 doStartTag(), doEndTag(), doAfterBody()には実際の処理を記述する事になりますが、 これらのメソッドは戻すintの値によって、その後の処理が変化します。 メソッドの戻り値に使用するintの定数はTag/IterationTag/BodyTagインターフェイスに定義されています。
それぞれのメソッドと定数を組み合わせる事によって、複雑な処理を行うタグを作成する事が可能です。 実践的なサンプルはカスタムタグの作成【分岐・繰り返し】を参照してください。 ※ release()メソッドには、xxx = null;といったように、クラス変数の開放処理を記述しておく事となります。 これは、サーブレットコンテナによっては同じJSPページ内で、タグクラスのインスタンスを使いまわす可能性があるため、 明確にクリア処理を行っていないと、思わぬバグを引き起こす事となるためです。 例えばtomcatではタグインスタンスの使いまわしを行います。 ですが、実際にはrelease()メソッドが呼び出されるタイミングは保証されていないため、 毎回上書かれない(必須でない)属性値を持つタグの場合はdoEndTag()タグ内で更に release()を呼び出すような実装にしておいた方が安全です。 |
|