方々を調べていると S2BlazeDS を使用していてもファイルのアップロード・ダウンロードはフツーに Servlet 作ってやったほうが良いというか、それしか方法がない気がする。なので Flex で Servlet からファイルダウンロードするやり方についてのメモ。
そういえば Adobe AIR と Flash Player 10 ではローカルファイル見れるようになったんで別かもしれないねぇ。
ちなみにアップロードは こっち
とりあえず、OutputStream にデータを書き込むという例のアレ的な処理をする Servlet をこさえる。
public class CsvDownloadServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest reqest, HttpServletResponse response) throws ServletException, IOException { OutputStream out = null; response.setContentType("application/octet-stream"); response.setHeader("Content-Disposition", "filename=\"downdloadcsv.csv\""); try { out = response.getOutputStream(); out.write('a'); } finally { out.close(); } } }
S2BlazeDS 使ってると忘れてしまいそうな Servlet のマッピングを web.xml に記述する。
<servlet> <servlet-name>csvdownload</servlet-name> <servlet-class>{パッケージ名省略}CsvDownloadServlet</servlet-class> </servlet> .... <servlet-mapping> <servlet-name>csvdownload</servlet-name> <url-pattern>/csvdownload</url-pattern> </servlet-mapping>
とりあえずこの段階で、ブラウザのアドレスに http://{servername}:{serverport}/{contextroot}/csvdownload で、ファイルダウンロードができれば Servlet 側は準備おーけー。
次は Flex 側。
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> <mx:Script> <![CDATA[ private var fileReference:FileReference = new FileReference(); private function download():void { var req:URLRequest = new URLRequest("../csvdownload"); fileReference.download(req, "downdload.csv"); } ]]> </mx:Script> <mx:Button click="download()"/> </mx:Application>
こちら側はいくつかポイントがある。
まず、URLRequest のコンストラクタに指定する URL は絶対パスも相対パスも使える。自分の環境では swf ファイルを http://{servername}:{serverport}/{contextroot}/flex/main.swf に置いているので、http://{servername}:{serverport}/{contextroot}/csvdownload には ../csvdownload でアクセスできる。
そして FileReference のインスタンスを作って download メソッドを呼べばファイル保存のダイアログを開くことができる。
ここで気をつけなければいけないのは、FileReference のインスタンスは関数のローカル変数にしてはいけない。ローカル変数にすると、ファイル保存のダイアログは出て、OK を押してもファイルを保存することができない、というか保存されない。
この原因は FileReferenceはローカル変数で使えない | _level0 | Kayac Front End Engineer's Blog に書かれてるように、fileReference.download を押したあと関数はすぐ抜けてしまうので、fileReference の参照が消えてしまうことにあるようだ。非同期実行の落とし穴ですね……