目次へ

8. ボディ部を操作するカスタムタグ

8.1. javax.servlet.jsp.tagext.BodyTag

「BodyTag」インタフェースにおける処理の流れの図

これまで作成したカスタムタグは、ボディ部の内容をハンドラクラスで操作する事ができませんでした。それを可能にするためには「javax.servlet.jsp.tagext.BodyTag」インタフェースを実装したハンドラクラスを作成する必要があります。「BodyTag」インタフェースは「IterationTag」を継承したインタフェースで、繰り返し機能も保持しています。

右図は「BodyTag」インタフェースにおける処理の流れです。「IterationTag」と異なる点は「doStartTag」の返り値に「EVAL_BODY_BUFFERED」を指定した場合の処理です。ボディ部の内容を処理するには、この「EVAL_BODY_BUFFERED」を指定する必要があります。「EVAL_BODY_INCLUDE」「SKIP_BODY」を指定した場合は、これまでと同じ挙動をします。

「EVAL_BODY_BUFFERED」を指定した場合の処理について説明します。「doStartTag」の返り値としてこの値が返されると、サーブレットコンテナは「setBodyContent」「doInitBody」メソッドを順に呼び出します。「setBodyContent」はタグに「javax.servlet.jsp.tagext.BodyContext」インスタンスを渡すメソッドで、これはボディ部のデータを格納するために使用されます。通常、コンテナは「JspWriter」のインスタンスである「out」(JSPにおける暗黙オブジェクト)にボディ部の内容を直接出力します。「doStartTag」が「EVAL_BODY_BUFFERED」を返した場合には、「BodyContent」インスタンスにボディ部の内容を格納します。ハンドラクラスではこの「BodyContent」インスタンスから、ボディ部の内容を取得します。

もう1つ実行されるメソッド、「doInitBody」はボディ部が初めて評価されるときに実行されます。ボディ部で行う処理の初期化などに利用されます。

その後の処理の順番は「IterationTag」と同じです。「doAfterBody」で「EVAL_BODY_AGAIN」を返した場合はボディ部の再評価、「SKIP_BODY」を返した場合は「doEndTag」が呼び出されます。「EVAL_BODY_AGAIN」を返した場合に再び「setBodyContext」「doInitBody」が呼び出される事はありませんが、ボディ部の内容は「bodyContent」に格納されます。

最後に1つ注意点があります。JSPページに何らかの出力を行う場合、「doStartTag」「doEndTag」内ではこれまで通り、「PageContext」の「getOut」で取得できる「JspWriter」を使用しても問題ありません。しかし「doAfterBody」メソッド内で同じ事をしても、JSPページには何の出力もされません。「doAfterBody」メソッド内では「BodyContent」の「getEnclosingWriter」で取得できる「JspWriter」を使用するようにしてください。これはカスタムタグの1つ外部に存在する親タグの「JspWriter」です。

以下に「BodyTag」を利用したタグ・ハンドラクラスの例を示します。これは属性「file」で指定されたファイルにボディ部の内容を書き込むタグです。「doAfterBody」のタグ内でボディ部の内容を読み込むためのリーダ、ファイルへ書き込むためのライタを生成しています。後は1行ずつボディ部から文字列を読み込み、ファイルへ書き出しています。

...
public class FileTag implements BodyTag{
  ...
  private BodyContent bodyContent=null;
  private File out=null;
  ...
  public void setFile(String path){
    out=new File(path);
  }
  
  public int doStartTag() throws JspException{
    return(EVAL_BODY_BUFFERED);
  }
  
  public void setBodyContent(BodyContent bodyContent){
    this.bodyContent=bodyContent;
  }
  
  public void doInitBody(){}
  
  public int doAfterBody() throws JspException{
    try{
      BufferedReader reader=new BufferedReader(bodyContent.getReader());
      BufferedWriter writer=new BufferedWriter(new FileWriter(out));
      String line;
      while((line=reader.readLine())!=null){
        writer.write(line,0,line.length());
        writer.newLine();
      }
      writer.flush();
      writer.close();
    }catch(IOException e){
      throw new JspException(e.getMessage());
    }
    return(SKIP_BODY);
  }
  
  public int doEndTag() throws JspException{
    return(EVAL_PAGE);
  }
  ...
}

ボディ部からデータを読み取る方法としては、サンプルのように「getReader」で返される「java.io.Reader」を利用する方法の他に、「getString」で直接文字列データを取得する方法もあります。

(実習課題1)

以下のカスタムタグを作成し、それを使用したJSPページを作成しなさい。

  • ボディ部にはタブ区切り(\t)で文字列データが記載される。そのデータをテーブルに変換してJSPページに出力するカスタムタグ。
  • タブで区切られた1つのデータが、そのままテーブルの1カラムになる事。
  • 1行がそのままテーブルの1行になる事。

解答例はこちら

↑このページの先頭へ

こちらもチェック!

PR
  • XMLDB.jp