Explicitly mapping ActionScript and Java objectsを眺めていたら Java の java.lang.Byte[] と ActionScript の flash.utils.ByteArray で型の対応関係つけてますよ、とのこと。Flex-Java のファイルアップロード・ダウンロードってこれでやるのかな? と思ったのでちょっと実験してみた。
とりあえずソースコード。
Java 側はこんな感じ。
public class FileDto { public String fileName; public Byte[]fileContents; }
public class FileService { public FileDto download() throws Exception { File dlFile = new File("bg_h1.jpg"); byte[] buf = new byte[(int) dlFile.length()]; InputStream in = null; try { in = new BufferedInputStream(new FileInputStream(dlFile)); in.read(buf); //例外はチョンボして全スルー } finally { if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } FileDto fileDto = new FileDto(); fileDto.fileName = dlFile.getName(); fileDto.fileContents = org.apache.commons.lang.ArrayUtils.toObject(buf); return fileDto; } public void upload(FileDto fileDto) throws Exception { System.out.println("upload file name:"+fileDto.fileName+ " size:" +fileDto.fileContents.length); File upFile = new File("upload/"+fileDto.fileName); byte[] buf = org.apache.commons.lang.ArrayUtils.toPrimitive(fileDto.fileContents); OutputStream out = null; try { out = new BufferedOutputStream(new FileOutputStream(upFile)); out.write(buf); } finally { out.close(); } } }
Flex 側はこんな感じ。
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"> <mx:Script> <![CDATA[ import mx.core.ByteArrayAsset; import mx.rpc.events.FaultEvent; import dto.FileDto; [Embed(source='bg_h1.jpg', mimeType="application/octet-stream")] private var Image0 : Class; private function downloadResultHandler():void { var fileDto:FileDto = fileSrv.download.lastResult; fileName.text = fileDto.fileName; var loader:Loader = new Loader(); loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function (event: Event): void { fileImage.data = loader.content; }); loader.loadBytes(fileDto.fileContents); trace(fileDto.fileContents.length); } private function uploadResultHandler():void { trace("upload result"); } private function downloadButtonHandler():void { fileSrv.download(); } private function uploadButtonHandler():void { trace("uploadButtonHandler"); var storyByteArray:ByteArrayAsset = ByteArrayAsset(new Image0()); var fileDto:FileDto = new FileDto(); trace(Image0.toString()); fileDto.fileName = "bg_h1.jpg"; fileDto.fileContents = storyByteArray; fileSrv.upload(fileDto); } private function downloadImageClearButtonHandler():void { fileImage.data = null; } private function faultHandler(event:FaultEvent):void { trace("faultHandler"); errorText.text = event.fault.toString(); } ]]> </mx:Script> <mx:RemoteObject id="fileSrv" destination="fileService" > <mx:method name="download" result="downloadResultHandler()" fault="faultHandler(event)"/> <mx:method name="upload" result="uploadResultHandler()" fault="faultHandler(event)"/> </mx:RemoteObject> <mx:HBox width="100%"> <mx:Button id="downloadButton" label="download" click="downloadButtonHandler()"/> <mx:Button id="imageClear" label="download image clear" click="downloadImageClearButtonHandler()"/> <mx:Button id="uploadButton" label="upload" click="uploadButtonHandler()"/> </mx:HBox> <mx:VBox width="100%"> <mx:Text id="fileName" text="てすと" width="100%" height="100%" fontSize="21" fontWeight="bold"/> <mx:Image id="fileImage" alpha="1.0"/> </mx:VBox> <mx:TextArea id="errorText" width="496" height="82"/> </mx:Application>
さて。突っ込みどころ多々なので、理解してる範囲でひとつずつ整理。
型マッピング
Java で Byte[]をプリミティブの byte[]にするためにワザワザ型変換を行っている。が、FileDto の Byte[]は byte[]にしても動作する。Byte[]じゃないと動作してくんないと思ったけど RemoteObject コンポーネントの使用 を見ると、Java と AS3 のマッピングは byte[] と ByteArray になってるんだよねぇ。ラッパークラスとプリミティブ型、どっちでも動作する、ってことなのかな?(まともにドキュメント読んでないのでどっかに書いてるあるかも) まぁ、ありがたいといえばありがたい。
サービスクラスの位置?
下記のようなコードを FileService#upload などのサービスメソッドで実行すると何が表示されるのかな? と思ってやってみた。
File f = new File(""); System.out.println(f.getAbsolutePath());
コンテキストルートかなーと思いきや TOMCAT_HOME のディレクトリ名が表示された。ちと予想外……。なんでココなんだろ?
Flex でフツウのファイルダウンロードとアップロード
画像表示は Image#load() とか。フツーは flash.net.URLRequest とか flash.net.FileReference とかあるわけで。
で、思ったこと。サンプルコードで実験したようなやり方って妥当なのかな? という点。たとえば、アップロードの場合ローカルファイルを ByteArray に入れるんだけど、これってメモリ消費がバカにならない可能性があるわけで……
このコード、厳密にはアップロードしてるって言えなくない?
Yes. 手抜きのため swf に埋め込んだ画像ファイルをサーバに送り返してるだけですw
というのは建前で、ホントーは Flash Player からだと簡単にローカルファイル見えないみたいなんだよね。色々調べてみると AIR ではこんな感じ でやれるし FlashPlayer10からローカルアクセスできます! って情報が。セキュリティ的にアレなので見えないようにしてたんかねぇ。
なので、今のところ Flex 使った開発でローカルリソースにバシバシアクセスしたい場合は AIR 使ったほうがよさそうですな。