扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
作者:www.ibm.com 来源:www.ibm.com 2007年9月15日
关键字: 技巧 JavaScript IBM lotus Office
IBM Lotus Component Designer 支持用于应用程序编程的 JavaScript。通过两种普通机制来实现:
JavaScript 是标准的、语法简单的、面向对象的、受浏览器和其他处理器支持的解释性编程语言。源语句嵌入到 XML、HTML 或其他源语言中,并由处理器中的解释器执行。
浏览器将自动处理可用的被称为文档对象模型(document object model,DOM)的对象集,DOM 代表页面。窗口对象提供了对页面上元素的访问。标准 JavaScript 和 DOM 的描述不在本文所讨论的范围内,不过有很多的指南和参考资料。在 Web 上搜索普通主题如 javascript dom、javascript 教程、javascript 参考或更多详细主题如 javascript switch 语句即可获取相关资料。
Lotus Component Designer 提供了作为主服务器运行时环境的一部分的 JavaScript 解释器,但是这并不是上一代的 JavaScript。该解释器包括内置的变量和类库,这些变量和类库将访问运行时上下文和后端数据存储、处理各种类型(string、numeric、Boolean 或正则表达式)的数据、调用 Web 服务以及模拟 IBM Lotus Domino @functions。该解释器还允许调用主服务器上的 Java 归档和 Lotus Component Designer Eclipse 环境中的 Java 代码。
使用 Lotus Component Designer 解释器可以处理服务器端脚本,或者使用浏览器解释器处理客户端脚本。
脚本案例分析
这里将演示一个简单的案例分析,用于说明客户端脚本和服务器端脚本。
页面有两个按钮,每个按钮有一个 onclick 事件和一个 computed 字段。图 1 展示了 Design 页面,突出显示了用于第一个按钮 hello client 的 Events 附签。
图 1. 客户端脚本
在 Events 附签上选择了以下选项:
代码是 window.alert 方法。当运行时用户单击按钮时,浏览器将立即显示窗口,如图 2 所示。
图 2. 运行时的客户端脚本
第二个按钮 hello server 与 computed 字段一起工作,图 3 突出显示了它在 Properties 附签中的值。
图 3. 服务器端脚本的 Computed 字段
该字段的值绑定到 request-scope(稍后将对此进行详细讨论)全局变量 hello 上。
第二个按钮和 Events 附签如图 4 所示。
图 4. 服务器端脚本
这里所选择的选项是:
脚本将值指定给绑定到 computed 字段的全局变量。当用户在运行时单击该按钮时,将有一个暂停,浏览器向服务器发送请求并且服务器以刷新页面进行响应。被重新描绘的浏览器屏幕如图 5 所示(调整了字体属性的大小和颜色)。
图 5. 运行时的服务器端脚本
概括地说,将使用 Lotus Component Designer 来创建页面、控件或其他工件。这些设计元素具有 XML 表示,可以在 Source 附签中查看并(谨慎)调整它们。图 6 展示了 hello world 示例页面的 Source 附签。
图 6. 示例页面的 Source 附签
部署过程将生成应用程序文件并/或将它们传输到服务器的文件系统。现在可以将组件作为应用程序部署到 IBM WebSphere Portal。例如,使用服务器的接口来设置应用程序,作为页面上的 portlet。然后用户可以启动应用程序,即访问包含该 portlet 的页面。有关部署说明,请参阅 Lotus Component Designer User Guide Help。
最初,服务器将生成默认页面的 HTML 并将它发送到用户的浏览器。用户将执行浏览页面、输入数据、单击按钮等操作。由用户操作所触发的事件可能会引起与服务器的交互或者不会引起交互,取决于在 Events 附签底部所选择的选项:
更新页面时,将重新计算被标记为“Compute Dynamically”的公式(参见图 7)。被标记为“Compute on Page Load”的公式仅在首次发送页面才进行计算。
图 7. 动态计算公式的示例
|
前端数据
可以直接通过标准客户端 JavaScript 及客户端 DOM 处理前端数据 —— 即用户放置在浏览器中当前页面上的数据。该方法的优点是不需要在客户机和服务器机器之间进行传输。另一方面,不具有服务器资源的访问权限。
在设计时客户端 DOM 元素的名称与指定给相应控件的名称不匹配。该名称是未知的,直到在载入浏览器页面之前由运行时生成。但是,可以将所生成的名称从服务器运行时传递到浏览器 DOM。例如,下面的代码是编辑框 inputText1 的 onchange 事件:
var e = window.document.getElementById("#{id:inputText1}");
e.value = e.value.toUpperCase()
选中了 Web Client 选项,因此在浏览器中运行,同时选中了 No Submission,所以不会引起与服务器的交互。当用户更改编辑框的值时,该值将立即转换成大写。
符号 #{id:inputText1} 是服务器端脚本,在将页面发送到浏览器之前执行该脚本。该嵌入脚本将获取由元素的设计时名称指定的运行时名称 (ID)。然后客户端 DOM 可以通过 ID 获取该元素。
通常,通过在客户端代码中嵌入服务器端脚本,可以将信息从服务器运行时传递到浏览器。下面是按钮的客户端 onclick 事件:
window.alert("#{javascript:session.getCommonUserName()}")
将该 JavaScript 载入浏览器之前,运行时将执行嵌入的服务器端脚本,因此普通的用户名在客户端 alert 方法中将作为字符串常量出现。
|
在 Lotus Component Designer 中,编程的核心在服务器端,它是资源之所在。但是,服务器端的处理需要浏览器和服务器之间的传输。
下面四个全局对象支持用户创建的变量且对于服务器端处理非常有用:
通过在 scope 对象名称后附加句点和名称来创建并引用用户变量。例如,如果按钮具有下面的服务器端 onclick 脚本:
requestScope.myvar = "My variable"
并且同一个页面上的标签使用下面的脚本进行计算:
requestScope.myvar
则当用户在运行时单击按钮时,标签的位置上将出现 “My variable”。
还可以使用 scope 对象的 put 方法和 get 方法。请注意将变量名指定为字符串:
requestScope.put("myvar", "My variable")
requestScope.get("myvar")
并且使用下面的语法:
requestScope["myvar"]
若要在服务器端使用用户输入的值,则获取并设置绑定到控件的数据元素。例如,可以将编辑框命名为 inputText1,但是若要获取它在服务器端的值,则在 Properties 附签上转到 Data 部分的 Data binding 字段。这可以是 schema 元素、Web 服务适配器或其他数据存储定义,不过也可以是全局变量。
假定使用以下脚本来指定该输入框的服务器端 onchange 事件,并且正在进行全部或部分更新:
requestScope.field1 = requestScope.field1.toUpperCase()
当运行时用户更改输入框内容时,浏览器将向服务器发送请求。服务器运行脚本,将绑定到字段的数据更改为大写。返回浏览器的 HTML 将反映更改。
关于性能的一点说明。如果将两个编辑框放在页面上,各带有一个服务器端 onchange 事件,然后用户更改第一个编辑框,则在向服务器发送请求并返回 HTML 时会出现暂停情况。当用户更改第二个编辑框时,同样的事情也会在第二个编辑框上发生。
避免多个中断的常用技术是将一个事件用于页面上的所有更新。例如,与每一个编辑框具有一个 onchange 事件相反,使用一个按钮的 onclick 事件。在更新两个字段后,用户单击按钮。按钮对应的代码如下所示:
requestScope.field1 = requestScope.field1.toUpperCase();
requestScope.field2 = requestScope.field2.toUpperCase();
如果以编程方式转到其他页面,则 requestScope 变量在不同页面之间是有效的。例如,在 page1 上一个编辑框有以下数据定义:
requestScope.field1
以及下面的 onchange 服务器端事件:
requestScope.field1 = requestScope.field1.toUpperCase();
context.redirectToPage("page2")
在 page2 上,computed 字段有以下值:
requestScope.field1
在运行时,用户更改 page1 上的编辑框,这将触发事件。浏览器向服务器发送请求,且执行事件代码。第一行代码将 field1 更改为大写。第二行将 page2 的 HTML 返回到浏览器 —— 上下文是指向 XSPContext 类型对象的内置变量,redirectToPage 是 XSPContext 的方法,该方法载入特定页面。因为所有处理位于一个请求内,所以 page2 上 field1 的值获得了在 page1 上所作的更改。
如果上述代码中不包含第二行内容,并且使用带有简单操作 Open Page 的第二个按钮以转到 page2,那么 computed 字段将返回空值。出现这种结果的原因是正完成一个请求(由 onchange 事件触发)并启动新请求(由按钮的 onclick 事件触发),因此 requestScope 变量不再有效。后一种技术也是低效的,它需要两个请求,而不是一个请求。
sessionScope 变量持续有效直到用户登出或者从服务器断开连接。例如,如果 page2 的 computed 字段和 page1 的数据定义如下:
sessionScope.field1
onchange 事件如下:
sessionScope.field1 = sessionScope.field1.toUpperCase()
则无论用户如何转到 page2,computed 字段将包含在 page1 编辑框中所放置的最后一个值的大写。请注意具有相同名称的不同 scope 变量并不是相同的变量。变量 requestScope.field1 与 sessionScope.field1 是不同的。
另一个警告:请确保字段的显示数据类型与数据的脚本使用是匹配的。例如,如果有一个编辑框的数据定义如下:
requestScope.field2
且具有以下 onchange 事件;
requestScope.field2 = Math.sqrt(requestScope.field2)
则目的是求平方根;但是仅当字段的显示类型是 Number (如图 8 所示)时才能工作。默认的显示类型是 String,因此这里可以检查数值计算是否产生正确结果。
图 8. 显示类型 Number
通过使用简单操作组,为一个事件中的客户端和服务器端编写脚本是可能的。
简单操作 Confirm Action 提供了带有 OK 和 Cancel 按钮的客户端对话框。如果用户单击 OK,则继续执行组中的简单操作;如果用户单击 Cancel,则终止组的执行。设计与图 9 相似。
图 9. 简单操作设计
Execute Script 简单操作将运行服务器端脚本,在 Edit Simple Action 对话框中对此进行了指定(参见图 10)。
图 10. Execute Script 简单操作
用户单击按钮时,第一个简单操作将运行,显示确认框。如果用户单击 OK,则运行第二个简单操作,执行脚本。如果用户单击 Cancel,则第二个简单操作不会运行。
通过附带两种脚本类型,也可以完成为一个事件中的客户端和服务器端编写脚本。如果一个事件同时具有客户端脚本和服务器端脚本,则首先执行客户端脚本。通过从客户端脚本返回 false,可以阻止执行服务器端行为,例如,一个按钮具有服务器端脚本,如清单 1 所示:
清单 1. 示例服务器端脚本
if(session.getCommonUserName() == "wpsadmin") { requestScope.field1 = requestScope.field1.toUpperCase(); requestScope.field2 = requestScope.field2.toUpperCase(); } |
以及下面的客户端脚本:
if(window.confirm("Changing fields to upper ... OK?") != true)
return false
当用户单击按钮时,将运行客户端脚本,显示确认框。如果用户单击 OK,则将运行服务器端脚本。如果用户单击 Cancel,则不会执行进一步操作。
|
后端数据
以非编程方式来处理数据存储的方法如下:
然后两个按钮都在当前页面的属性中返回被定义为“Next page (success or cancel)”的页面 HTML。
Lotus Component Designer 中的其他选项控制了处理后端数据存储时的各方面操作,例如是否创建或更新文档。可以使用包含视图查询的 View 控件来显示后端数据存储的多个文档。
现在将讨论用于处理数据存储的编程方法。服务器端 JavaScript 具有大型类集的访问权限,用于访问后端数据存储。后端数据存储的主要脚本接口是以下这些内置全局变量:
有关语法以及服务器端 JavaScript 所支持的类的详细信息,请参阅随产品提供的“Lotus Component Designer Scripting Reference”帮助。
清单 2 是按钮的 onclick 事件的部分代码。在放置按钮的同一个页面上是绑定到 requestScope 变量 field0 和 field1 的两个编辑框。当用户单击按钮时,将使用这些编辑框所输入的值在数据库中创建新文档。
清单 2. 将文档保存到后端数据存储
ar doc = database.createNewDocument(); doc.setStringValue("/schema1/element0", requestScope.field0); doc.setIntValue("/schema1/element1", requestScope.field1); doc.save(false); context.redirectToPage("page2") |
每行代码的解释如下:
清单 2 中的代码类似于向用户展示新文档的页面,用户填写与后端数据相绑定的字段并单击 Submit 按钮。
清单 3 是从后端数据存储获取文档的示例。同样,页面有两个绑定到 requestScope 变量 field0 和 field1 的字段,并且代码位于按钮 onclick 事件中。在会话期间当用户首次单击按钮时,将从当前数据库中的第一个文档开始填充页面,并将页面发送到浏览器。随后的单击操作将获取包装在最后一个文档之后的下一个文档。
清单 3. 从后端数据存储获取文档
var doc = null; // Initialize and get first doc first time if(sessionScope.dc == null) { sessionScope.dc = database.getAllDocuments(); doc = sessionScope.dc.getFirstDocument(); } else { // or get next doc doc = sessionScope.dc.getNextDocument(); } // At end of collection, get first doc again if(doc == null) { doc = sessionScope.dc.getFirstDocument(); } if(doc == null) { // If 2 nulls, collection is empty requestScope.field1 = "No documents"; } else { // Set fields to element values requestScope.field1 = doc.getStringValue("//element0"); requestScope.field2 = doc.getIntValue("//element1"); } context.redirectToPage("page2") |
|
错误处理和内容帮助
Lotus Component Designer 将捕获服务器端脚本中的基本语法错误。例如,输入以下代码作为按钮的 onclick 事件,其中将 var 错误地写为 va:
va doc = database.getDocumentById(sessionScope.id);
requestScope.x = doc.getCreationDate()
在嵌入编辑器中,将标记出包含错误的代码行。
然而在模式编辑器(窗口中的编辑器,在其中单击 OK 或 Cancel)中并没有标记出错误。直到关闭窗口后才能看到错误,因此很容易造成遗漏。但是如果试图部署包含错误的组件,则会收到消息。
Problems 附签列出了组件中的错误,如图 11 所示。如果双击 Problems 附签中的错误,则转到包含错误的代码,只不过是在 Source 附签中,而不是 Design 附签中。如果觉得这样不是很方便的话,那么打开 Design 附签中的指定资源(例如 page6),并查看指定代码行(例如 line1)。虽然错误消息并不详尽,但是至少知道它的位置。
图 11. Problems 附签
定期或当部署报告错误时检查 Problems 附签是个不错的主意。通过选择菜单中的 Window - Preferences,展开 IBM Lotus Component Designer,选择 Default Options 并选中 Problems 方框来启用该附签。在同一个窗口中,选择“Select which simple action categories to display”下的 All 也是个不错的主意(参见图 12)。
图 12. 附签和简单操作的偏好
同样地,启用 “Show advanced JavaScript classes and methods” 选项。若要实现上述操作,选择菜单中的 Window - Preferences,展开 IBM Lotus Component Designer,选择 Script Editor 并选中“Show advanced JavaScript classes and methods”。否则,当您查看 reference 面板或使用内容帮助时,将得到可用方法的子集。
图 13 展示了位于编辑窗口左侧的 reference 面板,包含了按照库和类排列的所有语法。默认情况下,当键入句点并等待半秒钟或者按下 Ctrl + space,将显示内容帮助。如果位于对象的末端,则显示可用方法的语法。
图 13. 键入全局变量 “database”(DBDatabase 对象)和句点
双击内容帮助或 reference 面板中的语法,将语法复制到编辑器中。但是请注意,所复制的语法仅包含方法名称和空括号,因此必须记得参数或者必须返回内容帮助或 reference 面板。
除了简单语法错误之外,服务器端错误在运行时将本身作为异常或异常行为进行展示。在前面的例子中,假定正确键入了 var,不过遗漏了 database 中的字母 e。它将通过设计时语法检查,但是运行时解释器不认为“databas”是已知对象。默认情况下,运行时将以下页面发送到浏览器:
Script interpreter error, line=1, col=19
Error calling method 'getDocumentById(java.lang.String)':'databas' is not a valid object
try...catch 结构将运行时异常行为更改为 catch 子句中所指定的行为。退出 catch 子句的默认操作与正常退出操作一样,例如将当前页面传递回浏览器以便进行 Full Update 或 Partial Update。清单 4 展示了 try...catch 结构中的上述代码。如果发生异常,则将其文本提交到 msg requestScope 变量。
清单 4. Try...catch 结构
try { var doc = databas.getDocumentById(sessionScope.id); requestScope.x = doc.getCreationDate(); } catch(e) { requestScope.msg = e; } |
清单 5 中的代码展示了如果将 msg requestScope 变量绑定到位于正在处理的页面的底部的 computed 字段,那么运行时可能生成的异常。
清单 5. 运行时生成的异常
set x go p 1 com.ibm.jscript.InterpretException: Script interpreter error, line=2, col=27 Error calling method 'getDocumentById(java.lang.String)': 'databas' is not a valid object |
服务器端异常将转到系统 log 文件。对于 WebSphere Portal,log 文件位于 WebSphere 目录的 PortalServer/log/SystemOut.log 下。应从下往上检查 log 或搜索 portlet 名称。
客户端错误 —— 甚至是简单语法错误 —— 在设计时也不会被报告。而且,在运行时它们往往会悄然无声地失败,除非打开 Java 控制台或调试器。例如,下面的客户端按钮代码并没有关闭字符串常量:
window.alert("hello client world)
但是没有将该行代码作为问题标记出,并且进行部署时没有出现错误。运行时单击按钮时,不会发生任何事情。
若要查看问题,则打开浏览器的 JavaScript 或 Java 控制台,可以使用以下三种菜单选择方法之一来实现操作:Tools - Web Development - JavaScript Console、Tools - JavaScript Console 或 Tools - Sun Java Console。
|
数据类型
JavaScript 从上下文中暗含数据类型 —— 例如,如果清单 6 是 computed 字段的值:
清单 6. computed 字段的值
var s = "This is a string." var x = 99.9; var b = true; s + " " + x + " " + b |
将变量 s 看作是字符串,x 看作是数字,b 看作是布尔值。运行时的字段如下所示:
This is a string. 99.9 true
数据类型可以采用冒号标记来表达,如清单 7 所示。但是该符号是建议性的,对实际类型和值没有任何影响。
清单 7. 冒号标记
var s:string = "This is a string." var x:double = 99.9; var b:boolean = true; s + " " + x + " " + b |
服务器端 JavaScript 支持以下标准库类:String、Number 和 Boolean(以及 Array、Date 和其他标准库类,还有 Math 库)。这些类提供了各种操作那些数据类型的方法。此外,原始数据类型将自动成为对象。例如,允许使用以下代码:
var s = "This is a string."
s.toUpperCase()
它相当于:
var s = new String("This is a string.");
s.toUpperCase()
但是前者更加有效,因为后者在内存中创建了两个字符串。
最后,请注意以下代码也是允许使用的:
"This is a string.".toUpperCase()
数值全部采用 IEEE 双精度格式。在 reference 面板、内容帮助和文档中,可以发现使用冒号标记将数值标注为 int、long 和 double。再次说明,该标记是建议性的,并且那些名称仅表明目的。在双精度格式中,integer 的范围是 2**-53 到 2**53。
|
其他编程功能
下面列出了 Lotus Component Designer 中的其他编程功能。有关其他编程功能的详细描述超出了本文的介绍范围。
Java 对象
服务器端 JavaScript 可以调用服务器上 Java 库中的 Java 类。请参阅 developerWorks 文章“用自定义 Java 代码扩展 IBM Workplace Designer 的功能”,获取进一步的讨论。另外,服务器端 JavaScript 可以调用组件中的静态 Java 类。作为不重要的示例,可以转到 Java perspective 并创建清单 8 中的代码:
清单 8. Java 类的代码
package foo; public class bar { public static String doit() { return "foobar"; } } |
然后可以编写以下 JavaScript(将显示 foobar)作为 computed 字段的值:
return foo.bar.doit()
Log 文件
print 语句是对服务器端 JavaScript 的增强。该语句将写入 Web 服务器的 log 文件中。如前所述,对于 WebSphere Portal,log 文件是 WebSphere 目录中的 PortalServer/log/SystemOut.log。例如,如果编写如下 beforePageLoad 页面事件:
print("<<< Application started >>>")
只要载入页面,那么类似于下列内容的语句将转到 log 文件的结尾部分:
[1/24/07 12:24:31:828 EST] 00000044 SystemOut O <<< Application started >>>
该示例将字符 <<< 放置在 log 文本的开始部分,因此搜索时可以方便地找到条目。请注意 log 文件包含很多条目,还要注意 window.alert 方法是不可用的且在服务器端 JavaScript 中是没有意义的。
调试器
调试器是已增强的远程 Eclipse Java 调试器,用于支持 Lotus Component Designer 和 JavaScript。需要在 Lotus Component Designer 中以及运行所部署组件的服务器上进行某些设置。请参阅产品帮助中的“IBM Lotus Component Designer User Guide”和“Java Development User Guide”。请注意服务器的设置说明中有一处遗漏(参阅 Release Notes),即必须添加 -Denable.jsdebugger=true 作为 JVM 调试参数。
Web 预览
Preview - Web 附签显示了页面在浏览器中的外观图片。可以与该显示进行一些交互,不过对于大部分内容来说,脚本是不起作用的,因为不存在任何服务器运行时。若要测试代码,则必须进行部署。
@functions
服务器端 JavaScript 支持很多模拟 IBM Lotus Domino Designer @functions 的函数。例如,可以输入以下内容作为 computed 字段:
@If(@Contains(@UserName(), "admin"), "Administrator", @UserName())
语法有些不同,即采用逗号代替分号来分隔参数。
脚本库
在每个组件的基础上,可以在客户机和服务器脚本库中保存 JavaScript 语句。实现事件或动态值的脚本可以使用 import 语句来插入库中的语句。库的使用(通常对于普通函数来说)是简单易懂的。请参阅产品帮助中的“IBM Lotus Component Designer User Guide”。
|
结束语
IBM Lotus Component Designer 提供了 JavaScript 解释器作为运行时的一部分。使用内置变量和其他特性对该解释器进行了增强,它可以访问源 Eclipse 环境中的 JavaScript 库和 Java 代码以及运行时服务器上的 Java 归档。JavaScript 库包括用来访问运行时上下文和后端数据存储的类。当用户浏览器向服务器发送请求(通常是通过触发事件来实现)时,将进行脚本处理。另外,使用浏览器中的标准 JavaScript 解释器,可以在客户端进行脚本处理。
我们希望本文能够为您提供有关 Lotus Component Designer 编程功能的指导性介绍。
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者