ダウンロード終了時の判定

ダウンロード開始時に画面の操作をできないようにし、ダウンロード終了後に画面操作できるようにするのに、いいアイデアをみつけた。

http://geekswithblogs.net/GruffCode/archive/2010/10/28/detecting-the-file-download-dialog-in-the-browser.aspx

処理のフローとしては、
1.画面を操作できないようにする。
2.クライアントjsで、トークンを生成する。
3.クライアントjsで、一定時間ごとに、「1.」のトークンがクッキーに入っているか確認する処理を実行。
4.「2.」のトークンをサーバーに送信する。
5.サーバーで、受信したトークンをクッキーに設定する。
6.サーバーで、ダウンロード処理を開始する。
7.「2.」の処理が「4.」でサーバーから設定されたトークンを発見する。
8.画面を操作できるようにする。

処理内容はなんてことないけど、思いつかなかった。すばらしい。

元記事をちょっと変更してjavaで実装してみた。
変更点

  • トークンはcookieで送信する。
  • エラーが発生した場合に備えてトークンを確認する回数を制限する。


クライアント javascript

var Demo = {};

/**
 * ダウンロード終了管理
 * トークンをクッキーにつけて送信し、
 * レスポンスの受信クッキーで終了を判定する。
 * @constructor
 */
Demo.downloadManager = function() {
    this.fileDownloadCheckTimer = undefined;
    this.tokenName = Demo.downloadManager.cookieToken;
    this.successTokenName = Demo.downloadManager.cookieSuccessToken;
    this.maxLoopCount = 10;
    this.loopCount = 0;
};
/** 送信トークン名(サーバーで受信)*/
Demo.downloadManager.cookieToken = 'download-token';
/** 受信トークン名(サーバーから送信)*/
Demo.downloadManager.cookieSuccessToken = 'download-success-token';
/** 画面フリーズ */
Demo.downloadManager.prototype.blockUIForDownload = function() {
	Demo.blockUI(); // 画面を操作できないようにする。
    this.loopCount = 0;
    var token = new Date().getTime();
    // 現在時刻でトークンを生成
    Demo.setCookie(this.tokenName, token, '/');
    Demo.setCookie(this.successTokenName, 'START', '/');
    var self = this;
    this.fileDownloadCheckTimer = window.setInterval(function() {
        // 一定時間ごとにクッキーの値を確認しダウンロードが終わったか判定
        var cookieValue = Demo.getCookie(self.successTokenName);
        //console.log(self.loopCount + ':' + cookieValue);
        if (cookieValue == token) {
            self.finishDownload();
        }
        self.loopCount++;
        if (self.loopCount > self.maxLoopCount) {
            self.finishDownload();
        }
    }, 1000);
};
/** 画面フリーズ解除 */
Demo.downloadManager.prototype.finishDownload = function() {
    // ダウンロードが終わった後に後始末を行う
    window.clearInterval(this.fileDownloadCheckTimer);
    Demo.setCookie(this.tokenName, 'END', '/');
    Demo.setCookie(this.successTokenName, 'END', '/');
	
    Demo.unBlockUI(); // 画面を操作できるようにする。
};
Demo.setCookie = function(name, value, path) {
	// クッキー設定処理
};
Demo.getCookie =  function(name) {
	// クッキー返却処理
};
Demo.blockUI = function(){
	// 画面操作を抑制する処理
};
Demo.unBlockUI = function(){
	// 画面操作抑制を解除する処理
};


HTML

<input type="button" value="test" onclick="new Demo.downloadManager().blockUIForDownload()" />

Server処理 java

    public static final String COOKIE_NAME_DOWNLOAD_TOKEN = "download-token";
    public static final String COOKIE_NAME_DOWNLOAD_SUCCESS_TOKEN = "download-success-token";

    …
       // ダウンロード処理の前にクッキーを設定する
        String downloadToken = "";
        for (Cookie c : request.getCookies()) {
            if (c.getName().equals(COOKIE_NAME_DOWNLOAD_TOKEN)) {
                downloadToken = c.getValue();
            }
        }
        log.debug("Download Token:" + downloadToken);

        Cookie resultCookie = new Cookie(COOKIE_NAME_DOWNLOAD_SUCCESS_TOKEN,
                downloadToken);
        resultCookie.setPath("/");
        response.addCookie(resultCookie);
        // ダウンロード処理