部分刷新重复控制和托管 Bean 运行 问题
Partial Refresh Repeat Control and Managed Bean running issue
我将 xPage 中的一个面板设置为在计时器上进行部分刷新。如时间字段所示,部分刷新面板外的页面不会刷新,但是,刷新面板外的重复控件中的托管 Bean 会在每个计时器事件上初始化。如果我用 ComputedField 替换 Repeat Control,则 Bean 不会 运行。这会在服务器上造成不必要的负载,因为托管 Bean 会收集大量数据。除了计时器之外,按钮事件也存在问题。
以下是我的测试页。感谢任何帮助。
<xp:this.beforeRenderResponse><![CDATA[#{javascript:var time = new Date();
var timeString= ("0" + time.getHours()).slice(-2) + ":" +
("0" + time.getMinutes()).slice(-2) + ":" +
("0" + time.getSeconds()).slice(-2);
viewScope.put("time",timeString)}]]></xp:this.beforeRenderResponse>
<xp:scriptBlock
id="scriptBlockRefresh">
<xp:this.value>
<![CDATA[
setInterval(function()
{XSP.partialRefreshGet("#{id:refreshPanel}", {})},
10 * 1000);]]>
</xp:this.value>
</xp:scriptBlock>
<xp:panel id="refreshPanel">
<xp:text escape="true" value="#{classABean.classAText}"></xp:text>
<xp:text escape="true" value="#{viewScope.time}"></xp:text>
</xp:panel>
<xp:panel id="restOfPagePanel">
<xp:text escape="true" id="computedField4" value="#{classBBean.classBText}"></xp:text>
<xp:repeat id="repeat1" rows="30" value="#{classBBean.classBText}" var="rowData">
<xp:text escape="true" value="#{rowData}"></xp:text>
</xp:repeat>
<xp:text escape="true" value="#{viewScope.time}"></xp:text>
</xp:panel>
测试托管 Bean
import java.io.Serializable;
public class ClassA implements Serializable{
private static final long serialVersionUID = 1L;
private String classAText;
public String getClassAText() {
System.out.println("Running Class A");
classAText = "I am Class A";
return classAText;}
B 类也是如此
FacesConfig
<managed-bean>
<managed-bean-name>classABean</managed-bean-name>
<managed-bean-class>uk.networkconnect.wallboardutils.ClassA</managed-bean-class>
<managed-bean-scope>view</managed-bean-scope>
<managed-bean>
<managed-bean-name>classBBean</managed-bean-name>
<managed-bean-class>uk.networkconnect.wallboardutils.ClassB</managed-bean-class>
<managed-bean-scope>view</managed-bean-scope>
用于测试的按钮代码。
<xp:button value="Refresh Panel A" id="button1">
<xp:eventHandler event="onclick" submit="false" >
<xp:this.script><![CDATA[XSP.partialRefreshGet("#{id:refreshPanel}",{})
]]></xp:this.script>
</xp:eventHandler>
</xp:button>
您的代码应该可以工作,但有一个问题 - 我不能说您是否已经处理好它。事实上,使用 JSF 时,您必须确保仅在第一次加载数据,并对后续调用采取防御措施。事实上,引擎可能会在生命周期中两次调用相同的方法。
以您提供的模型为例,代码应如下所示:
public class ClassA implements Serializable {
private static final long serialVersionUID = 1L;
private String text;
public String getClassText() {
if (text == null) {
String name = getClass().getName();
System.out.println("Running class " + name);
text = "I am class " + name;
}
return text;
}
}
基本上,只有在计算结果为 null
时才设置文本。设置变量后,无论引擎对该方法进行多少次调用,代码都不会再进入块内。
XPage不需要修改。
<xp:scriptBlock
value="
setInterval(function() {
XSP.partialRefreshGet('#{id:refreshPanel}');
}, 10 * 1000)" />
<xp:panel id="refreshPanel" style="background-color: red">
<xp:text escape="true" value="#{a.classText}" />
<xp:text escape="true" value="#{viewScope.time}" />
</xp:panel>
<xp:panel id="restOfPagePanel" style="background-color: grey">
<xp:text escape="true" id="computedField4" value="#{b.classText}" />
<xp:repeat id="repeat1" rows="30" value="#{b.classText}"
var="rowData">
<xp:text escape="true" value="#{rowData}" />
</xp:repeat>
<xp:text escape="true" value="#{viewScope.time}" />
</xp:panel>
<xp:button value="Label" id="button1">
<xp:eventHandler event="onclick" submit="true"
execMode="partial" refreshMode="partial" refreshId="refreshPanel" />
</xp:button>
刷新到浏览器的内容与在服务器上处理的内容不同。 refreshId
涵盖 XPage 的哪些区域应该 HTML 传回给浏览器。但是 HTML 可能会有所不同,具体取决于用户在页面其他地方所做的更新。这就是 execId
的目的,它决定了 server 应该处理的区域。 exec 区组件的值 属性 仍然需要在生命周期中计算。如果您的 bean 的 getter 每次都只是 运行 代码,正如 Shillem 所说,延迟加载(如果为 null,则设置该值,否则使用该值)是一个很好的方法。与 Java.
中的 SSJS 方法和标准相比,这是一个显着的优势
如果 bean 中的值永远不变,另一种选择是将重复控件的值 属性 设置为在页面加载时计算 - ${b.classText}
而不是 #{b.classText}
。
重复控件还有其他设置,也可以设置为处理不变的内容。 repeatControls="true"
设置页面加载时重复的值,并在组件树中创建行组件的副本。默认情况下,将有一个抽象的组件行,每次刷新都会对其进行迭代。 removeRepeat="true"
将在所有组件集都加载到组件树中后删除重复控件。
我将 xPage 中的一个面板设置为在计时器上进行部分刷新。如时间字段所示,部分刷新面板外的页面不会刷新,但是,刷新面板外的重复控件中的托管 Bean 会在每个计时器事件上初始化。如果我用 ComputedField 替换 Repeat Control,则 Bean 不会 运行。这会在服务器上造成不必要的负载,因为托管 Bean 会收集大量数据。除了计时器之外,按钮事件也存在问题。
以下是我的测试页。感谢任何帮助。
<xp:this.beforeRenderResponse><![CDATA[#{javascript:var time = new Date();
var timeString= ("0" + time.getHours()).slice(-2) + ":" +
("0" + time.getMinutes()).slice(-2) + ":" +
("0" + time.getSeconds()).slice(-2);
viewScope.put("time",timeString)}]]></xp:this.beforeRenderResponse>
<xp:scriptBlock
id="scriptBlockRefresh">
<xp:this.value>
<![CDATA[
setInterval(function()
{XSP.partialRefreshGet("#{id:refreshPanel}", {})},
10 * 1000);]]>
</xp:this.value>
</xp:scriptBlock>
<xp:panel id="refreshPanel">
<xp:text escape="true" value="#{classABean.classAText}"></xp:text>
<xp:text escape="true" value="#{viewScope.time}"></xp:text>
</xp:panel>
<xp:panel id="restOfPagePanel">
<xp:text escape="true" id="computedField4" value="#{classBBean.classBText}"></xp:text>
<xp:repeat id="repeat1" rows="30" value="#{classBBean.classBText}" var="rowData">
<xp:text escape="true" value="#{rowData}"></xp:text>
</xp:repeat>
<xp:text escape="true" value="#{viewScope.time}"></xp:text>
</xp:panel>
测试托管 Bean
import java.io.Serializable;
public class ClassA implements Serializable{
private static final long serialVersionUID = 1L;
private String classAText;
public String getClassAText() {
System.out.println("Running Class A");
classAText = "I am Class A";
return classAText;}
B 类也是如此
FacesConfig
<managed-bean>
<managed-bean-name>classABean</managed-bean-name>
<managed-bean-class>uk.networkconnect.wallboardutils.ClassA</managed-bean-class>
<managed-bean-scope>view</managed-bean-scope>
<managed-bean>
<managed-bean-name>classBBean</managed-bean-name>
<managed-bean-class>uk.networkconnect.wallboardutils.ClassB</managed-bean-class>
<managed-bean-scope>view</managed-bean-scope>
用于测试的按钮代码。
<xp:button value="Refresh Panel A" id="button1">
<xp:eventHandler event="onclick" submit="false" >
<xp:this.script><![CDATA[XSP.partialRefreshGet("#{id:refreshPanel}",{})
]]></xp:this.script>
</xp:eventHandler>
</xp:button>
您的代码应该可以工作,但有一个问题 - 我不能说您是否已经处理好它。事实上,使用 JSF 时,您必须确保仅在第一次加载数据,并对后续调用采取防御措施。事实上,引擎可能会在生命周期中两次调用相同的方法。
以您提供的模型为例,代码应如下所示:
public class ClassA implements Serializable {
private static final long serialVersionUID = 1L;
private String text;
public String getClassText() {
if (text == null) {
String name = getClass().getName();
System.out.println("Running class " + name);
text = "I am class " + name;
}
return text;
}
}
基本上,只有在计算结果为 null
时才设置文本。设置变量后,无论引擎对该方法进行多少次调用,代码都不会再进入块内。
XPage不需要修改。
<xp:scriptBlock
value="
setInterval(function() {
XSP.partialRefreshGet('#{id:refreshPanel}');
}, 10 * 1000)" />
<xp:panel id="refreshPanel" style="background-color: red">
<xp:text escape="true" value="#{a.classText}" />
<xp:text escape="true" value="#{viewScope.time}" />
</xp:panel>
<xp:panel id="restOfPagePanel" style="background-color: grey">
<xp:text escape="true" id="computedField4" value="#{b.classText}" />
<xp:repeat id="repeat1" rows="30" value="#{b.classText}"
var="rowData">
<xp:text escape="true" value="#{rowData}" />
</xp:repeat>
<xp:text escape="true" value="#{viewScope.time}" />
</xp:panel>
<xp:button value="Label" id="button1">
<xp:eventHandler event="onclick" submit="true"
execMode="partial" refreshMode="partial" refreshId="refreshPanel" />
</xp:button>
刷新到浏览器的内容与在服务器上处理的内容不同。 refreshId
涵盖 XPage 的哪些区域应该 HTML 传回给浏览器。但是 HTML 可能会有所不同,具体取决于用户在页面其他地方所做的更新。这就是 execId
的目的,它决定了 server 应该处理的区域。 exec 区组件的值 属性 仍然需要在生命周期中计算。如果您的 bean 的 getter 每次都只是 运行 代码,正如 Shillem 所说,延迟加载(如果为 null,则设置该值,否则使用该值)是一个很好的方法。与 Java.
如果 bean 中的值永远不变,另一种选择是将重复控件的值 属性 设置为在页面加载时计算 - ${b.classText}
而不是 #{b.classText}
。
重复控件还有其他设置,也可以设置为处理不变的内容。 repeatControls="true"
设置页面加载时重复的值,并在组件树中创建行组件的副本。默认情况下,将有一个抽象的组件行,每次刷新都会对其进行迭代。 removeRepeat="true"
将在所有组件集都加载到组件树中后删除重复控件。