JavaSTHプロジェクトについて

Javaエンジニアの使用しやすい HTMLテンプレートエンジンのフレームワークです。ちなみにSTHとは Simple Template HTMLの略です。 htmlファイルをベースにjavaのモデルクラスのデータをリンクさせて 動的ページを作ります。
スクリプト言語でも新しい言語でもJSPでもなく「Java 」で書きます。

コンセプト

・Javaで書く。独自のテンプレートエンジン用の構文を覚えたくない!(JSPもヤダ)
・HTMLテンプレートエンジンに徹する。(コントローラに手を出さない)
・シンプルにつくり、拡張させる。(フレームワークに徹する)

結果→
・よりシンプルなHTMLをリソースとするのでデザイナと分業できる!
・Javaで書けるから新しい構文覚えなくていい。
コード補完ももちろんできる! 使い慣れた環境、構文。
・Javaだから拡張するときもJavaのクラスだけ気にすればOK!

JavaエンジニアなのだからJavaだけで書きたい!!!


他のプロダクトとの違い

・通常のテンプレートエンジンとの違い
HTML専用なのでHTMLへのプログラムからのアクセスが簡単

・他のHTMLテンプレートエンジンとの違い HTMLはシンプルに。キーはidのみ。omitやifなどをHTMLに書くなんて考えられない!
spanタグやdivタグをシステムのために追加するのを極力しないようにしたい。
(tdタグの中にspanタグが同じ領域を制御するのにあるのとか最悪!)
あとはXHTMLだからと言ってデザイナがよく理解できない名前空間はあまり使いたくない。
(これはニーズによっては対応するかも)
Javaでアクセス。(Javaエンジニアですもの)
1つのタグに複数の効果を付けて操作できる。

javaで書いているので、変更があったとき、
どのHTMLに影響があるかをすぐ確認することが出来ます
DTOを受け渡していても、そのカラムが画面に影響があるかどうかまで詳細にIDEが知らせてくれます。

使い方

キーワードは「Sth」

java5以上対応。

概要

1.

まず用意するものはテンプレートとなる「HTML」ファイルです。
このHTMLはXMLとして読める形式である必要があります。
具体的に言うと<br>タグや<input>タグは通常HTMLで書くときにはタグが閉じられていないことが多いですが
これらのタグも<br />、<input />といったようにタグを閉じる必要があります。

次に処理をしたいタグにはidが必要です。
処理を行うタグにidをつけて、名前をつけてください。


デザイナとの連携の意味もあわせて
現バージョンでは対応していませんが通常のHTML(閉じタグなどが省略されたもの)も読めるようにしたいと考えています。
現在はパース出来ないのでHTMLからXHTMLに変換できるnekoHTMLなどを使用して変換してください。

2.

次に必要なものがHTMLに対応するJavaファイルです。
現在はこのクラスのネーミングはまず先頭を大文字にしてさらにHTMLファイルの名前から.htmlの「.」を除いて「H」を大文字にしたものを推奨しています。

例) abc.htmlと対応するクラスを作成する場合、
AbcHtml.javaを作成する。


とりあえず、用意するものはこれだけです。
では中身の解説。

まず、JavaSTHはidとリンクして処理を行います。
idを探し、idの名称と合致するフィールド、もしくはプリフィックスにidが付くメソッドがあった場合それを呼び出します。
それだけです。

ではサンプルを見ながらどうぞ。


■HTMLファイル

  1. <html>
  2. <head>
  3. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  4. <title>タグまとめて紹介</title>
  5. </head>
  6. <body>
  7. JavaSTH<br/>
  8. <table id="tableData">
  9. <thead>
  10. <tr>
  11. <th>no</th>
  12. <th>oddeven</th>
  13. <th>text</th>
  14. <th>button</th>
  15. <th>check</th>
  16. </tr>
  17. </thead>
  18. <tbody>
  19. <tr id="grid">
  20. <td id="no"></td>
  21. <td id="oddeven"></td>
  22. <td><input type="text" id="txt"/></td>
  23. <td><input type="button" id="btn" /></td>
  24. <td><span id="maru"></span></td>
  25. </tr>
  26. <tr id="dummy">
  27. <td>a</td>
  28. <td>b</td>
  29. <td>c</td>
  30. <td>d</td>
  31. <td>e</td>
  32. </tr>
  33. </tbody>
  34. </table>
  35. </body>
  36. </html>



■Javaファイル

  1. package jp.sourceforge.javasth.view.model;
  2. import java.util.Arrays;
  3. import jp.sourceforge.javasth.Sth;
  4. import jp.sourceforge.javasth.annotation.SthText;
  5. import jp.sourceforge.javasth.util.SthUtil;
  6. public class SthTestHtml {
  7. @SthText
  8. public String no;
  9. public Sth idTableData(){
  10. return SthUtil.createSTag("bgcolor", "blue");
  11. }
  12. public Sth idGrid(){
  13. Integer[] list = new Integer[]{1,2,3,4,5,6,7,8,9,10};
  14. return SthUtil.createSFor(Arrays.asList(list), this, "gridNext");
  15. }
  16. public void setGridNext(Integer i){
  17. this.no = String.valueOf(i);
  18. }
  19. public Sth idOddeven(){
  20. String text = Integer.parseInt(no) % 2 == 0 ? "even" : "odd";
  21. return SthUtil.createSText(text);
  22. }
  23. public Sth idTxt(){
  24. return SthUtil.createSTag("value", "data" + no)
  25. .setAllOverWrite(false);
  26. }
  27. public Sth idBtn(){
  28. return SthUtil.createSTag("value", "押下")
  29. .addAttribute("id", null)
  30. .addAttribute("class", "s")
  31. .addAttribute("hoge", null);
  32. }
  33. public Sth[] idMaru(){
  34. String text = Integer.parseInt(no) % 3 == 0 ? "◎" : "";
  35. return new Sth[]{
  36. SthUtil.createSText(text),
  37. SthUtil.createSTagOmitTrue()
  38. };
  39. }
  40. public Sth idDummy(){
  41. return SthUtil.createSIf(false);
  42. }
  43. }

■実行結果(改行や空白は実際の出力と異なります)

  1. <html>
  2. <head>
  3. <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
  4. <title>タグまとめて紹介</title>
  5. </head>
  6. <body>
  7. JavaSTH
  8. <br />
  9. <table bgcolor="blue" id="tableData">
  10. <thead>
  11. <tr>
  12. <th>no</th>
  13. <th>oddeven</th>
  14. <th>text</th>
  15. <th>button</th>
  16. <th>check</th>
  17. </tr>
  18. </thead>
  19. <tbody>
  20. <tr id="grid_0">
  21. <td id="no_0">1</td>
  22. <td id="oddeven_0">odd</td>
  23. <td><input id="txt_0" type="text" value="data1" /></td>
  24. <td><input class="s" type="button" value="押下" /></td>
  25. <td></td>
  26. </tr>
  27. <tr id="grid_1">
  28. <td id="no_1">2</td>
  29. <td id="oddeven_1">even</td>
  30. <td><input id="txt_1" type="text" value="data2" /></td>
  31. <td><input class="s" type="button" value="押下" /></td>
  32. <td></td>
  33. </tr>
  34. <tr id="grid_2">
  35. <td id="no_2">3</td>
  36. <td id="oddeven_2">odd</td>
  37. <td><input id="txt_2" type="text" value="data3" /></td>
  38. <td><input class="s" type="button" value="押下" /></td>
  39. <td></td>
  40. </tr>
  41. <tr id="grid_3">
  42. <td id="no_3">4</td>
  43. <td id="oddeven_3">even</td>
  44. <td><input id="txt_3" type="text" value="data4" /></td>
  45. <td><input class="s" type="button" value="押下" /></td>
  46. <td></td>
  47. </tr>
  48. <tr id="grid_4">
  49. <td id="no_4">5</td>
  50. <td id="oddeven_4">odd</td>
  51. <td><input id="txt_4" type="text" value="data5" /></td>
  52. <td><input class="s" type="button" value="押下" /></td>
  53. <td></td>
  54. </tr>
  55. <tr id="grid_5">
  56. <td id="no_5">6</td>
  57. <td id="oddeven_5">even</td>
  58. <td><input id="txt_5" type="text" value="data6" /></td>
  59. <td><input class="s" type="button" value="押下" /></td>
  60. <td></td>
  61. </tr>
  62. <tr id="grid_6">
  63. <td id="no_6">7</td>
  64. <td id="oddeven_6">odd</td>
  65. <td><input id="txt_6" type="text" value="data7" /></td>
  66. <td><input class="s" type="button" value="押下" /></td>
  67. <td></td>
  68. </tr>
  69. <tr id="grid_7">
  70. <td id="no_7">8</td>
  71. <td id="oddeven_7">even</td>
  72. <td><input id="txt_7" type="text" value="data8" /></td>
  73. <td><input class="s" type="button" value="押下" /></td>
  74. <td></td>
  75. </tr>
  76. <tr id="grid_8">
  77. <td id="no_8">9</td>
  78. <td id="oddeven_8">odd</td>
  79. <td><input id="txt_8" type="text" value="data9" /></td>
  80. <td><input class="s" type="button" value="押下" /></td>
  81. <td></td>
  82. </tr>
  83. <tr id="grid_9">
  84. <td id="no_9">10</td>
  85. <td id="oddeven_9">even</td>
  86. <td><input id="txt_9" type="text" value="data10" /></td>
  87. <td><input class="s" type="button" value="押下" /></td>
  88. <td></td>
  89. </tr>
  90. </tbody>
  91. </table>
  92. </body>
  93. </html>

こんな感じになります。
では説明。

まず基本はidと同じ名前のgetterを用意します。
戻り値は基本はSthになります。
Sth以外ですと、STextと同じ動きになります。

ではSthを継承している
タグにリンクして与えることが出来るコマンドの種類
STag
SIf
SFor
SInclude
SText

以上。これがJavaSTHの全て。

名前だけで大体動きが分かると思いますが。説明します。

STag
タグそのものを編集する
omit trueを与えると処理のタグが消えます。(中身は消えません)
addAttribute アトリビュートを追加する。
サンプルではtableDataと言うidをつけたやつでやってます。 bgcolorにbuleをついかしてます。

SIf
タグの中身ごと表示・非表示を制御
サンプルではdummyと言うidをつけたやつでやってます。

SFor
タグを中身ごと繰り返します。
指定するものはイテレートなオブジェクトと、ループ処理をするときに呼び出すときに呼ばれるセットするプロパティ名です。
htmlのidは一意である必要があるため、繰り返しに含まれたidは元の名前に + 「_」+ ループindexのidになります。
ネストしたforとかの場合、「元の名前 _ ループ1のindex _ ループ2のindex」と言った様に付加されていきます
サンプルではgridと言うidをつけたやつでやってます。

SInclude
サンプルでは使ってません。が読み込みたいhtmlをセットするだけです。
注意としてはincludeしたhtmlも処理対象になりますので、
includeしたidと同じ名前のidが含まれている場合、処理がループする可能性があります。
ロジックでnullを返すことによりbreakすることは出来ますが、無限ループにならないよう注意してください

SText
タグ内のテキストに文字列を出力します。 サンプルではoddevenと言うidをつけたやつでやってます。

これらはSthUtilクラスのメソッドで簡易的に作成できるようになっていますが、
独自にインスタンス化も可能です。
例)

  1. public Sth idDummy(){
  2. return new SIf(){
  3. @Override
  4. public boolean isCondition() {
  5. return false;
  6. }
  7. };
  8. }
メソッドの中で計算処理とかいろいろやってもOK。だってJavaですもの。
ただJSPと違い、アクセスできる力がある場所はそのタグに対してのみになります。
そのため、MVCモデルをより促す形になっています。

次にこのコマンドは複1つのidに数指定することが出来ます。
そのときには戻り値をSth[](配列)にします。
サンプルではmaruと言うidをつけたやつでやってます。
これは出力するSTextでテキストを処理してから、
STagのomit処理をしてタグを消します。

複数指定するときには順序が大切です。
たとえばこのmaruに処理しているのを逆にすると、
STagがomit処理をします。
するとSTextはターゲットのタグがすでになくなっているのでなにも処理しません。
処理の順番を意識しながら並べ替えてください。

これを組み合わせると面白い処理も出来ます。
SForとSIfを指定したりすると、
SForが順番に処理していく中で、
SIfでnoが奇数のときのみconditionをtrueにすると偶数のタグだけ消えたりします。
またSForの重ねがけも出来たりします。(あんまり意味ないですが。)
とにかく自由につけることが出来ます。
いろいろやってみてください。



一応このクラス群に対応した簡易的に処理するものとしてアノテーションも用意されています。
アノテーションはフィールドのみに付加することが出来ます。
アノテーションはそのフィールドの値をそのまま使うだけなどのときに利用できます。
フィールド名はidと同名である必要があります。
getterメソッドがあった場合、フィールドのアノテーションは無視されます
SthTag
SthIf
SthFor
SthInclude
SthText

上の例ではnoに対してSthTextが付加されてます。
なのでSTextと同等の動きをnoの値を使って動作します。
SIfだけは他のフィールドの値を参照することで動作するように出来ます。
SText等と重ねて指定するときに便利です。


アノテーションも重ねがけするときには並びに注意しよう。
(テストでは並び順に取得できていますが、規約では並びの通りに取れるって書いてないらしい。。)
心配な人はidメソッドで実装してネ。

Webでの連携の設定

まず、web.xmlにサーブレットを追加します。
viewRootPathにはhtmlファイルを置くルートpackageを指定します。
modelRootPathにはhtmlに対応するjavaクラスを置くルートpackageを指定します。

  1. <servlet>
  2. <servlet-name>sth</servlet-name>
  3. <servlet-class>jp.sourceforge.javasth.web.SthDefaultServlet</servlet-class>
  4. <init-param>
  5. <param-name>modelRootPath</param-name>
  6. <param-value>abc.viewmodel</param-value>
  7. </init-param>
  8. <init-param>
  9. <param-name>viewRootPath</param-name>
  10. <param-value>abc.view</param-value>
  11. </init-param>
  12. </servlet>
  13. <servlet-mapping>
  14. <servlet-name>sth</servlet-name>
  15. <url-pattern>*.html</url-pattern>
  16. </servlet-mapping>

あとは、対象のhtmlとjavaをそれぞれに配置します。
設定し終わったら、urlをたたくだけです。

urlに対応したhtmlが呼び出されます。
モデルに設定される値は

1.HttpServletRequest#getAttribute()
2.HttpServletRequest#getParameter()
3.HttpSession#getAttribute()

の優先順位でセットされます。

セットされるときには型のコンバートは今のところ処理していません。
(予定でも今のところ対応しない予定です。)
型が合わない場合はマッピングされません。

javaクラスにキーと同名のパブリックフィールドもしくはセッターがある場合、
自動的にセットされます。

キー名に「.」が含まれている場合、「.」(ドット)を「_」(アンダーバー)
に変更した、名前でマッピングが設定されます。

値が設定された後、テンプレートに対して処理の実行が行われます。


newで自分でインスタンス化するのとSthUtilを使用してタグコマンドを作る違い

SthUtilを使用すると、そのタグコマンドが取得されたときの値のみで実行されますが
new SIf(){ ... } といった形で実装した場合、
連携するタグがある場合、タグを動作させながら評価されます。
例1:

  1. new Sth[]{
  2. SthUtil.createSFor(Arrays.asList(new Integer[]{1,2,3,4,5,6}), this, "i"),
  3. SthUtil.createSIf(i%2 == 0)
  4. }

例2:
  1. new Sth[]{
  2. SthUtil.createSFor(Arrays.asList(new Integer[]{1,2,3,4,5,6}), this, "i"),
  3. new SIf(){
  4. @Override
  5. public boolean isCondition() {
  6. return i%2==0;
  7. }
  8. }
  9. }

例1の場合だと、このコマンドを取得するときのiの状態で全てIfが評価されるため、
iが0だと全てが表示されます。
例2の場合だと、Forのコマンドが実行されるたびにiを評価するため、
奇数のForの結果タグが表示されなくなります。
このようなコマンドの重ねがけのときにしか違いが出ませんが、
1つのタグに重ねてコマンドをかけるときは少しだけ意識しましょう。

キーワードは「Sth」

ユーザが使うべきクラスは基本的にSthでコード保管できるようになっています。
アノテーションで何があるか分からないときは@Sthと打ってコード保管してください。
タグで分からないときはSthと打ってSthUtilを呼び出してください。
タグを自分でインスタンスするときだけSから始まるクラスになっています。
名称を忘れたときにはSthUtil.createと打ってそのあとに続く名前がタグのクラス名となっています。

また、メソッドの戻り値は必ずSthもしくはSth[]です。
クラス名などが分からないときはSthでGOです。

コントローラのプロダクトとの連携について

JavaSTHはMVCで言う、V(ビュー)のプロダクトです。
そこでViewからその前のC(コントローラ)のプロダクトとの連携について
サンプルを紹介して行きたいと思います。

プロダクトの連携サンプルのページ




Wikiってなに

その前に、「Wikiってなに?」という方は、Wikipedia の「ウィキ」のページを参考にしてください。

文法などのドキュメントは、サイドバーに標準で入っているリンクか、SourceForge.JP プロジェクト内の Wikiガイド を参照してください。

ツール

JavaSTHのファイルを書く際に便利な、Eclipseプラグインも作りたいと思っています。

Wikiの練習ページ