Javaで構築されたWebアプリのsubmit時にローディング画面を表示する

既に運用しているレガシーなシステムだとローディング画面をgifやアニメーション表示をしたいという場面がそこそこあります。もちろん案件にもよりますが。蓋を開けてみると少し遠回りして実装しないといけなかったり、ボタンを非活性として対応したり、やり方は様々かと思います。今回はJavajQueryを使ってローディング画面をどのように実装したか、以下の目次で書いていきます。

1. 前提条件

  1. jquery-cookieの導入(以下をダウンロード)
    GitHub - carhartl/jquery-cookie: No longer maintained, superseded by JS Cookie:
  2. ローディング用のgifは作成済み

2. 要件

  1. ファイルダウンロードの時はsubmit時にクライアント側で検知する
  2. クライアント側でローディング画面を表示させた後にサーバー側でcookieの値を設定してクライアント側で検知する
  3. 画面遷移がある場合はsubmitのactionに任せる
  4. ローディング画面を表示する処理は明示的に修正可能であること

3. プログラムの実装

3-1. サーバー側のJava実装

// ※クラスは省略しています
// クライアントへ返却するresponseの作成
HttpServletResponse response = ServletActionContext.getResponse();

// ダウンロード処理の前にクッキーを設定する(定数は好みでkeyとvalueを設定)
Cookie resultCookie = new Cookie(COOKIE_NAME_DOWNLOAD, COOKIE_NAME_DOWNLOAD_SUCCESS);

// cookieのパス
resultCookie.setPath("/");

// 作成したcookieをresponseに設定
response.addCookie(resultCookie);

3-2. ローダー用JavaScriptの実装

  • 作成したjsはどこかの共通処理に読み込みます
  • 読み込むgifはどこかで作成しておきます
  • cssは色々あるのでここでは割愛しています(gifは中央の背景画像として表示させる前提)
/***
 * ローディング検知用のonLoadingHandler
 * ファイルダウンロードが発生する場合はsubmit後のcookie値を監視して明示的にローディング画面を閉じる
 * @param action : submit時のform action
 */
function onLoadingHandler(action) {

  // ローディング画面の生成
  dispLoading("ローディング画面の文言");

  // ファイルダウンロード系のactionを全て判断して、cookie値からの監視を行い、ローディング画面の制御を行い
  // 該当しないactionならsubmitの動作に委譲する
  if(action === '対象のaction' ) {
    // setInterval用の変数
    var intervalId;
    // 一定時間ごとに特定の処理を繰り返す
    intervalId = setInterval(function() {
      // サーバー側から受け取ったcookie値を取得出来た場合 
      if ($.cookie('download')) {
        // ローディング画面を止める
        removeLoading();
        // intervalの処理を止める
        clearInterval(intervalId);
        // 受け取ったcookieをクリア
        $.removeCookie('download', { path: '/' });
      }
    }, 1000);
  }
}

/***
 * ローディング画面表示用のdispLoading
 * dispLoading('表示させたいメッセージ');で単独でも呼び出せる
 * @param msg : 表示させたいメッセージ
 */
function dispLoading(msg) {
  // メッセージがない場合も許容しておく
  if( msg === undefined || msg === null ){
    msg = "";
  }
  // 画面表示メッセージ用DOM生成
  var dispMsg = "<div class='loadingMsg'>" + msg + "</div>";

  // ローディング画像が表示されていない場合のみ出力する
  if($("#loading").length === 0){
    $("body").append("<div id='loading'>" + dispMsg + "</div>");
    // Webブラウザのキャッシュ対策でgifにパラメータを付与して表示させる
    var timestamp = new Date().getTime();
    var filePath = "../css/images/loader.gif?" + timestamp; // ファイルのパスは環境に合わせて
    // 対象の要素にcss付与(gifはセンター寄せ)
    $('#loading .loadingMsg').css('background', 'url("' + filePath + '") center center no-repeat');
  }
}

/***
 * ローディング画面停止用のremoveLoading
 */
function removeLoading(){
  $("#loading").remove();
}

3-3. ローダー用JavaScriptの呼び方

// 画面遷移する場合
function fileNoneLoaded() {
  $("#form").attr("action", "対象のactionパス");
  $("#form").submit();
  // actionを空文字で渡す
  onLoadingHandler('');
}

// ファイルのダウンロードの場合
function fileDownLoaded() {
  $("#form").attr("action", "対象のactionパス");
  $("#form").submit();
  // action名にfileExportを渡す、onLoadingHandlerで検知出来るように対象actionは記述しておく
  onLoadingHandler('fileExport');
}

4. まとめ

このようにサーバー側でcookie値を設定してクライアントで検知することで、ローディングの可否について判定させることが出来ます。html部分もjavaScriptで生成しているので、画面全体にwrap出来るように工夫する事で画面全体を覆う事が可能なのでhtmlも不要です。「4. ローディング画面を表示する処理は明示的に修正可能であること」の通り、必ずしも画面遷移毎にローディング画面を表示させるわけではないという点には気を使いました。

5. あとがき

使用しているブラウザが特殊なブラウジングアプリ(DoCANブラウザなど)だと、CSSJavaScriptがうまく効かないという現象があるためお気をつけ下さい。