jQueryの非同期通信関数$.ajaxを使用して、サーバ側でのファイルの作成とダウンロードを行う
やりたいことは、左図のようなこと。クライアントからリクエストを送り、サーバ側でダウンロードするファイルを作成(すでにある場合は加工)してクライアントへ返す(ダウンロード)といったこと。
同期通信の場合、クライアントからsubmitボタンを使用して、サーバ側の処理を呼び出し、ダウンロードするファイルをレスポンスデータとしてクライアントへ返すといった、いわゆる普通のダウンロード処理を実装すればよい。ただし、同期通信の場合、レスポンスが返却されるまで、クライアント側の処理が止まってしまう。それを回避すべく、非同期通信でファイルダウンロードを実施しようと考えた。
そこで、jQueryの$.ajax関数を使用して非同期通信によってサーバ側の処理を呼び出してやれば、クライアント側の処理は非同期で継続させられると考えた。しかし、それでは、サーバからクライアントへレスポンスが返却されても、ブラウザがダウンロード用のダイアログを表示してくれなかった。
W3Cのサイトを参照すると、xmlHttpRequestのレスポンスは、テキストベースのレスポンス(responseText)か、XMLベースのDOMオブジェクトでのレスポンス(responseXML)の2つである。そのため、エクセルやパワーポイントファイルダウンロードのレスポンスをハンドリングできない。
そこで、ファイルの作成・加工は非同期通信のリクエストでファイルの作成・加工を行うservletを呼び出し、ダウンロードは非同期通信のコールバック関数の中でダウンロード処理を行うservletを呼び出すようにした。
クライアント側では、非同期通信のコールバック関数で、window.location = "ダウンロード用servletのURL"として、ダウンロードを実行している。
//ファイルダウンロード $('#downloadFile').click(function() { var _urlForCreatingSheet = "http://localhost:8080/cookie/createLedgerSheet"; var _urlForDownload = "http://localhost:8080/cookie/downloadFile"; $.ajax({ url : _urlForCreatingSheet, async : true, cache : false, success : function(data, dataType) { //ダウンロードのためlocationにダウンロード用コントローラのservletに対応するURLを設定する window.location = _urlForDownload; } }); alert("asynchronous"); });
サーバ側のダウンロード用servletのダウンロード部分は、こんな感じ。
protected void printOutFile(HttpServletRequest req, HttpServletResponse res, File fileOut) throws ServletException, IOException { OutputStream os = res.getOutputStream(); String filePath = "sample.xls"; try { FileInputStream hFile = new FileInputStream(filePath); BufferedInputStream bis = new BufferedInputStream(hFile); // レスポンス設定 res.setContentType("application/octet-stream"); res.setHeader("Content-Disposition", "attachment; filename=\"" + fileOut.getName() + "\""); int len = 0; byte[] buffer = new byte[1024]; while ((len = bis.read(buffer)) >= 0) { os.write(buffer, 0, len); } bis.close(); } catch (IOException e) { printOutNotFound(res); } finally { if (os != null) { try { os.close(); } catch (IOException e) { } finally { os = null; } } } }
こんなやり方しかないのかな。