オレオレAjaxアノテーションで超簡単Ajax
チュートリアルのダウンロードのソース見てたら「あれ?これパクれば Ajax できるんじゃね?」と思ってさっそくやってみた。クラス名とか気にしないで・・・。
すぱいだー日記さんにインスピレーションを受けて
SAStrutsで自前AjaxアノテーションとAOPを使って
超簡単にAjaxできてしまうプログラムを書いてみた。
Action側のコードはこんな感じ。
public class AjaxTestAction { public String hoge; public String fuga; @Ajax @Execute(validator = false) public String callAjax() { return hoge + " と " + fuga; } }
通常のSAStrutsの実行メソッドに
自前で作った@Ajaxアノテーションを付けるだけ。
呼び出し側のJSPは以下のとおり。
<script src="../js/prototype.js"></script> <script> function ajaxTest() { var url = '/sa-struts-tutorial/ajaxTest/callAjax'; var queryString = 'hoge=ほげ&fuga=ふが'; var myAjax = new Ajax.Request( url, { method: 'post', parameters: queryString, onComplete: showResponse } ); } function showResponse(request) { alert(request.responseText); } </script> <input type="button" onclick="ajaxTest()">
振る舞いとしては、ボタンが押されたらAjaxTestActionクラスに
hogeパラメータとfugaパラメータを渡してcallAjaxメソッドを呼び出し、
戻り値をJavaScriptのalert関数で表示する感じ。
hogeパラメータに「ほげ」、fugaパラメータに「ふが」という値を
セットしたクエリーストリング(queryString )を作成して
Ajax.Requestに渡している。
呼び出すURLは'/sa-struts-tutorial/ajaxTest/callAjax'なので、
sa-struts-tutorialアプリのAjaxTestActionクラスのcallAjaxメソッドとなる。
オレオレAjaxの仕込み方
どのような仕込みをしたのかについて説明する。
オリジナルで作ったAjaxInterceptorは@Ajaxアノテーションが実行メソッドにあれば、
String型の戻り値が画面遷移先ではなく、レスポンスとして扱うようになる仕組み。
以下、順を追って説明。
Step1. オリジナルのAjaxアノテーションを作成する
Step2. インターセプターを作成する
Step3. diconファイルにインターセプターの設定を施す
Step1. オリジナルのAjaxアノテーションを作成する
package tutorial.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Ajax { String encode () default "UTF-8"; String contentType() default "text/plain"; }
Step2. インターセプターを作成する
AjaxInterceptor.java
package tutorial.interceptor; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import javax.servlet.http.HttpServletResponse; import org.aopalliance.intercept.MethodInvocation; import org.seasar.framework.aop.interceptors.AbstractInterceptor; import org.seasar.framework.container.SingletonS2Container; import tutorial.annotation.Ajax; public class AjaxInterceptor extends AbstractInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable { Ajax ajax = invocation.getMethod().getAnnotation(Ajax.class); if (ajax == null) { return invocation.proceed(); } Object ret = invocation.proceed(); printOut(ret.toString(), ajax.contentType(), ajax.encode()); return null; } protected void printOut(String value, String contentType, String encode) { HttpServletResponse response = SingletonS2Container.getComponent(HttpServletResponse.class); response.setContentType(contentType + "; charset=" + encode); PrintWriter out = null; try { out = new PrintWriter(new OutputStreamWriter(response.getOutputStream(), encode)); out.print(value); } catch (IOException e) { e.printStackTrace(); } finally { if (out != null) { out.close(); } } } }
SMARTデプロイの規約によりルートパッケージ直下のinterceptorパッケージにInterceptorという名前で終わるクラス名にしておけば、このクラスは自動的にS2コンテナに登録される。SMARTデプロイの規約により"ajaxInterceptor"というコンポーネント名でS2コンテナから取り出すことができる。
AjaxInterceptorは呼び出されたメソッドに@Ajaxアノテーションがあるかどうかをチェックして、あればメソッドの戻り値を画面遷移としでではなく、レスポンスの値として処理する。
Step3. diconファイルにインターセプターの設定を施す
customizer.dicon
…中略… <component name="actionCustomizer" class="org.seasar.framework.container.customizer.CustomizerChain"> <initMethod name="addAspectCustomizer"> <arg>"aop.traceInterceptor"</arg> </initMethod> <initMethod name="addAspectCustomizer"> <arg>"actionMessagesThrowsInterceptor"</arg> </initMethod> <initMethod name="addCustomizer"> <arg> <component class="org.seasar.framework.container.customizer.TxAttributeCustomizer"/> </arg> </initMethod> <initMethod name="addCustomizer"> <arg> <component class="org.seasar.struts.customizer.ActionCustomizer"/> </arg> </initMethod> <!-- 追加したAjaxInterceptor用の設定はここから --> <initMethod name="addAspectCustomizer"> <arg>"ajaxInterceptor"</arg> </initMethod> <!-- 追加したAjaxInterceptor用の設定はここまで --> </component> …中略…
actionCustomizerに作成したAjaxInterceptorを関連付ける。こうすることでActionクラスの全publicメソッドが呼ばれるたびに、AjaxInterceptorが呼ばれることになる。
以上。