【问题标题】:XPages sometimes refresh and lose contentXPage 有时会刷新并丢失内容
【发布时间】:2012-05-31 14:10:22
【问题描述】:

我希望有人可以帮助我解决我们目前面临的一个非常严重的问题,即当用户在其中工作时,关键业务应用程序会丢失数据。

这是随机发生的——我从未复制过,但系统中的用户比我多得多。

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

有时,用户进入工作流程步骤,他们必须填写富文本字段并在下拉字段中做出选择,然后使用工作流程按钮提交文档。当按下工作流按钮(进行完整更新)时,一些客户端 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 事件,这显然会重新加载页面,而页面上没有最近的编辑,所以用户丢失了他们输入的所有信息!

这一定是我在使用 XPages 时遇到过的最烦人的问题,因为我找不到成功的 QuerySave(甚至因为未填写必填字段而导致失败)会导致页面像这样刷新的原因并丢失内容。请有人可以帮我指出正确的方向吗?

【问题讨论】:

标签: xpages xpages-ssjs


【解决方案1】:

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

【讨论】:

  • 感谢您的回复。我希望它是那么简单。我在页面上有 KeepSessionAlive 的代码版本(而不是 ExtLib CC),这可能会发生,就像今天一样,在用户通过之前的一些工作流程步骤成功提交文档然后到达一个需要填写RTF字段。今天的问题是在问题发生前3次通过工作流提交和重新加载相同的文档,每次页面都进行“完整更新”;所有这些都在大约 3 分钟的时间内完成。
  • 我假设对文档进行完整更新并使其正常工作会导致会话超时重新启动,对吗?因此,如果是 30 分钟,而有人在 15 分钟后提交,那么他们从那时起再获得 30 分钟?
  • 感谢迄今为止所有的帮助和指点。在讨论了有关使用托管 bean 进行适当验证的讨论后,我意识到——据我所知,这是有充分理由的,为什么不能这样做。我们需要在文档上有选项卡式面板,并且字段验证仅在您可以看到的字段上运行。这就是验证被移到脚本库以在提交时针对整个文档运行的原因。
【解决方案2】:

我会设计流程略有不同。在 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 库。里面的变量被初始化。当内存条件需要时,库会被卸载,并且所有相关的变量都会被丢弃。因此,如果您在调用之间依赖位于 SSJS 库中的 JS 函数中的任何变量,您可能会或可能不会取回该值,这可能会描述您的错误情况。您想要保留的东西应该进入一个范围(viewScope 似乎就在这里)。

为了让它更棘手一点: 当您使用闭包和第一类函数时,这些函数可以访问父函数中的变量,除非库已被卸载。此外,函数(您也可以将它们停放在作用域中)不会序列化(开放缺陷),因此在将它们放入作用域时需要小心。

如果你的东西真的很复杂,你最好使用 backing bean。 这有帮助吗?

【讨论】:

  • 哇,感谢这里提供的所有方便提示。我的设计中需要注意的一两件事可能会或可能不会有所作为。该应用程序在提交的任何正常工作流文档上都有大约 100 个字段,随着流程的进行,越来越多的信息被添加。它为每个字段都有一个“字段”文档,描述字段的标签、添加到工具提示的帮助文本,以及它是否是强制性的(以及强制性字段错误消息)。当我接管这个应用程序时,我删除了验证器,因为每个字段都有一个 DBLookup 并将其放入脚本中
  • 脚本从 QS 事件中调用,并通过将这些 Field 文档作为一个集合进行所有验证,然后依次遍历每个文档,而不是 100 个 DbLookups 来查看每个字段是否为必填项等. 鉴于需要能够更改有关字段的详细信息,不确定这种方法是否更好(这个应用程序现在已经推出了几次相同的设计)。
  • 最后,为了解决这个错误:[link]www-304.ibm.com/support/docview.wss?uid=swg1LO55614 我将应用设置为“仅保留当前页面在内存中”
  • 所以基本上你有一个在配置文档中描述的验证机制。我仍然会使用验证器而不是 QS 事件。创建一个在内存中加载验证定义的托管 bean(它为 applicationScope 大喊大叫)。在 Java 中创建一个与 bean 对话的自定义验证器。然后,您只需将验证器分配给您的字段。您在配置中记录了哪些类型的验证条件?
  • 验证的主要类型只是检查一个字段是否为空。但是某些字段在工作流的某些步骤中成为必需的。就像您在提交问题时不需要填写问题的解决方案一样。另外 - 你说设置一个 var qsResult = false;然后将其设置为 true 并在您满意的情况下在 QS 中返回它。我已经在这样做了,并且 QS 肯定完成了最后一次出现错误,因为日志显示 (31-May-2012 08:53:06)... caseQuerySave Returning: true (31-May-2012 08:53 :06)... caseQuerySave :- 完成
【解决方案3】:

要创建托管 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");

这允许 XPages 直接在 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。希望有帮助!

【讨论】:

  • 感谢以上所有有价值的信息。我已经开始编写 Java bean 验证器并获得了一个可以工作的 simlpe 版本。我现在要等待新的 Java 开发人员下个月加入我的团队,这样他就可以完成它:-)
  • 我刚刚注意到的一件事是,如果您将并发模式设置为失败,因此不会创建代表冲突,并且在您在网络上工作时编辑文档,查询保存代码当您尝试保存时运行,但在调用实际保存时立即停止执行。我在上面描述了 QS 是如何运行的,而不是保存然后运行 ​​PS 事件代码,接下来运行的是 beforePageLoad 事件。当并发模式启动时,如果保存有问题,我的处理错误的代码似乎完全被忽略了
【解决方案4】:

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

该问题可能已在以后的版本中得到解决,但我至少在 8.5.2 中看到了它。

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

【讨论】:

    猜你喜欢
    • 2014-05-24
    • 1970-01-01
    • 2023-03-25
    • 2021-01-16
    • 2019-09-04
    • 2014-12-31
    • 1970-01-01
    • 2022-11-02
    • 2017-04-19
    相关资源
    最近更新 更多