【发布时间】:2010-10-18 19:51:22
【问题描述】:
我有一个应用程序,其中用户经常让页面整天在浏览器中运行。该页面有一个间隔渲染,每 30 秒更新一次数据。
但是,如果用户有一段时间没有与页面交互,它仍然会过期。只要浏览器打开并发出预定的请求,我希望它自动扩展。
有没有办法在每次为这些页面之一触发预定的渲染器时自动扩展会话?
【问题讨论】:
标签: java tomcat jsf icefaces java-ee-5
我有一个应用程序,其中用户经常让页面整天在浏览器中运行。该页面有一个间隔渲染,每 30 秒更新一次数据。
但是,如果用户有一段时间没有与页面交互,它仍然会过期。只要浏览器打开并发出预定的请求,我希望它自动扩展。
有没有办法在每次为这些页面之一触发预定的渲染器时自动扩展会话?
【问题讨论】:
标签: java tomcat jsf icefaces java-ee-5
如果我不明白您的真正目的是什么,那么您需要一种计时器,它会自动扩展每个用户会话客户端,从而覆盖服务器端默认页面会话到期时间(通常为 30 分钟,仅用于详细说明,因为我了解如果用户在页面上处于活动状态,则脚本每 30 秒“呈现”一次)。
如果很好,在 JSF 之前,我总是通过地下 Javascript 扩展非活动用户会话,所以我也会在你的情况下使用它。实际上,您可以从以下位置开始在 Javascript 中构建一个简单的页面侦听器:
window.setInterval( expression , msecIntervalTiming );
“表达式”可以是一个被调用函数,您可以在其中调用一些虚拟 JSF 来保持会话处于活动状态而无需重新加载用户访问的当前页面,过去我使用标准框架或 iframe 进行 http 调用,现在使用 XHR / Ajax 也更简单。
Javascript 示例:
var timerID = null;
function simplePageListener() { // invoked by some user event denoting his absence status
// here goes all events and logic you need and know for firing the poller...
if (timerID == null) // avoid duplicates
timerID = window.setInterval( "window.startPoller()", msecIntervalTiming );
}
//...
function pollerStart() {
// make iframe or ajax/xhr requests
}
function pollerStop() {
// make action like page reloading or other needings
}
//...
function triggeredCleanTimer(timer) { // invoked by some user event denoting his active status
clearTimeout(timer); // it can be also the global variable "timerID"
timerID = null;
}
实际上,您使用“timerID”作为全局参考来跟踪侦听器状态,因此当您需要激活“自动扩展”时,您可以为其分配一个 setInterval。相反,当用户返回页面(由您知道的某些事件触发)时,您清除停止侦听器轮询的超时。 上面的例子显然暗示了用户回来后必须手动重新加载页面。
但是,在您的具体情况下,我会避免干扰 Icefaces 框架自动生成的 javascript。即使对于 ipothesys,您可以在不可见的输入元素上定期模拟一些用户事件(样式设置为“可见性:隐藏”,绝对不是“显示:无”),这也会导致 Icefaces 事件不要停止它并使其自身持续工作
像 可以通过
周期性调用点击事件 document.forms["YourDummyForm"]["invisivleButton"].click();
有关用法,请参阅 Devedge Online 的旧 JS 文档 :-)
http://devedge-temp.mozilla.org/library/manuals/2000/javascript/1.3/reference/window.html#1203669
【讨论】:
ICEfaces 有一个保持会话活动的内部机制(该机制有时被称为“心跳”)。您可以查看所属的documentation 并在您的web.xml 中配置上述参数(尤其是heartbeatInterval 和heartbeatTimeout)。
【讨论】:
Iceface 的 Ajax 桥具有回调 API,例如您可以使用的 Ice.onSessionExpired()。
<body id="document:body">
<script type="text/javascript">
Ice.onSessionExpired('document:body', function() {
<!-- Do something here -->
});
</script>
更多详情请见http://www.icefaces.org/docs/v1_8_0/htmlguide/devguide/references4.html#1094786。
【讨论】:
当我的代码已经被 ICEFaces 每 30 秒调用一次时,我真的不想通过 Javascript hack 来单击按钮。 ICEFaces 内部计时器的以下黑客解决方法似乎有效:
private void updateSessionExpiration () {
HttpSession sess = getSession();
if (sess != null) {
try {
Field fld = SessionDispatcher.class.getDeclaredField("SessionMonitors");
fld.setAccessible(true);
Map map = (Map)fld.get(null);
String sessID = sess.getId();
if (map.containsKey(sessID)) {
log.info("About to touch session...");
SessionDispatcher.Monitor mon =
(SessionDispatcher.Monitor)map.get(sessID);
mon.touchSession();
}
} catch (Exception e) {
log.error("Failed to touch session");
}
}
}
此外,对于ICEFaces 1.8.2RC1(可能最终也将使用ICEFaces 1.8.2 的发布版本),有两种新的解决方法可用:
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpSession session = request.getSession();
if (session != null) {
SessionDispatcher.Monitor.lookupSessionMonitor(session).touchSession();
}
或者,将其放在 web.xml 中以更新对特定模式中 URL 的任何命中:
<filter>
<filter-name>Touch Session</filter-name>
<filter-class>com.icesoft.faces.webapp.http.servlet.TouchSessionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Touch Session</filter-name>
<url-pattern>/seam/remoting/*</url-pattern>
</filter-mapping>
【讨论】: