XPages有时会刷新并丢失内容

时间:2012-05-31 14:10:22

标签: xpages xpages-ssjs

我希望有人可以帮助我解决我们当前遇到的一个非常严重的问题,当用户使用它时,关键业务应用程序会丢失数据。

这是随机发生的 - 我从来没有复制过这个,但用户在系统中比我更多。

创建的文档中包含大量字段,并且有2个富文本字段。我们正在使用Domino 8.5.3 - 没有使用扩展lib控件。该文档内置了工作流,所有验证都是通过从数据查询保存事件调用的SSJS函数完成的。对sessionscope.log进行了大量的日志记录,这也是(现在)为Notes文档中的每个用户捕获的,因此我可以查看他们正在做什么。

有时,用户进入工作流程步骤,他们必须填写富文本字段并在下拉字段中进行选择,然后他们使用工作流程按钮提交文档。当按下工作流程按钮时(完全更新),某些客户端JS首先运行

// Process any autogenerated submit listeners
if( XSP._processListeners ){ // Not sure if this is valid in all versions of XPages
    XSP._processListeners( XSP.querySubmitListeners, document.forms[0].id );
}

(我添加了这个以尝试防止RTF字段在阅读博客后丢失其值,但到目前为止它还没有工作)

然后运行服务器端事件并调用view.save()以触发QS代码(用于验证)和PS代码以在服务器上运行工作流代理。

95%的时间,这很好。

然而,只有5%的时间,页面刷新所有所做的更改,包括RFT字段(CKEditor)和下拉字段都按原样重新加载,没有内容。就像保存没有发生一样,完全更新按钮决定像页面刷新而不是提交一样工作。

在正常情况下,日志显示当按下工作流按钮时,QuerySave代码启动并返回True。然后记录按下的工作流程按钮的ID(因此我可以看到在查看问题时正在使用哪些),然后PostSave代码启动并最终返回true。

当出现问题时,QuerySave事件会运行,如果验证通过则返回true,如果验证失败则返回false,然后停止。还会记录工作流程按钮的ID。但是如果QuerySave返回true,则代码应该通过调用PostSave函数继续 - 它甚至不记录它启动PostSave函数。

更糟糕的是,在调用PostSave代码失败之后,记录的下一件事是运行的beforePageLoad事件,这显然会重新加载页面,该页面没有最近的编辑,并且所以用户丢失了他们输入的所有信息!

这一直是我曾经遇到的最烦人的问题,因为我无法找到成功的QuerySave(甚至是因为没有填写必填字段而导致失败)会导致页面的原因像这样刷新并丢失内容。请有人帮我指点正确的方向吗?

4 个答案:

答案 0 :(得分:1)

听起来好像在5%的用例中,文档打开了> 30分钟,XSP会话超时 - 提交导致重新创建组件树,现在空页面返回给用户。尝试增加应用程序的时间以查看问题是否消失。

答案 1 :(得分:0)

我会设计流程略有不同。在JSF / XPages中,验证属于验证器,而不属于QuerySave事件。此外,我宁愿使用提交按钮,因此您不需要在代码中触发view.save()。这不会干扰JSF的一系列事情 - 但这种风格不一定是你问题的根源......对此的想法:

正如Jeremy所说,作为第一站,我怀疑是超时,那么下一站是QuerySave事件中的一个致命问题,它会破坏运行时(无论出于何种原因)。你可以尝试这样的事情:

var qsResult = false;
// your code goes here, no return statements
// please and if you are happy
qsResult = true;
return qsResult;

悲观的方法最终会告诉你是否有问题。另外:如果有中止并且您的querySave只返回,那么您可能会在此陷阱中运行

function noReturn() {return; }  //nothing comes back!

noReturn() == true;    --> false
noReturn() == false;   --> false
noReturn() != false;   --> true!!!!

您需要检查的内容:您的性能设置是什么:序列化到磁盘,保留在内存中或保留最新的内存?可能是你在JavaScript库的工作方式上犯了错误。

只要需要,就会加载SSJS库。里面的变量被初始化。当内存条件需要它时,将卸载库,并丢弃所有相关变量。因此,如果您依赖于JS函数中的任何变量,这些变量位于调用之间的SSJS库中,您可能会或可能不会获取值,这可能会描述您的错误情况。你要保留的东西应该进入范围(viewScope似乎就在这里)。

让它变得更加棘手: 当您使用闭包和第一类函数时,除非已卸载库,否则这些函数可以访问父函数中的变量。还有函数(你也可以将它们放在一个范围内)不要序列化(打开缺陷),所以在将它们放入范围时你需要小心。

如果您的东西非常复杂,那么使用支持bean可能会更好。 这有帮助吗?

答案 2 :(得分:0)

要创建托管bean(或更多),请选中Per's article。您的验证器将位于应用程序bean中:

<faces-config>
    <managed-bean>
       <managed-bean-name>workflowvalidator</managed-bean-name>
       <managed-bean-class>com.company.WfValidator</managed-bean-class>
       <managed-bean-scope>application</managed-bean-scope>
    </managed-bean>
</faces-config>

在里面,您将使用地图来显示错误消息

public Map<String,String> getErrorMessages() {
     if (this.errorStrings == null) { // errorStrings implements the MAP interface
        this.loadErrorDefinitions(); //Private method, loads from Domino
     }
     return this.errorStrings;
}

然后您可以在验证器的错误消息字符串中使用EL:

 workflowvalidator.errorMessage("some-id");

这允许XPage直接在EL中选择正确的,这比SSJS更快。然后,您可以实现自己的custom Java validator与该bean对话(这将允许您在此处绕过SSJS)。除了示例之外,我不会将注释代码放入其中,而是与您的WfValidator类进行对话。要做到这一点,你需要在Java中获得它的句柄:

private WfValidator getValidatorBean() {
    FacesContext fc = FacesContext.getCurrentInstance();
    return (WfValidator) fc.getApplication()
                           .getVariableResolver()
                           .resolveVariable(fc, "workflowvalidator");
}

使用解析器可以访问已加载的bean。希望有所帮助!

答案 3 :(得分:0)

我的经验是,这个问题是由于将页面保留在内存中。有时由于某种原因,页面会被内存消失。当有很多部分刷新和相当复杂的后端Java处理时,我看到了这一点。这种处理似乎从XPage使用的内存中占用了空间。

问题可能已在以后的版本中修复,但我至少在8.5.2中看到了它。

在您的情况下,我会找出CKEditor错误的其他一些解决方法,并使用“保留磁盘上的页面”选项。或者,如果您可以升级到9.0.1,它可能会解决这两个问题。