下图 1、图 2 是我们要实现的基于 Quickr Domino 标准模板定制后的一个新应用。这个应用实现了一个简单的项目管理,功能包括:
整个应用包括两个页面,一是 Overview 界面,另外一个是项目的 Milestone 界面。和常见的 Quickr Domino 应用中对人员的角色管理不同,在这个应用中,我们将用户的角色共分为三类:leader,member 和 stakeholder 。在 Overview 界面里,只有拥有 leader 角色的用户可以对项目的名称,描述以及项目人员进行添加,删除。在 milestone 界面里,也只有 leader 角色的用户可以对项目的里程碑进行添加,修改或删除。
从用户交互模式讲,在 Milestone 里面添加对象的方式和常见的 Quickr 应用也有所不同。在 Quickr 应用中添加或修改对象的常见交互模式是:点击 -> 跳至一个新页面 -> 用户输入新的信息 -> 点击保存 -> 跳回至原有视图。在这个应用里,我们则采用了 in-place-editing 这种在 Web 2.0 中常见的交互模式,从而进一步提升用户体验。
为了实现灵活 Quickr Domino 应用,包括 Web2.0 的交互设计模式,用户角色定制等,我们采用如下的分层架构设计:
在整个架构中,Quickr 应用前端由标准的 Web 技术诸如 HTML、CSS 以及 Javascript. 开发实现。对于服务器端,我们将 Quickr Domino 服务器逻辑上看成两个部分,一部分作为 runtime 的容器,另一部分作为数据的持久化存储。对于服务层,则可以采用 servlet 或 Quickr Domino 相关的技术如 Placebot 或 Domino URL 命令来实现。
Quickr 数据对象本质上是一种包含 Quickr 特定域的 Notes 文档,换句话说,如果我们能够创建的 Notes 文档如果能够包含 Quickr 特定域,则能够被 Quickr 所解析,能够运行在 Quickr Domino 的容器中。
Quickr 文档保留域包含如下表 1:
| 名称 | 功能 |
| h_Type | 0 = Page 1 = Folder 2 = Room 3 = Subroom 5 = Room Type h_Field = Field h_Form. = Form. h_Group = Group h_Member = Member h_Agent = PlaceBot h_Skin = Skin h_SkinGroup = Skin Group |
| Form | H_PageUI ( 固定值 ) |
| h_IsHidden | 是否隐藏: 0 或 1 |
| h_Form | 当前对象要用于显示的 Form. 的 ID |
| h_IsPublished | 是否发布: 1 表示发布 |
| h_IsInToc | 是否出现在 TOC 中 |
| h_Authors | 该文档作者 |
| h_Readers | 该文档读者 |
| h_Name | 文档标题 |
| Folderid | 当前文档属于哪个文件夹 |
以 Milestone 对象为例,下面图 4 给出了这个对象的基本模型。
创建该 Quickr 数据对象的主要代码如下清单 1:
lotus.domino.Document doc = db.createDocument();
// 存储保留域信息
doc.replaceItemValue("h_Type", "0");
doc.replaceItemValue("Form", "h_PageUI");
doc.replaceItemValue("h_IsHidden", "0");
doc.replaceItemValue("h_Form", "");
doc.replaceItemValue("h_DraftVersionUNID", getMSFormId());
doc.replaceItemValue("h_IsInToc", "");
doc.replaceItemValue("h_IsPublished", "1");
doc.replaceItemValue("h_LinkTitle", "");
doc.replaceItemValue("h_LinkURL", "");
doc.replaceItemValue("h_NameIsBanner", "1");
doc.replaceItemValue("h_PageType", "");
doc.replaceItemValue("h_PublishedVersionUNID", "");
doc.replaceItemValue("h_RevNum", "");
doc.replaceItemValue("h_SetEditScene", "h_StdPageEdit");
doc.replaceItemValue("h_SetReadScene", "h_StdPageRead");
doc.replaceItemValue("h_SystemName", "");
doc.replaceItemValue("h_TaskStatus", "");
doc.replaceItemValue("h_TextAbstract", "");
doc.replaceItemValue("PageBody", "");
doc.replaceItemValue("h_Name", title);
// 存储对象信息
doc.replaceItemValue("title", title);
doc.replaceItemValue("duedate", title);
doc.replaceItemValue("description",description);
// 存储权限信息
…
doc.save(true);
|
注意代码中 h_Form. 的赋值是该数据对象对应的 Form. 的 ID,我们利用函数 getMSFormId() 动态获取 milestone 这个 form. 的 id:,核心代码如下
private String getMSFormId(){
String id = "";
try{
lotus.domino.View view = db.getView("h_Forms");
lotus.domino.Document doc = view.getFirstDocument();
boolean flag = true;
while(doc!=null && flag){
if(doc.getItemValueString("h_Name").equalsIgnoreCase("pmMilestone")){
id = doc.getUniversalID();
flag = false;
}
doc = view.getNextDocument(doc);
}
}
catch(Exception e){
e.printStackTrace();
}
return id;
}
|
在 Quickr 定制开发中,如果开发人员希望按照任意特定的方式访问自创对象,比如按照某个分类来显示和搜索对象,则需要创建相应的视图。
在 Domino 开发中创建视图,一般是采用 Domino Designer 在数据库文件中添加视图:设置名称,分类,视图段落,选择条件等。在 Quickr 应用中,由于默认用户无法打开 main.nsf 数据库,需要开发人员将该数据库拷贝到本地文件夹,然后进行编辑,创建视图的操作。对于频繁编辑和部署的情况下,该方法很容易导致 Quickr 数据库数据丢失或其他异常错误,并且,这种方法对于最终部署也不灵活。结合 Quickr 的 PlaceBots,采用如下的方法,可以实现在 Quickr Domino 应用中动态创建视图,简化开发和最终部署过程。
整个方法如下:
select p_form= "pmProject" |
Dim session As New NotesSession
Dim db As NotesDatabase
Dim exporter As NotesDXLExporter
Dim output1 As String
Dim filenum As Integer
Msgbox "export design elements"
Set db = session.CurrentDatabase
Set exporter = session.CreateDXLExporter
output1 = exporter.Export(db)
filenum = Freefile
Open "c:\\main.dxl" For Output As filenum
Write #filenum, output1
Close filenum
|
lotus.domino.View view = db.getView();
if(view!=null){
view.remove();
}
InputStream io = getClass().getResourceAsStream("/vwProject.xml");
lotus.domino.Stream stream = ss.createStream();
stream.setContents(io);
if( (stream.getBytes() >0)) {
lotus.domino.DxlImporter importer = ss.createDxlImporter();
importer.setDesignImportOption(lotus.domino.DxlImporter.DXLIMPORTOPTION_CREATE);
importer.importDxl(stream, db);
}
io.close();
stream.close();
|
只要在 Quickr 应用中通过 customize 面板利用该文件创建一个 PlaceBot,然后运行这个 PlaceBot,就可以在相应的应用中创建出我们所需要的视图了。
在 Quickr 的简单定制开发中,通常只需要定义对象,然后利用 Quickr 所默认的展示方式(列表等)来显示。这种方式简单,但是数据显示的方式单一,另外对数据的添加修改的交互模式也会很固定。因此对于示例中的 Milestone 界面而言,并不适用。如果我们希望按照自己的方式组织和显示数据,并提供灵活的交互模式,例如在我们的示例中的 milestone 界面中,用表格来显示数据,用 in-place-editing 来动态修改数据,则需要采用更灵活的方式来实现。
以显示 milestone 列表的界面为例,这个过程如下:
以下代码展现的是 HML 页面中显示 milestone 列表的部分:
清单 5. 用于显示 milestone 列表的 HTML 页面
|
该页面 load 的时候,会执行如下 JS 代码:
YAHOO.util.Event.addListener(window, "load", function() {
window.setTimeout(function() {
try {
……
milestoneView.loadTable();
……
}
catch (e) {
alert(e);
}
}, 100);
});
|
上述代码中 milestoneView.loadTable() 函数则可以通过 Ajax 调用后台数据,给 Table 的单元格赋值并显示。这样,我们就可以按照自己需要的方式灵活显示 milestone 列表。
Quickr 默认提供了五种用户群组:Readers、Authors、Editors、Managers、SuperUsers,和四种角色:h_Editors、h_Managers、h_Members、h_SuperUser 。其中,h_Members 表示该用户是当前场所的用户。每种用户权限对应关系如下:
| 用户群组 | Notes ACL | Quickr 角色 | 权限说明 |
| Readers | Reader | h_Members | 只读权限 |
| Authors | Author | h_Members | 读和编辑自己创建文档 |
| Editors | Author | h_Members、h_Editors | 读、编辑自己和其他人所创建的文档 |
| Managers | Manager | h_Members、h_Managers | 读、编辑自己和其他人创建的问题;定制场所;部分用户管理权限 |
| SuperUsers | Manager | h_Members、h_Managers、h_SuperUser | 读、编辑自己和其他人创建的问题;定制场所;管理所有用户 |
如果希望整个应用中的角色更加细化,或额外引入另外的角色并通过自定义的 UI 来进行用户管理(如图 6),我们可以通过 Domino ACL 类来添加这些角色。
在本例中,我们自定义了三类角色,分别称之为 Leader, Member, Stakeholder,与 Quickr 默认的用户组并不直接对应,因此我们可以通过 Domino ACL 类来添加这些角色。角色定制主要涉及角色的添加,以及将用户与角色相关联。代码清单 8 显示在 Quickr Domino 应用中动态添加了一个 Leader 角色,代码清单 9 则显示了如何将一个用户设置为 Leader 角色。
lotus.domino.ACL acl = db.getACL();
Vector roles = acl.getRoles();
if(!roles.contains("Leader")){
acl.addRole("Leader");
}acl.save();
|
lotus.domino.ACL acl = db.getACL();
lotus.domino.ACLEntry entry = acl.getEntry(currentuser);
if(entry!=null){
Vector role = entry.getRoles();
if(!role.contains("Leader")){
Vector dbroles = acl.getRoles();
if(!dbroles.contains("Leader")){
acl.addRole(Util.Role_Leader);
}
entry.enableRole(Util.Role_Leader);
acl.save();
}}
|
用户管理,包括用户的添加删除等也是在一个 Quickr Domino 应用中常见一类定制问题。这类问题的解决主要利用 QPTool 来访问 Quickr API,并结合 XML 操作实现。调用 QPTool 的核心代码如下:
QPAPI.init(); QPAPI.process(inFilename, outFilename); QPAPI.term(); |
其中 inFilename 是指用于输入的 XML 文件,outFilename 指的是输出 XML 文件,通过分析后者可以判断相应操作是否成功。下面图 7 给出了一个用于创建本地用户的 XML 文件的示例。
|
级别: 高级
张 强 (zhqiang@cn.ibm.com), 高级研发工程师, IBM 中国研究院
李 峰 (lifbjcrl@cn.ibm.com), 实习生
李 起成 (liqic@cn.ibm.com), 高级研发工程师, IBM 中国研究院
刘 嘉 (liujcrl@cn.ibm.com), 实习生
2008 年 9 月 11 日
本文通过一个实例介绍了一种灵活定制开发 Quickr Domino 模板应用的方法。采用这种方法,可以提供灵活的用户交互模式,自定义的信息展现方式,并根据需要定制用户角色和访问控制。
Lotus Quickr 是 IBM 的一款用于协同内容管理的工作平台,并与产品一起提供了一些开箱即用的模板,包括标准模板,blog 模板 , wiki 模板等。针对不同的协作需求,Quickr 允许用户在标准模板的基础上进行定制,从而配置出符合用户需求的新应用。利用 Quickr 内在的模板机制还可以将这些定制后的应用实例进一步转变成新的应用模板被其他人员重复使用,从而提高工作效率。 Quickr 所允许定制的范围很广,从仅由管理员以配置的形式修改和定制,包括对模板的主题(theme)的修改,模板中不同模块之间位置的调整等,到由开发人员参与的以编程的方式实现完全灵活的自由定制等。 Quickr 目前共有两种部署选择,一类是 Quickr for Domino,另一类是 Quickr for J2EE 。本文从一个实例出发,对深入定制开发 Quickr Domino 模板的一些关键问题给出相应的介绍。
|
下图 1、图 2 是我们要实现的基于 Quickr Domino 标准模板定制后的一个新应用。这个应用实现了一个简单的项目管理,功能包括:
整个应用包括两个页面,一是 Overview 界面,另外一个是项目的 Milestone 界面。和常见的 Quickr Domino 应用中对人员的角色管理不同,在这个应用中,我们将用户的角色共分为三类:leader,member 和 stakeholder 。在 Overview 界面里,只有拥有 leader 角色的用户可以对项目的名称,描述以及项目人员进行添加,删除。在 milestone 界面里,也只有 leader 角色的用户可以对项目的里程碑进行添加,修改或删除。
从用户交互模式讲,在 Milestone 里面添加对象的方式和常见的 Quickr 应用也有所不同。在 Quickr 应用中添加或修改对象的常见交互模式是:点击 -> 跳至一个新页面 -> 用户输入新的信息 -> 点击保存 -> 跳回至原有视图。在这个应用里,我们则采用了 in-place-editing 这种在 Web 2.0 中常见的交互模式,从而进一步提升用户体验。
|
为了实现灵活 Quickr Domino 应用,包括 Web2.0 的交互设计模式,用户角色定制等,我们采用如下的分层架构设计:
在整个架构中,Quickr 应用前端由标准的 Web 技术诸如 HTML、CSS 以及 Javascript. 开发实现。对于服务器端,我们将 Quickr Domino 服务器逻辑上看成两个部分,一部分作为 runtime 的容器,另一部分作为数据的持久化存储。对于服务层,则可以采用 servlet 或 Quickr Domino 相关的技术如 Placebot 或 Domino URL 命令来实现。
|
Quickr 数据对象本质上是一种包含 Quickr 特定域的 Notes 文档,换句话说,如果我们能够创建的 Notes 文档如果能够包含 Quickr 特定域,则能够被 Quickr 所解析,能够运行在 Quickr Domino 的容器中。
Quickr 文档保留域包含如下表 1:
| 名称 | 功能 |
| h_Type | 0 = Page 1 = Folder 2 = Room 3 = Subroom 5 = Room Type h_Field = Field h_Form. = Form. h_Group = Group h_Member = Member h_Agent = PlaceBot h_Skin = Skin h_SkinGroup = Skin Group |
| Form | H_PageUI ( 固定值 ) |
| h_IsHidden | 是否隐藏: 0 或 1 |
| h_Form | 当前对象要用于显示的 Form. 的 ID |
| h_IsPublished | 是否发布: 1 表示发布 |
| h_IsInToc | 是否出现在 TOC 中 |
| h_Authors | 该文档作者 |
| h_Readers | 该文档读者 |
| h_Name | 文档标题 |
| Folderid | 当前文档属于哪个文件夹 |
以 Milestone 对象为例,下面图 4 给出了这个对象的基本模型。
创建该 Quickr 数据对象的主要代码如下清单 1:
lotus.domino.Document doc = db.createDocument();
// 存储保留域信息
doc.replaceItemValue("h_Type", "0");
doc.replaceItemValue("Form", "h_PageUI");
doc.replaceItemValue("h_IsHidden", "0");
doc.replaceItemValue("h_Form", "");
doc.replaceItemValue("h_DraftVersionUNID", getMSFormId());
doc.replaceItemValue("h_IsInToc", "");
doc.replaceItemValue("h_IsPublished", "1");
doc.replaceItemValue("h_LinkTitle", "");
doc.replaceItemValue("h_LinkURL", "");
doc.replaceItemValue("h_NameIsBanner", "1");
doc.replaceItemValue("h_PageType", "");
doc.replaceItemValue("h_PublishedVersionUNID", "");
doc.replaceItemValue("h_RevNum", "");
doc.replaceItemValue("h_SetEditScene", "h_StdPageEdit");
doc.replaceItemValue("h_SetReadScene", "h_StdPageRead");
doc.replaceItemValue("h_SystemName", "");
doc.replaceItemValue("h_TaskStatus", "");
doc.replaceItemValue("h_TextAbstract", "");
doc.replaceItemValue("PageBody", "");
doc.replaceItemValue("h_Name", title);
// 存储对象信息
doc.replaceItemValue("title", title);
doc.replaceItemValue("duedate", title);
doc.replaceItemValue("description",description);
// 存储权限信息
…
doc.save(true);
|
注意代码中 h_Form. 的赋值是该数据对象对应的 Form. 的 ID,我们利用函数 getMSFormId() 动态获取 milestone 这个 form. 的 id:,核心代码如下
private String getMSFormId(){
String id = "";
try{
lotus.domino.View view = db.getView("h_Forms");
lotus.domino.Document doc = view.getFirstDocument();
boolean flag = true;
while(doc!=null && flag){
if(doc.getItemValueString("h_Name").equalsIgnoreCase("pmMilestone")){
id = doc.getUniversalID();
flag = false;
}
doc = view.getNextDocument(doc);
}
}
catch(Exception e){
e.printStackTrace();
}
return id;
}
|
|
在 Quickr 定制开发中,如果开发人员希望按照任意特定的方式访问自创对象,比如按照某个分类来显示和搜索对象,则需要创建相应的视图。
在 Domino 开发中创建视图,一般是采用 Domino Designer 在数据库文件中添加视图:设置名称,分类,视图段落,选择条件等。在 Quickr 应用中,由于默认用户无法打开 main.nsf 数据库,需要开发人员将该数据库拷贝到本地文件夹,然后进行编辑,创建视图的操作。对于频繁编辑和部署的情况下,该方法很容易导致 Quickr 数据库数据丢失或其他异常错误,并且,这种方法对于最终部署也不灵活。结合 Quickr 的 PlaceBots,采用如下的方法,可以实现在 Quickr Domino 应用中动态创建视图,简化开发和最终部署过程。
整个方法如下:
select p_form= "pmProject" |
Dim session As New NotesSession
Dim db As NotesDatabase
Dim exporter As NotesDXLExporter
Dim output1 As String
Dim filenum As Integer
Msgbox "export design elements"
Set db = session.CurrentDatabase
Set exporter = session.CreateDXLExporter
output1 = exporter.Export(db)
filenum = Freefile
Open "c:\\main.dxl" For Output As filenum
Write #filenum, output1
Close filenum
|
lotus.domino.View view = db.getView();
if(view!=null){
view.remove();
}
InputStream io = getClass().getResourceAsStream("/vwProject.xml");
lotus.domino.Stream stream = ss.createStream();
stream.setContents(io);
if( (stream.getBytes() >0)) {
lotus.domino.DxlImporter importer = ss.createDxlImporter();
importer.setDesignImportOption(lotus.domino.DxlImporter.DXLIMPORTOPTION_CREATE);
importer.importDxl(stream, db);
}
io.close();
stream.close();
|
只要在 Quickr 应用中通过 customize 面板利用该文件创建一个 PlaceBot,然后运行这个 PlaceBot,就可以在相应的应用中创建出我们所需要的视图了。
|
在 Quickr 的简单定制开发中,通常只需要定义对象,然后利用 Quickr 所默认的展示方式(列表等)来显示。这种方式简单,但是数据显示的方式单一,另外对数据的添加修改的交互模式也会很固定。因此对于示例中的 Milestone 界面而言,并不适用。如果我们希望按照自己的方式组织和显示数据,并提供灵活的交互模式,例如在我们的示例中的 milestone 界面中,用表格来显示数据,用 in-place-editing 来动态修改数据,则需要采用更灵活的方式来实现。
以显示 milestone 列表的界面为例,这个过程如下:
以下代码展现的是 HML 页面中显示 milestone 列表的部分:
清单 5. 用于显示 milestone 列表的 HTML 页面
|
该页面 load 的时候,会执行如下 JS 代码:
YAHOO.util.Event.addListener(window, "load", function() {
window.setTimeout(function() {
try {
……
milestoneView.loadTable();
……
}
catch (e) {
alert(e);
}
}, 100);
});
|
上述代码中 milestoneView.loadTable() 函数则可以通过 Ajax 调用后台数据,给 Table 的单元格赋值并显示。这样,我们就可以按照自己需要的方式灵活显示 milestone 列表。
|
Quickr 默认提供了五种用户群组:Readers、Authors、Editors、Managers、SuperUsers,和四种角色:h_Editors、h_Managers、h_Members、h_SuperUser 。其中,h_Members 表示该用户是当前场所的用户。每种用户权限对应关系如下:
| 用户群组 | Notes ACL | Quickr 角色 | 权限说明 |
| Readers | Reader | h_Members | 只读权限 |
| Authors | Author | h_Members | 读和编辑自己创建文档 |
| Editors | Author | h_Members、h_Editors | 读、编辑自己和其他人所创建的文档 |
| Managers | Manager | h_Members、h_Managers | 读、编辑自己和其他人创建的问题;定制场所;部分用户管理权限 |
| SuperUsers | Manager | h_Members、h_Managers、h_SuperUser | 读、编辑自己和其他人创建的问题;定制场所;管理所有用户 |
如果希望整个应用中的角色更加细化,或额外引入另外的角色并通过自定义的 UI 来进行用户管理(如图 6),我们可以通过 Domino ACL 类来添加这些角色。
在本例中,我们自定义了三类角色,分别称之为 Leader, Member, Stakeholder,与 Quickr 默认的用户组并不直接对应,因此我们可以通过 Domino ACL 类来添加这些角色。角色定制主要涉及角色的添加,以及将用户与角色相关联。代码清单 8 显示在 Quickr Domino 应用中动态添加了一个 Leader 角色,代码清单 9 则显示了如何将一个用户设置为 Leader 角色。
lotus.domino.ACL acl = db.getACL();
Vector roles = acl.getRoles();
if(!roles.contains("Leader")){
acl.addRole("Leader");
}acl.save();
|
lotus.domino.ACL acl = db.getACL();
lotus.domino.ACLEntry entry = acl.getEntry(currentuser);
if(entry!=null){
Vector role = entry.getRoles();
if(!role.contains("Leader")){
Vector dbroles = acl.getRoles();
if(!dbroles.contains("Leader")){
acl.addRole(Util.Role_Leader);
}
entry.enableRole(Util.Role_Leader);
acl.save();
}}
|
用户管理,包括用户的添加删除等也是在一个 Quickr Domino 应用中常见一类定制问题。这类问题的解决主要利用 QPTool 来访问 Quickr API,并结合 XML 操作实现。调用 QPTool 的核心代码如下:
QPAPI.init(); QPAPI.process(inFilename, outFilename); QPAPI.term(); |
其中 inFilename 是指用于输入的 XML 文件,outFilename 指的是输出 XML 文件,通过分析后者可以判断相应操作是否成功。下面图 7 给出了一个用于创建本地用户的 XML 文件的示例。
|
与角色定义相关的还有访问权限控制,由于 Quickr 数据文档从本质上说属于 Notes 文档,遵循着 Domino 的存取控制原则,即基于读者域 [h_Readers] 和作者域 [h_Authors] 的存取访问控制。因此只要通过对一个数据对象的这两个域进行设置,即可实现访问控制的定制。
在本例中,对于 Milestone 对象,通过清单 11 所示代码可以 milestone 能被应用中的 leader 及 h_SuperUser 角色的用户去编辑,而 member 及 stakeholder 角色的用户则只能查看
lotus.domino.Item iAuthor = doc.getFirstItem("h_Authors");
Vector vL = new Vector();
vL.add("[h_SuperUser]");
vL.add("[Leader]");
iAuthor = doc.replaceItemValue("h_Authors", vL); iAuthor.setAuthors(true);
lotus.domino.Item iReader = doc.getFirstItem("h_Readers");
Vector vA = new Vector();
vA.add("[Leader]");
vA.add("[Member]");
vA.add("[Stakeholder]");
iReader = doc.replaceItemValue("h_Readers", vA);
iReader.setReaders(true);
|
采用前述架构设计及开发思路,最后我们可以得到相应不同类型的代码。最后部署时,通常的做法是将与前端显示相关的代码中的资源文件,如 Img,CSS,以及 Javascript. 文件剥离后放在 Quickr 服务器的 Data/Domino/HTML 路径下。 然后在一个应用中利用 customize 面板导入创建相应的 Form,并在恰当的位置上添加该 Form. 的实例。将 Servlet 导出并部署在 Quickr Domino 服务器的 Data/Domino/Servlet 路径下,配置相应 Data 目录下 servlets.properties 文件以及在 Domino Administrator 中配置 servlet 文件路径。如果使用了 placebot,也应该在应用的 customize 面板中导入相应的 placebot,从而完成整个 Quickr 应用的定制开发。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/14751907/viewspace-586496/ ,如需转载,请注明出处,否则将追究法律责任。