我想显示<p:growl>
会话已过期。我发现了许多处理会话过期的方法,例如JSF/PrimeFaces ajax 请求上的 Session timeout 和 ViewExpiredException 处理,但我无法将 faces 消息推送到<p:growl>
.
至此,当 HTTP 会话在服务器端自动过期时,如何在客户端自动运行一些(JavaScript)代码?
我想显示<p:growl>
会话已过期。我发现了许多处理会话过期的方法,例如JSF/PrimeFaces ajax 请求上的 Session timeout 和 ViewExpiredException 处理,但我无法将 faces 消息推送到<p:growl>
.
至此,当 HTTP 会话在服务器端自动过期时,如何在客户端自动运行一些(JavaScript)代码?
您可以为此使用 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>
要在多个页面中激活超时处理,请在布局模板中包含超时模板:
<!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>
会自动关闭,关闭代码为 1000(“正常关闭”)。
换句话说,只需执行以下操作:
<f:websocket ... scope="session" onclose="sessionScopedSocketCloseListener" />
function sessionScopedSocketCloseListener(code) {
if (code == 1000) {
alert("Session has expired!");
}
}
如有必要,您可以将其与<p:growl>
.
<p:growl widgetVar="growl" ... />
PF("growl").renderMessage({severity: "warn", summary: "Session has expired!" });
如果您还没有使用 JSF 2.3,那么您始终可以使用<o:socket>
它提供onclose
与<f:websocket>
. 另请参阅服务器如何将异步更改推送到由 JSF 创建的 HTML 页面?
@uı6ʎɹnɯ lǝıuɐp发布的代码非常有用,但我将添加一些观察:
@Jonathan L建议替换processTimer = 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);
}
请记住, 的属性在您可以在任何地方调用的 javascript 函数中进行转换
name="doLogout"
。p:remoteCommand
使用托管 bean 迭代视图是完美的。这种方法将防止您的系统堆栈ViewExpiredException。
有些人不理解这个keepAlive
概念,但很简单,只需在托管 bean 中添加一个简单的函数即可。示例keepSessionAlive
动作:
public void keepSessionAlive () {
System.out.println(">>> Session is alive... ");
}
请记住,
p:remoteCommand
namedkeepAlive
是一个被调用的 javascript 函数keepAlive()
,它调用keepSessionAlive
托管 bean 中的一个动作。这个动作表明你没有闲着。
web.xml的session.maxInactiveInterval
idleMonitor 引用<session-timeout>
<p:idleMonitor timeout="#{session.maxInactiveInterval * 1000 - 125000}"
onidle="startIdleMonitor()" onactive="timeoutDialog.hide()" />
我建议在会话结束前 5 秒执行会话监视器,以防止
doLogout()
在会话结束后运行并获取ViewExpiredException。
第一行 javascript 代码是var TIME = 120; // in seconds
,这表示结束会话的时间。原始代码# {session.maxInactiveInterval * 1000 - 125000}
将使用会话超时乘以 1.000(因为它是毫秒)并减去 125.000 表示 125 秒,比计数器少 5 秒,因此不需要更改。
我只是想在这里为未来的访问者发帖,我能够找到一种稍微不同但工作的方法,其中包含 idlemonitor 和 timer 组件。基本上,如果在 web.xml 中将会话超时设置为 30 分钟,则此代码将在用户空闲 28 分钟后打开一个对话框,其中包含以下组件: 消息 - 您即将在几分钟内注销。请单击确定按钮以使会话保持活动状态。Timer - Primefaces 扩展计时器,将有 2 分钟倒计时。确定按钮 - 使会话保持活动状态 注销按钮 - 注销用户。这是此更改的代码:
sessionTimeOut.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:pu="http://primefaces.org/ultima"
xmlns:pe="http://primefaces.org/ui/extensions">
<h:form>
<p:idleMonitor timeout="#{session.maxInactiveInterval * 1000 - 130000}" onidle="PF('idleDialog').show();PF('timeoutTimer').start();" />
<p:dialog id="timeoutDialog" header="Are you there?" widgetVar="idleDialog" modal="true" closable="false" draggable="false" resizable="false" >
<p:panelGrid columns="1" styleClass="ui-noborder">
<p:panel>
<h:outputText value="You are about to be logged off in " />
<p:spacer width="10"/>
<pe:timer id="timeoutTimer" widgetVar="timeoutTimer" singleRun="true" timeout="120" format="mm:ss" autoStart="false" listener="#{userSessionBean.logout()}"/>
<p:spacer width="10"/>
<h:outputText value=" mins." />
</p:panel>
<p:panel>
<h:outputText value="Please click 'Ok' to keep the session alive" />
</p:panel>
<p:panel style="text-align: center;">
<p:commandButton id="confirm" value="Ok" actionListener="#{userSessionBean.keepAlive()}" onclick="PF('timeoutTimer').stop(true);" oncomplete="PF('idleDialog').hide();" process="@this"/>
<p:spacer width="10"/>
<p:commandButton id="timeoutLogout" value="Log Out" widgetVar="timeoutLogoutWV"
actionListener="#{userSessionBean.logout()}" oncomplete="PF('timeoutTimer').stop(true); PF('idleDialog').hide(); location.reload(true);"/>
</p:panel>
</p:panelGrid>
</p:dialog>
</h:form>
</ui:composition>
将此插入到您的基本模板中
<ui:include src="./sessionTimeOut.xhtml" />
这是java端代码
public void keepAlive() {
logger.info("User " + loggedInUser.getUserLogin() + " requested the Session " + getCurrentHttpSessionId() + " to be kept alive at " + new Date().toString());
/**
* Do nothing
*/
}
public String logout() throws IOException {
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
externalContext.getContextName();
logger.info(FacesContext.getCurrentInstance().getExternalContext().getContextName());
facesContext.getExternalContext().redirect("/Project/views/login.xhtml");
logger.info("Logout");
}
我希望这有帮助。谢谢。