我有一个前端文档锁定过程,它创建一个Application Scope变量,其中包含UNID / Username / time,然后是一个每30秒更新一次该信息的计时器。如果有人试图打开文档进行编辑,我会检查(使用UNID)以查看是否有其他人拥有该文档。如果时间大于30秒,我取消锁定并允许新用户打开它。
我考虑过与数据库做类似的事情'锁定'这很简单,但我需要一个唯一的浏览器会话标识符。我可以使用ReplicaID / UserName / time构建applicationScope变量,但我还需要一条能识别此浏览器会话的信息。
在某处可以获得这样的信息吗?像浏览器sessionID?
答案 0 :(得分:3)
您希望每个用户和数据库只允许一个打开浏览器窗口/标签。
对于您在浏览器中打开的每个XPage,您必须测试是否已在另一个浏览器窗口/选项卡中打开相同的数据库。如果是这样,请拒绝打开XPage,例如重定向到错误XPage。
仅在服务器端无法执行此操作,因为服务器不知道Xpage在哪个浏览器选项卡中打开。
因此,服务器需要客户的帮助。客户必须向服务器提供唯一浏览器窗口/标签ID 。
浏览器窗口/标签没有唯一的ID。但是,打开新窗口/标签我们可以创建随机ID 并将其存储在浏览器 sessionStorage 中。这是每个窗口/标签的唯一存储空间。
此窗口/选项卡ID 可以通过部分刷新GET发送到服务器,并在应用程序范围变量中存储在服务器上。
此外,服务器必须知道窗口/选项卡何时关闭,以便可以在另一个窗口/选项卡中打开相同的数据库。为此,客户必须告诉服务器"我还活着#34;每隔X秒。
这是完整的解决方案:
创建自定义控件" UniqueBrowserTab"
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:eventHandler
event="onClientLoad"
submit="false">
<xp:this.script><![CDATA[
var secondsIamAliveInterval = 5;
var tabId = sessionStorage.getItem("tabId");
if (!tabId) {
tabId = Math.random();
sessionStorage.setItem("tabId", tabId);
}
function sendTabIdToServer() {
XSP.partialRefreshGet("#{id:browserTabControl}", {
params: {'tabId': tabId}
});
}
sendTabIdToServer();
setInterval(function() {
sendTabIdToServer();
}, secondsIamAliveInterval * 1000);
]]></xp:this.script>
</xp:eventHandler>
<xp:panel id="browserTabControl">
<xp:this.rendered><![CDATA[#{javascript:
var secondsIgnoreOtherSession = 7;
if (param.tabId) {
var userName = session.getEffectiveUserName();
var userData = applicationScope.get(userName);
var now = new Date().getTime();
if (userData) {
if (userData.tabId !== param.tabId) {
if (userData.time + secondsIgnoreOtherSession*1000 > now) {
context.redirectToPage("Error.xsp");
}
}
}
applicationScope.put(userName, {tabId : param.tabId, time: now});
}
return true
}]]></xp:this.rendered>
</xp:panel>
</xp:view>
包括自定义控件&#34; UniqueBrowserTab&#34;进入每个XPage或例如进入应用程序布局的自定义控件。
<?xml version="1.0" encoding="UTF-8"?>
<xp:view
xmlns:xp="http://www.ibm.com/xsp/core"
xmlns:xc="http://www.ibm.com/xsp/custom">
<xc:UniqueBrowserTab />
...
</xp:view>
创建一个XPage Error.xsp,其不包含自定义控件&#34; UniqueBrowserTab&#34;。
对于所有浏览器中的用户,每个数据库只允许一个浏览器窗口/选项卡。
答案 1 :(得分:0)
SessionID cookie对于浏览器是唯一的。我相信它是作为部分刷新信息的一部分传递的。
请记住,SessionID对于浏览器的多个窗口都是相同的。我不确定这是不是一个问题。
答案 2 :(得分:0)
感谢所有发布在这里的内容。实际上有两个相似但不同的问题。
在第一个实例中,它是在同一个浏览器中阻止应用程序的多个实例,而Sven的帖子回答了那个实例。
第二个问题是在多个浏览器中打开相同的应用程序。在这种情况下,我将使用一个applicationScope变量appSession,它是一个Map,键为UserName~DBRepID,然后是两个&#39;
客户端计时器事件刷新的时间,该事件更新每个&#34; N&#34;秒。 sessionID = facesContext.getExternalContext()。getRequest()。getSession()。getId();
在之前的页面加载中(可能作为PhaseListener ??)如果sessionID匹配打开页面,我用关键UserName~RepID查找appSession。如果appSession中的时间到期,则将时间设置为当前时间,并将sessionID设置为当前的getID()并打开页面。如果没有,则打开错误页面。 sessionID必须有一个计时器,这样如果用户关闭浏览器或选项卡,它最终会超时。我使用类似这样的东西来制作XPage文档锁定例程并且效果很好。
我还没有将这些全部放在一起,但它看起来好像应该完成工作。如果有人看到更好的方法,我会很高兴听到。