kagamihogeの日記

kagamihogeの日記です。

Flex 勉強に S2BlazeDS でファイルアップロード・ダウンロード

Explicitly mapping ActionScript and Java objectsを眺めていたら Javajava.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 で ByteArray を Image に表示させる

はてなダイアリー

何気に悩んだ箇所なのでメモ。

中々情報が少なくて困りました;

はてなダイアリー より抜粋

おかげで非常に助かりましたw

Flex でフツウのファイルダウンロードとアップロード

画像表示は Image#load() とか。フツーは flash.net.URLRequest とか flash.net.FileReference とかあるわけで。

で、思ったこと。サンプルコードで実験したようなやり方って妥当なのかな? という点。たとえば、アップロードの場合ローカルファイルを ByteArray に入れるんだけど、これってメモリ消費がバカにならない可能性があるわけで……

このコード、厳密にはアップロードしてるって言えなくない?

Yes. 手抜きのため swf に埋め込んだ画像ファイルをサーバに送り返してるだけですw

というのは建前で、ホントーは Flash Player からだと簡単にローカルファイル見えないみたいなんだよね。色々調べてみると AIR ではこんな感じ でやれるし FlashPlayer10からローカルアクセスできます! って情報が。セキュリティ的にアレなので見えないようにしてたんかねぇ。

なので、今のところ Flex 使った開発でローカルリソースにバシバシアクセスしたい場合は AIR 使ったほうがよさそうですな。