なんじゃくにっき

プログラミングの話題中心。

Rhinoを使ってサーバーサイドでJavaからJavaScriptの関数を使う(3) 〜FlexでもJavaScript〜

ActionScriptからJavaScriptを呼び出すにはExternalInterfaceを使う。
 
Rhinoを使うとJavaからJavaScriptを呼び出せるので、
クライアント側がFlex、サーバー側がJavaの構成のとき、
クライアント側とサーバー側とで同じJavaScriptを用いることが出来る。
 
前回のプログラムをFlexで書き換えてみた。
 
 
まずはいくつかハマった点、気になった点などを。
 
・ExternalInterface.callがIE8でnullを返してくる(FirefoxSafariではOK)
 →2,3時間悩んだが、ググって解決。
  swfを埋めこんでいるHTMLのobjectのidはexternalという文字を含んでいないとIEでは動かない
 http://quality.ekndesign.com/archives/2006/07/externalinterfa.html
 
・AMF通信でServletContextが欲しい場合
 →BlazeDSを使っている場合はflex.messaging.FlexContext.GetServletContext
 →T2実装の場合はActionメソッドの本来の引数の後ろにServletContextを追加すると、
  T2が呼び出し時に自動でセットしてくれた。Flex側では本来の引数だけ指定すればよい。
  結果的にJava側とFlex側で引数の個数が異なっても動作する。
 
・T2の@FormのDTOとAMF通信のDTOは共用できる
 →まあ当然といえば当然か。Fieldを持っているだけのクラスだから。
  但しT2のFormがサポートする型、FlexJavaの変換でサポートされる型の考慮は必要。
 
・一つのT2Pageクラス内にAMF通信のActionメソッドと通常のPostメソッドが混在していると、
 AMFの方を呼んだつもりがPostの方が呼ばれてエラー???
 →分けた方が無難っぽい
 
 
以下、サンプルのソース


Flex Main.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="300">
<mx:RemoteObject id="remote" destination="/amf" endpoint="t2.amf" />

<mx:Script>
<![CDATA[
import flash.external.ExternalInterface;
import mx.controls.Alert;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.AsyncResponder;
import mx.rpc.AsyncToken;
import examples.dto.PostalCodeDTO;

public function onButtonClick(): void {
var arg: String = postalcodeEdit.text;
var result :Boolean = ExternalInterface.call("isValidPostalCode", arg);
if (!result) {
Alert.show("NG");
return;
}

var dto:PostalCodeDTO = new PostalCodeDTO();
dto.postalcode = postalcodeEdit.text;
dto.address = addressEdit.text;
var token:AsyncToken = remote.amf(dto);
token.addResponder(new AsyncResponder(onSuccess, onFault));
}

private function onSuccess(e:ResultEvent, object:Object = null):void {
Alert.show("OK");
}


private function onFault(e:FaultEvent, object:Object = null):void {
Alert.show(e.message.toString());
}

]]>

</mx:Script>

<mx:Canvas>
<mx:Label x="0" y="10" text="郵便番号:" textAlign="right" />
<mx:TextInput x="50" y="10" id="postalcodeEdit" width="80" maxChars="8" />
<mx:Label x="20" y="40" text="住所:" textAlign="right" />
<mx:TextInput x="50" y="40" id="addressEdit" width="300" maxChars="40" />
<mx:Button x="50" y="70" label="送信" click="onButtonClick()" />
</mx:Canvas>
</mx:Application>

 


Flexを埋め込んでいるJSP
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "">http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta http-equiv="Content-Script-Type" content="text/JavaScript" />
<script type="text/javascript" src="js/postalcodeutil.js"></script>

</head>
<body>
<object data="swf/main.swf" width="400" height="300"
type="application/x-shockwave-flash"
allowScriptAccess="always"
id="anexternal" >

<param name="movie" value="swf/main.swf" />
<param name="FlashVars" value="value" />
<param name="allowScriptAccess" value="always" />
<embed src="swf/main.swf" width="400" height="300"
allowScriptAccess="always"
type="application/x-shockwave-flash"
pluginspage="http://www.macromedia.com/go/getflashplayer" />

</object>
</body>
</html>

 


FlexDTO(Java側のDTOは前回と同じ)
package examples.dto {
[RemoteClass(alias="examples.dto.PostalCodeDTO")]
public class PostalCodeDTO {
public var postalcode :String;
public var address: String;

public function PostalCodeDTO() {}

}
}

 


Java側Pageクラス
package examples.page;

import javax.servlet.ServletContext;

import org.t2framework.commons.util.Logger;
import org.t2framework.t2.annotation.core.Amf;
import org.t2framework.t2.annotation.core.Page;
import org.t2framework.t2.format.amf.navigation.AmfResponse;
import org.t2framework.t2.spi.Navigation;

import examples.dto.PostalCodeDTO;
import examples.util.PostalCodeUtil;

@Page("/amf")
public class AmfPage {
@SuppressWarnings("unused")
private static Logger logger = Logger.getLogger(PostalCodePage.class);

@Amf
public Navigation amf(PostalCodeDTO dto, ServletContext context) throws Exception{

PostalCodeUtil util = PostalCodeUtil.getInstance();
util.setJSPath(context.getRealPath("js/postalcodeutil.js"));

Boolean result;

if (util.isValidPostalCode(dto.getPostalcode())){
result = true;
/*
* 正常時の処理をここに処理を書く
*/

} else {
result = false;
/*
* エラー時の処理をここに処理を書く
*/

}

return AmfResponse.to(result);
}
}