Bil*_*l F 1 database session-variables xpages
我想在一个人打开应用程序时设置一个applicationScope变量.设置的值在当前会话期间不会更改.可以作为sessionScope,但有相同的问题如何在会话打开时设置它.
执行此操作的"正确"方法是定义托管bean.
将Java设计元素添加到应用程序中.因为您的问题没有说明您尝试解决的业务需求,所以以下是一个完全通用的示例,希望能够说明该模式:
package com.example.bean;
import java.io.Serializable;
public class ExampleBean implements Serializable {
private static final long serialVersionUID = 1L;
private Object exampleProperty;
public ExampleBean() {
}
public Object getExampleProperty() {
if (exampleProperty == null) {
/*
* This is where you would auto-initialize the property value
*/
}
return exampleProperty;
}
public void setExampleProperty(Object exampleProperty) {
this.exampleProperty = exampleProperty;
}
}
Run Code Online (Sandbox Code Playgroud)
上面例子中的关键位是其中的块注释getExampleProperty().在您的真实类中,您将使用用于确定属性的当前值的任何逻辑替换该注释,并将其分配exampleProperty给该逻辑的结果.该代码每个范围实例只运行一次,因为访问该属性的每个额外时间,其值将不再为null,因此将返回当前值.
exampleProperty在类构造函数中放置自动初始化的逻辑似乎更直观(public ExampleBean() {...),但不要.遵循这种"延迟加载"模式有三个原因.首先,可以想象用户可能永远不会触发需要知道财产的价值.同样,我不知道为什么您希望在访问应用程序时立即存储值,因此在您的特定用例中,用户可能总是立即需要属性值.但是假设目标是存储一些应用程序设置,但是用户从不在应用程序中执行任何需要知道该设置的内容......您将检索该设置而不会从中获得任何好处.使用上述模式,在用户"询问"它之前不会检索它,但是当它们执行时,它就在那里,并一直持续到范围到期.
第二个原因是因为随着时间的推移你的类变得越来越复杂(因为你以这种方式存储越来越多的属性值),如果你在构造函数中放置初始化属性的所有逻辑,那么这个方法会变得很大,而且会是很难立即看到哪些代码用于初始化哪个属性.通过将每个属性的初始化逻辑放在其关联的"getter"方法中,您就可以隔离每个属性的逻辑; 该课程尽可能清晰,便于持续维护.
但也许最重要的原因是,当您将越来越多的应用程序逻辑移动到bean(以及我们所有人都应该)时,您将确定用于定义viewScope(特定于页面)bean的用例.除非您明确设置应用程序设置以将所有页面存储在内存中,否则viewScope只要应用程序认为应该将bean自动序列化到磁盘(因此在类声明中指示该类implements Serializable.稍后将根据需要将它们加载回内存中.这会触发类构造函数,然后将属性值设置回原来的值.换句话说,如果初始化exampleProperty在构造函数中,然后执行此操作的代码将在页面加载时执行,然后在针对页面执行的任何事件期间再次执行...但如果其值在某个时刻发生更改,则它将继续在每个事件上重新初始化,仅无论其后来的价值如何都要被覆盖.这几乎完全违背了将值存储在范围内的目的.不管范围如何,使所有bean可序列化也是一个好主意,因为如果IBM曾经为XPage添加真正的集群支持,那么应用程序和会话bean也需要序列化到磁盘,以便将它们复制到其他服务器,所以现在只需将所有bean序列化,当您升级到包含群集支持的Domino版本时,您不必担心您的应用程序突然中断.
总而言之,请记住,"延迟加载"模式对于bean来说"更好".:)
一旦定义了Java类,就可以"注册"它faces-config.xml.此文件存储在WebContent/WEB-INF,您可以通过Package Explorer找到,但在Domino 9中,它也表现为"应用程序配置"类别下的设计元素.
<?xml version="1.0" encoding="UTF-8"?>
<faces-config>
<managed-bean>
<managed-bean-name>exampleBean</managed-bean-name>
<managed-bean-class>com.example.bean.ExampleBean</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
</managed-bean>
<!--AUTOGEN-START-BUILDER: Automatically generated by IBM Domino Designer. Do not modify.-->
<!--AUTOGEN-END-BUILDER: End of automatically generated section-->
</faces-config>
Run Code Online (Sandbox Code Playgroud)
上面包含的示例类是命名的ExampleBean,我给它一个包名com.example.bean,因此类的"规范"名称com.example.bean.ExampleBean可以在上面的XML中看到.该名称是您要从应用中的任何位置引用的变量.该XML的范围部分定义要你的bean驻留在什么是特别方便关于这四个范围的是,如果你以后决定,这是存储在一个更好的契合sessionScope,那么你可以重新回到faces-config和更改application为session...并立即引用它的所有代码现在将访问sessionScope变量而不是applicationScope变量.您根本不需要更改任何XPage代码.
说到这里,现在你可以实际引用它,因为它被定义为托管bean:
从SSJS中的任何位置,您可以通过将bean名称视为对象来调用bean的公共方法:
return exampleBean.getExampleProperty();
Run Code Online (Sandbox Code Playgroud)
...要么...
exampleBean.setExampleProperty(someNewValue);
Run Code Online (Sandbox Code Playgroud)将bean视为数据源.你可以绑定任何组件属性(即value,title,rendered,等)直接到bean的任何属性:
#{exampleBean.exampleProperty}
这导致自动评估是否在"读取"上下文或"写入"上下文中访问该属性.如果用户当前正在做的是导致Domino"询问"属性值是什么,那么这就是读取.结果,它将自动知道调用"getter"方法(在这种情况下getExampleProperty()).但是,如果将可编辑组件属性(即value编辑框,单选按钮等属性)绑定到bean属性,并且用户现在将数据发布到该组件,Domino会自动知道调用"setter" (setExampleProperty())代替,并传递新值.
因此,如果这是一个应用程序设置,您可以包含一个只有进程所有者才能访问的设置页面,并使该属性可以编辑.在setter方法中,除了更新内部属性值之外,您还可以将新值写回到您获取它的任何位置(即配置文档).现在所有用户都可以访问新值,而无需再次从磁盘中检索它,但新值也会被存储,因此如果bean超出范围,则下次加载bean时会自动再次检索更新的值.
相反,如果它是用户设置(即存储在其中sessionScope),那么您可以类似地从应用程序中的任何位置访问该属性,同时也为他们提供修改设置的方法.与应用程序设置一样,当前值将始终在内存中,但如果在修改时将其写回磁盘,则内存中的值将始终为当前值,但是当该范围到期时,可以检索该值(一次) )需要时再次.
所有这些行为在技术上也可以通过SSJS实现.但是,正如我在本回答的开头所提到的,在范围内存储数据的最正确方法是通过托管bean.