web-dev-qa-db-ja.com

セッションの有効期限が切れると、クライアント側でアクションを自動的に実行します

セッションの有効期限が切れたことを<p:growl>に表示したい。 JSF/PrimeFaces ajaxリクエストでのセッションタイムアウトとViewExpiredException処理 のように、セッションの有効期限を処理する多くのメソッドを見つけましたが、facesメッセージを<p:growl>にプッシュできませんでした。

要するに、サーバー側でHTTPセッションが自動的に期限切れになったときに、クライアント側で(JavaScript)コードを自動的に実行するにはどうすればよいですか?

10
user2354035

PrimeFaces アイドルモニター を使用できます。セッションを無効にするために、タイムアウト後にユーザーはログアウトアクションにリダイレクトされます。ユーザーに警告するカウントダウンダイアログが表示される2分前。マウスをもう一度動かした後、セッションが延長されます。

PrimeFacesアイドルモニターおよび ダイアログ は、関連するすべてのページに追加できるテンプレートに配置されます。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:h="http://Java.Sun.com/jsf/html"
   xmlns:ui="http://Java.Sun.com/jsf/facelets"
   xmlns:p="http://primefaces.org/ui">

<ui:composition>
   <h:form prependId="false">
      <p:idleMonitor
     timeout="#{session.maxInactiveInterval * 1000 - 125000}"
     onidle="startIdleMonitor()"
     onactive="timeoutDialog.hide()" />

      <p:dialog id="timeoutSession"
     header="#{msg['session.expire']}"
     widgetVar="timeoutDialog"
     showEffect="fade" hideEffect="fade"
     modal="true"
     width="400"
     height="110"
     closable="false"
     draggable="false"
     resizable="false"
     appendToBody="true"
     onHide="stopCount()"
     onShow="doTimer()">
     <br />
     <p>
        <span class="ui-icon ui-icon-alert" style="float: left; margin: 8px 8px 0;"/>
        <p:panel>
           #{msg['logoff.soon.1']}
           <span id="dialog-countdown" style="font-weight: bold"></span>
           #{msg['logoff.soon.2']}
        </p:panel>
     </p>
     <br />
     <p style="font-weight: bold;">#{msg['move.cursor']}</p>
      </p:dialog>
      <p:remoteCommand name="keepAlive" actionListener="#{auth.keepSessionAlive}" />
   </h:form>
   <script type="text/javascript">
      var TIME = 120; // in seconds
      var countTimer = TIME;
      var processTimer;
      var timer_is_on = 0;
      var redirectPage = "#{request.contextPath}/auth/j_verinice_timeout";

      var countDownDiv = "dialog-countdown";
      var txtCountDown = null;
      if (!txtCountDown)
        txtCountDown = document.getElementById(countDownDiv);

      function startIdleMonitor() {
        countTimer = TIME;
        txtCountDown.innerHTML = countTimer;
        timeoutDialog.show();
      }
      function timedCount() {
        txtCountDown.innerHTML = countTimer;
        if (countTimer == 0) {
            stopCount();
            window.location.href = redirectPage;
            return;
        }
        countTimer = countTimer - 1;
        processTimer = setTimeout("timedCount()", 1000);
      }
      function doTimer() {
        if (!timer_is_on) {
            timer_is_on = 1;
            timedCount();
        }
      }
      function stopCount() {
        clearTimeout(processTimer);
        timer_is_on = 0;
        keepAlive();
      }
      </script>
</ui:composition>
</html>
  • 11行目:アイドル状態のモニターのタイムアウトは、システム変数session.maxInactiveIntervalによって設定されます。 web.xmlまたはサーバー構成で設定した値。
  • 12/13行目:JavascriptメソッドstartIdleMonitor()は、タイムアウト後にユーザーの操作なしで呼び出されます。このメソッドはダイアログを開きます。 timeoutDialog.hide()は、ユーザーが再びビジー状態になると呼び出されます:ダイアログが閉じられます
  • 26/27行目:ダイアログが表示または非表示になると、さらに2つのJavascriptメソッドが呼び出されます:doTimer()が開始し、 stopCount()はカウントダウンを停止します。
  • 40行目:セッションを存続させるためのPrimeFacesリモートコマンド。サーバー上の任意のメソッドを呼び出すことにより、セッションが拡張されます。コマンドは、78行目のJavascriptメソッドkeepAlive()によって呼び出されます。
  • 59-68行目:JavascriptメソッドtimedCount()が毎秒呼び出され、カウントダウンが実行されます。タイムアウト後、63行目でリダイレクトが実行されます。

複数のページでタイムアウト処理をアクティブにするには、レイアウトテンプレートにタイムアウトテンプレートを含めます。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:h="http://Java.Sun.com/jsf/html"
  xmlns:ui="http://Java.Sun.com/jsf/facelets"
  xml:lang="de-DE">
<h:head>
  ...
</h:head>
<body>
  <ui:include src="/template/sessionTimeOut.xhtml" />
  <ui:include src="/nav.xhtml"/>>
  <ui:insert name="content">Default content</ui:insert>
  <ui:include src="/footer.xhtml"/>>
</body>
</html>

Web.xmlで設定できるWebアプリケーションの特定のタイムアウト:

<!--?xml version="1.0" encoding="UTF-8"?-->
<web-app>
   ...
   <session-config>
      <!-- Session idle timeout in min. -->
      <session-timeout>30</session-timeout>
    </session-config>
</web-app>

このソリューションの詳細については、このブログ投稿を参照してください: JSFおよびPrimeFaces:セッションタイムアウト処理

JSF 2.3を使用している場合は、スコープが設定されたセッションを使用できます <f:websocket> これには。サーバー側でセッションが期限切れになると、<f:websocket>close code 1000( "normalclosure") で自動的に閉じられます。

言い換えれば、次のことを実行してください。

<f:websocket ... scope="session" onclose="sessionScopedSocketCloseListener" />
function sessionScopedSocketCloseListener(code) {
    if (code == 1000) {
        alert("Session has expired!");
    }
}

必要に応じて、これを<p:growl>のJavaScriptAPIと組み合わせることができます。

<p:growl widgetVar="growl" ... />
PF("growl").renderMessage({severity: "warn", summary: "Session has expired!" });

まだJSF2.3を使用していない場合は、いつでも <o:socket> を使用できます。これは、<f:websocket>とまったく同じonclose機能を提供します。参照 サーバーはJSFによって作成されたHTMLページに非同期変更をプッシュする方法は?

8
BalusC

@uı6ʎɹnɯlǝıuɐpによって投稿されたコードは非常に便利ですが、いくつかの所見を追加します。

  • @ Jonathan LprocessTimer = setTimeout("timedCount()", 1000)setInterval("timedCount()", 1000)に置き換えます。私は理にかなっていると思いますが、いくつかの変更が必要です:

    _function doTimer() {
        if (!timer_is_on) {
            timer_is_on = 1;
            processTimer = setInterval("timedCount()", 1000);
        }
    }
    
    function stopCount() {
        clearInterval(processTimer);
        timer_is_on = 0;
        keepAlive();
    }
    _

  • メソッドtimedCount()は次のように変更できます。

    _function timedCount() {
        txtCountDown.innerHTML = countTimer;
        if (countTimer > 0) {
            countTimer = countTimer - 1;
        } else {
            clearInterval(processTimer);
            doLogout();
        }
    }
    _

    そして、keepAlive remoteCommandの下に次のようなものを追加する必要があります。

    _<p:remoteCommand name="doLogout" action="#{loginMB.logout()}" 
                     process="@this" partialSubmit="true" immediate="true" />
    _

    マネージドBeanの内部:

    _public void logout() {
        FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
        validUser = false;
        loggedUser = false;
        redirectToPage("/login.xhtml");
    }
    
    private void redirectToPage(String page) {
        ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
        context.redirect(context.getRequestContextPath() + page);
    }
    _

    _name="doLogout"_の属性_p:remoteCommand_は、どこからでも呼び出すことができるjavascript関数に変換されることを忘れないでください。マネージドBeanでビューを繰り返すのに最適です。

    このアプローチにより、システムスタックが防止されますViewExpiredException


  • keepAliveの概念を理解していない人もいますが、それは非常に簡単です。マネージドBean内に単純な関数を追加するだけです。例keepSessionAliveアクション:

    _public void keepSessionAlive () {
        System.out.println(">>> Session is alive... ");
    }
    _

    _p:remoteCommand_という名前のkeepAlivekeepAlive()というJavaScript関数であり、その呼び出しはアクションkeepSessionAliveマネージドBean内。

    このアクションは、アイドル状態ではないことを示します。


  • _session.maxInactiveInterval_のidleMonitor参照_<session-timeout>_のweb.xml

    _<p:idleMonitor timeout="#{session.maxInactiveInterval * 1000 - 125000}"
                   onidle="startIdleMonitor()" onactive="timeoutDialog.hide()" />
    _

    セッション終了後の実行doLogout()を防ぎ、ViewExpiredExceptionを取得するために、セッション終了の5秒前にセッションモニターを実行することをお勧めします。

    Javascriptコードの最初の行は_var TIME = 120; // in seconds_で、これはセッションを終了する時間を表します。元のコード_# {session.maxInactiveInterval * 1000 - 125000}_は、1.000で乗算されたセッションタイムアウトを使用し(ミリ秒であるため)、125秒を表す125.000を減算します。これは、カウンターより5秒短いため、変更する必要はありません。


これがお役に立てば幸いです...幸運を祈ります!

3
ℛɑƒæĿ