Strutsのカスタムタグを拡張する

Strutsはカスタムタグが提供されていますが、汎用的過ぎて業務仕様からするともの足りないことが多いと思います。そういったときに、より業務仕様に特化したカスタムタグを作成すると都合がよいです。

今回のサンプルは数値用のテキストフィールドのタグを作ってみます。
html:textタグを拡張してhtml:numtextという数値フィールド用テキストタグを考えます。
あまり凝ったものではなく、
フォーカスロスト(onblur)→3桁区切りでカンマをつける
フォーカスロスト
フォーカスゲイン(onfocus)→カンマを除去する
フォーカス取得
という機能を持ちます。JavaScriptで実現します。

タグクラスNumTextTag

カスタムタグの本体を作成します。継承元のクラスはorg.apache.struts.taglib.html.TextTagです。
public class NumTextTag extends TextTag {

このタグの実装としてはTextTagと同様の機能を持ちながら、自動的にonblur、onfocusのイベント処理が指定されるようにします。TextTagは「処理の一部がオーバーライドされる前提」で作成されているので、簡単に機能拡張できます。
onblur時に、javascriptの関数addCommaを呼び出す処理を追加します。(addCommaの実装については後述)

  @Override
  public String getOnblur() {
    String org = super.getOnblur();
    return "addComma(this);" +  (org == null ? "" : org);
  }

JSP上のHTMLでもonblurを指定できないと困るので、直接タグで指定したonblurも呼び出されるようにします。
addComma(this);{タグで指定した処理};
のように処理を連続して動作させるようにします。
onfocus時にも同様に、関数removeCommaを呼び出すようにします。

さて、addComma/removeComma関数はどこに用意しましょうか?
外部JavaScriptファイルを用意して、JSPからインクルードするようにしてもOKですが、そうなると、「このJavaScriptファイルを必ずインクルードすること」というコード現れない制約が発生してしまいます。
NumTextTag単体で使えるようにするため、このタグを使用すると自動的にaddComma/removeComma関数を定義するようにします。

doStartTagメソッドをオーバーライドして、NumTextTagが使用されたときにaddComma/removeComma関数を出力するようにします。タグを2度使用されても関数が2回定義されないようにpageContextに属性を用意しています。こうすることでNumTextTagが初めて現れたときだけ出力されます。

if (pageContext.getAttribute(TextTag.class.getName()) == null){
  //イベント用関数の生成
  TagUtils.getInstance().write(this.pageContext,
        "<script language=\"javascript\">"
      +  "function addComma(field){"
      ~中略:後述~
      +  "}"
      +  "function removeComma(field) {"
      ~中略:後述~
      +  "}"
      + "</script>"
  );
  pageContext.setAttribute(TextTag.class.getName(), Boolean.TRUE);
}

Javaソースコードの文字列リテラルの中にJavaScriptを記述するのは書きにくいです。。。
これでカスタムタグは完成です。

addComma/removeComma関数

これは検索したら、とても簡潔なコードがありましたのでそれを参考にさせてもらいました。
参考:634 – JavaScript – 数値のカンマ編集を行う
引数に文字列ではなくテキストオブジェクトを渡すようにし、value値を書き換えるようにしました。

tldファイルの修正

カスタムタグはクラスを作成するだけでは使えません。tldファイルに定義が必要になります。
struts-html.tldファイルに、taglib/tag/nameがtextとなっているタグの定義があります。これがTextTagの定義です。今回作成するNumTextTagはほとんどこれと同じなので、この定義をごっそりコピーして追加し一部を修正します。

<tag>
  <name>numtext</name>
  <tagclass>struts.tags.NumTextTag</tagclass>
  <attribute>
    <name>accesskey</name>
    <required>false</required>
    <rtexprvalue>true</rtexprvalue>
  </attribute>
  ~中略~
</tag>

tagclassの部分を自分が作成したクラス名に置き換えます。
自作したタグに新しい属性を追加したい場合には、attributeタグを追加したりするわけです。このへんの作り方は、strutsは関係なくJSP仕様のタグライブラリの作成方法に従います。

JSPから使用する

これで準備が整いました。JSPからはこんな感じで記述するだけです。

数値型フィールド1:<html:numtext property="num1" styleClass="numfield"/>

styleClassは右寄せ表示するスタイルを定義しています。カスタムタグで自動出力してもよいのですが、見た目に依存することなのでカスタムタグからは指定していません。「JSP側で個別に指定したいこともあるだろう」との考えです。業務仕様ガッチリのタグを作るのでされば、カスタムタグで指定しちゃってもよいと思います。

IDEからtldファイルの内容を読み込んで、オートコンプリートで選択できるようになるはずです。
数値フィールド

サンプルソースコード

https://app.box.com/s/v63vb7ai98dc16kjwa2rhgct9jbij3wc

更に機能追加して、自動で数値の入力チェックをおこなってエラーのときに赤くするとかも考えられます。
カスタムタグは作っていて楽しいです。
あまり汎用性などを意識せずに、「~こうなっていたら、JSP書く時にすごく簡潔に書けるのにー」って要望を存分に実装して、JSPの記述がすごく楽になるようにすると便利です。でもチーム開発している時に、あまり懲りすぎると新たに加わった開発メンバーが、カスタマイズされまくったカスタムタグを勉強するのに時間がかかるなんてこともあるので、その辺も考慮しつつ作成するとよいかと思います。


Strutsのカスタムタグを拡張する」への3件のフィードバック

  1. ソースが断片過ぎてよくわからないです
    サンプルソースもすでに404になっていて残念です(><

  2. とりあえずこのページだけ修正しました。

  3. おお!すごいかわってる!
    こんな過去の技術なのにありがとうございます。
    もう一度読み直して勉強します!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください