Xpages Xpage extlib对话框keepComponents true和JSF组件

Xpages Xpage extlib对话框keepComponents true和JSF组件,xpages,xpages-extlib,Xpages,Xpages Extlib,扩展库中的对话框控件有问题: 我创建了一个java自定义控件,它搜索一些视图,收集一些数据并显示。如果我把它放在XPage上,效果会很好 但是我想在对话框中显示数据,所以我使用了扩展库中的对话框控件。在没有任何配置的情况下使用对话框控件也可以正常工作,但是每次打开对话框时,我的控件都需要一些时间来搜索视图和显示数据。因此,为了减少用户的等待时间,我希望使用对话框控件中的选项“keepComponents=“true” 现在,如果我第一次打开对话框,一切都正常,但是如果我再次打开它,它会显示第一次

扩展库中的对话框控件有问题:

我创建了一个java自定义控件,它搜索一些视图,收集一些数据并显示。如果我把它放在XPage上,效果会很好

但是我想在对话框中显示数据,所以我使用了扩展库中的对话框控件。在没有任何配置的情况下使用对话框控件也可以正常工作,但是每次打开对话框时,我的控件都需要一些时间来搜索视图和显示数据。因此,为了减少用户的等待时间,我希望使用对话框控件中的选项
“keepComponents=“true”

现在,如果我第一次打开对话框,一切都正常,但是如果我再次打开它,它会显示第一次打开的内容以及controlRenderer的错误,它告诉我它无法从控件中获取viewName。每次打开和关闭对话框时,这个错误都会累积起来

我在OpenNtf上找到了一篇帖子,有人在使用这个选项时,在他的对话框中出现了多个内容的相同问题,但他没有得到任何问题的答案。
这是组件的一个bug吗?我是否应该忘记这个选项并将数据缓存在bean中?为什么渲染器不能从组件中获取Viewname?

下面的答案假设您问题中的短语“java自定义控件”指的是您开发的JSF组件;在XPages中,术语“自定义控件”通常指定制控件设计元素的实例,这是IBM对JSF概念“复合组件”的实现

您已经声明,组件最初的行为与预期一致,但在后续请求中失败。这通常表示组件的
restoreState
saveState
方法未正确实现

当为应用程序启用默认序列化选项时,所有组件状态将在每个请求结束时写入磁盘,并在下一个请求开始时读回内存。这两个操作分别由每个组件的
saveState
restoreState
方法处理

例如,假设您定义了一个组件,用于将HTML画布标记添加到XPage,并决定支持与该元素关联的手势和触摸事件。因此,组件类将包含用于存储绑定到这些事件的任何代码的字段:

private String ongesturechange;
private String ongestureend;
private String ongesturestart;
private String ontouchcancel;
private String ontouchend;
private String ontouchmove;
private String ontouchstart;
这些字段中的每一个通常都会有一个关联的“getter”和“setter”方法:

初始化该组件的实例时,将向与为该组件实例定义的每个属性相关联的“setter”方法传递为该属性定义的值。对于初始页面请求的其余部分,每个已定义属性的私有字段将存储已设置的值。在请求结束时,
saveState
方法将这些字段的值写入磁盘。典型的
saveState
方法如下所示:

@Override
public Object saveState(FacesContext context) {
    Object[] properties = new Object[8];
    int idx = 0;
    properties[idx++] = super.saveState(context);
    properties[idx++] = this.ongesturechange;
    properties[idx++] = this.ongestureend;
    properties[idx++] = this.ongesturestart;
    properties[idx++] = this.ontouchcancel;
    properties[idx++] = this.ontouchend;
    properties[idx++] = this.ontouchmove;
    properties[idx++] = this.ontouchstart;
    return properties;
}
@Override
public void restoreState(FacesContext context, Object state) {
    Object[] properties = (Object[]) state;
    int idx = 0;
    super.restoreState(context, properties[idx++]);
    this.ongesturechange = ((String) properties[idx++]);
    this.ongestureend = ((String) properties[idx++]);
    this.ongesturestart = ((String) properties[idx++]);
    this.ontouchcancel = ((String) properties[idx++]);
    this.ontouchend = ((String) properties[idx++]);
    this.ontouchmove = ((String) properties[idx++]);
    this.ontouchstart = ((String) properties[idx++]);
}
调用
super.saveState()
执行相同的方法,但使用父类中定义的方法版本。因此,每个组件的磁盘上表示本质上是一个嵌套数组:层次结构中的每个层在数组的第一个元素中存储它从父类继承的所有属性,然后在其他数组元素中存储它定义的所有属性

在后续请求中恢复组件树时,每个组件都使用其
restoreState
方法重新构造其所有字段的值。典型的
restoreState
方法如下所示:

@Override
public Object saveState(FacesContext context) {
    Object[] properties = new Object[8];
    int idx = 0;
    properties[idx++] = super.saveState(context);
    properties[idx++] = this.ongesturechange;
    properties[idx++] = this.ongestureend;
    properties[idx++] = this.ongesturestart;
    properties[idx++] = this.ontouchcancel;
    properties[idx++] = this.ontouchend;
    properties[idx++] = this.ontouchmove;
    properties[idx++] = this.ontouchstart;
    return properties;
}
@Override
public void restoreState(FacesContext context, Object state) {
    Object[] properties = (Object[]) state;
    int idx = 0;
    super.restoreState(context, properties[idx++]);
    this.ongesturechange = ((String) properties[idx++]);
    this.ongestureend = ((String) properties[idx++]);
    this.ongesturestart = ((String) properties[idx++]);
    this.ontouchcancel = ((String) properties[idx++]);
    this.ontouchend = ((String) properties[idx++]);
    this.ontouchmove = ((String) properties[idx++]);
    this.ontouchstart = ((String) properties[idx++]);
}
这将按层次结构读回磁盘上的数据:每个类将一组属性传递给父类,然后将剩余的数组元素分配给保存组件状态时与之关联的字段

这个过程提供了一种跨请求维护组件状态的简单方法——每个继承层只需要关心层定义的新属性——但是这些状态维护方法很容易忘记实现。如果组件实现中省略了任何一种方法,那么页面就会“忘记”后续请求的属性值,因为它们要么从未写入磁盘,要么没有加载回内存,要么两者都有

假设这是问题的根本原因,那么当组件位于具有
keepComponents
的默认(
false
)值的对话框中时,问题不会发生的原因是,默认对话框行为是在对话框关闭时将其子项完全从组件树中移除。这种行为是出于性能原因:从理论上讲,存储仅存在于用户当前未与之交互的对话框中的组件的服务器端表示形式不会带来任何好处。再次打开对话框时,将使用原始特性值创建每个子零部件的新实例。在这种情况下,组件不保存其状态并不重要,因为每次使用它时,都会创建一个新实例。但是如果对话框被告知将其子项保留在组件树中,那么组件现在必须正确地维护自己的状态。。。否则,它的属性值将在每个请求结束时丢弃,后续请求不知道以前的值


总之,是的,如果数据不太可能在请求之间发生足够的变化,从而证明在每个事件中再次获取数据是合理的,那么您正在显示的数据应该缓存在bean(或数据源)中。但是您所描述的特定行为的原因很可能是因为您的组件实现没有正确地维护自己的状态。

嗨,Tim,谢谢您的建议,但我已经使用了