presentation層はGroovy
Groovyはpresentation層で活躍させよう、と思う。
- FrontControllerとしてGroovyServlet
- scriptがDicontainerに管理されるサービスを実行
- scriptはTemplateServletにディスパッチ
- HTMLが生成される
TemplateServlet
GroovyにTemplateServletというものがあることを発見。JSPに似た構文を使えるらしい。
- JSPみたいに<% %>や<%= %>が使える。${}もつかえる。
- 暗黙変数もjspと同じ。Defaultのものを使うならinit-paramでtrueを指定する。暗黙変数はTemplateServletを継承すればカスタマイズ可能。
- 入力画面からのパラメータ(Request Parameter)はrequestから取り出さなくても次画面でそのまま使用できる。web.xmlのinit-paramでtrueを指定する必要あり。
- Groovyなので型を意識する必要なし。<% %>のなかでも${}でもパス構造?(request.class.methods.nameみたいな)でアクセスできる。
- GroovyServletよりこっちのほうが使いやすそう。
今わかってるのはこれくらい。
web.xml
Template groovy.servlet.TemplateServlet bindDefaultVariables true bindRequestParameters true Template *.template
カスタムタグみたいのはあるのか(これから出来るのか)なぁ?
setContentType
GroovyServletもTemplateServletもHttpServletRequest#getWriter()のあとでsetContentType()しちゃってる。setContentType()してからgetWriter()しないと。
groovy.servlet.GroovyServletの拡張
ソースはとても短いので継承するにしても別個に同等のものつくるにしても簡単。
GroovyServletでは「request」「response」「application」「session」「out」の変数がGroovletで暗黙的に使用できるように定義されている。outの変数を定義する前にServletResponse#setContentType()をしとけば日本語が表示可能。
暗黙変数作るのも簡単なのでS2Containerもたとえば「container」とかで定義できちゃう。
暗黙変数を定義して使うのっていうのはGroovletじゃなくても使えそう。これは面白い。
import groovy.xml.MarkupBuilder html = new MarkupBuilder(out).html() { head() { title("日本語つかえます") } p("宣言しなくてもcontainerの変数使えます") body() { table(border:1) { tr() { td("戻り値"); td("メソッド名"); td("引数の型") } for (m in container.class.methods) { tr() { td(m.returnType.name); td(m.name); td(m.parameterTypes.name) } } } } }
GroovletとMarkupBuilder
Groovletを動かしてみる。なんとなく使ってみたくなった。
Groovy - Java用スクリプト言語の例ではHTML自体が文字列でその中に変数埋め込んでいるけど、条件分岐やループを使ってページを生成するにはMarkupBuilderを使うことになると思う。生きてまをみてMarkupBuilderのコンストラクタにWriterを渡せることに気づいたので暗黙変数のoutをわたす。
import groovy.xml.MarkupBuilder map = [1:"one",2:"two",3:"three"] html = new MarkupBuilder(out).html() { head() { title("Groovlet and MarkupBuilder") } body() { p("Number Mapping Display") table(border:1) { for (e in map) { tr() { td(e.key); td(e.value) //;を使って横に書く } } } } }
結果
Number Mapping Display
1 | one |
2 | two |
3 | three |
- 感想など
- 設定はweb.xmlを編集するだけなのですぐ使える。
- 日本語を表示したかったけどどうするのだろう?HttpServletResponse#setContentType()つかえないし。
- eachとかtimesをつかったループが使えなかった。for文は問題ない。
- タグのBodyと属性の両方指定することはできない?
ひとつのタグで1行じゃなきゃいけないのか?td()など横にいくつも書けたらいいのに。でないと見にくい。横に書ける。;が使える忘れてた。- 使い勝手はいまいち?
「Groovlet」でぐぐってみると日本語のページは3件だけ。自分の日記もふくまれちゃってる。
S2GroovyBuilderでClosureを使う
adviceにClosureを渡せるところがすてきだと思う。
こんなことをしてみた。
CalcClient
package taedium.study; import org.seasar.framework.container.S2Container; import org.seasar.framework.container.factory.S2ContainerFactory; import test.org.seasar.extension.openamf.Calculator; public class CalcClient { private static final String PATH = "taedium/study/CalcClient.groovy"; public static void main(String[] args) { S2Container container = S2ContainerFactory.create(PATH); Calculator calc = (Calculator) container.getComponent(Calculator.class); int answer = calc.plus(10,20); System.out.println(answer); } }
クラスに属さないメソッドの定義(defを使ったもの)の中からはそのスコープの外で定義された変数を参照できないのでメソッドからDEBUGやTRACEを参照するためにクラスをつくる。
CalcClient.groovy
import org.seasar.framework.aop.interceptors.* import org.seasar.groovy.* import test.org.seasar.extension.openamf.CalculatorImpl // Container new SeasarBuilder().components(){ ad = new Advices(); // 下で定義したclass include("j2ee.dicon") component(class: TraceInterceptor, name: "trace") component(class: CalculatorImpl){ aspect(advice: "j2ee.requiredTx") aspect(advice: ad.trace()) aspect(advice: ad.intercept()) } } class Advices { TRACE = true DEBUG = true /* DefaultのClosure、interceptされてるmethodを実行するだけ */ invocation = { return it.proceed() } /* * TRACEがtrueならばTraceInterceptorのComponent登録名(String)を返す * TRACEがfalseならばDefaultのClosureを返す */ Object trace() { if (TRACE) { return "trace" } return invocation } /* * DEBUGがtrueならば任意のClosureを返す * DEBUGがfalseならばDefaultのClosureを返す */ Object intercept() { if (DEBUG) { return { return 9999999 } } return invocation } }
実行結果(TRACEもDEBUGもtrueの場合)
BEGIN est.org.seasar.extension.openamf.CalculatorImpl#plus(10, 20) END est.org.seasar.extension.openamf.CalculatorImpl#plus(10, 20) : 9999999 9999999
実行結果(TRACEもDEBUGもfalseの場合)
30
ひさびさにSeasarさわった。
diconからgroovyをincludeできることとその逆ができることを確認。適材適所で使い分けができますね。
Quick and Easy Object Persistence: pBeans + Groovy Beans
TheServerSideのNews Forum。肯定的なコメントが少ないよう…。