使用 Dojo TreeGrid 管理 WebSphere Process Server 工作流为数据创建 Web 2.0 风格的 UI

简介

如果您正在使用 IBM WebSphere Process Server,那么肯定了解它的许多特性。在本文中,学习如何使用强大的 Dojo TreeWidget 来管理 WebSphere Process Server 中的流程。本文通过一个例子探索如何处理分层数据,并通过创建 Web 2.0 风格的用户界面(UI)来管理数据。

您还可以通过下面的 下载列表 下载本文的样例代码。

回页首

Dojo TreeGrid

dojox.Grid 是 Dojo 小部件的重要组件之一,它允许您轻松地操作和呈现远程数据和来自 web 页面的数据。TreeGrid 同时具备 dijit.Tree 和 dojox.Grid 的优点:它能够像 dijit.Tree 一样处理分层数据结构,也能够像 dojox.Grid 一样呈现数据。与 dojox.Grid 一样,TreeGrid 可以通过两种方式来构建 TreeGrid:声明式或编程式。图 1 显示了一个简单的 TreeGrid


图 1. 简单的 Dojo TreeGrid
这个简单的 Dojo TreeGrid 包含以下标题:Player、Session、Game、Quarter、Points、Rebounds、Assists 和 Time Played

架构

TreeGrid 采用 Model-View-Controller (MVC) 设计模式,如下所示。


图 2. TreeGrid 的架构
这个图显示 TreeGrid 的架构,包括 Model 和 View

TreeGrid 维护一个数据模型,该模型管理 TreeGrid 用于通过 UI 呈现数据的原始数据。TreeGrid 能够通过 dojo.data.api 提供的 API 访问数据存储以获取或处理数据,这是访问 Dojo 中的数据的标准方式。Dojo 提供许多以实现了 dojo.data.api 的 API 的数据存储,包括:ItemFileReadStoreItemFileWriteStore(用户可以使用它们读取和处理 JSON 数据);用于其它数据格式的 XmlStore、CsvStore 和 OpmlStore;以及其他数据存储。表 1 列出了所有数据存储。


表 1. 实现的 Dojo 数据存储
数据存储 作用
dojo.data.ItemFileReadStore 用于 JSON 数据的只读数据存储
dojo.data.ItemFileWriteStore 用于 JSON 数据的读/写数据存储
dojox.data.CsvStore 用于 CVS 数据的只读数据存储
dojox.data.OpmlStore 用于 Outline Processor Markup Language (OPML) 数据的只读数据存储
dojox.data.HtmlTableStore 用于 HTML 表数据的只读数据存储
dojox.data.XmlStore 用于 XML 数据的读/写数据存储
dojox.data.FlickrStore 用于 flickr.com 查询数据的只读数据存储。web 服务数据存储的杰出例子。
dojox.data.FlickrRestStore dojox.data.FlickrStore 的高级版本
dojox.data.QueryReadStore 用于来自服务器端的 JSON 数据的只读数据存储
dojox.data.AtomReadStore 用于 Atom XML 数据的只读数据存储

这是关于获取数据和正确地向用户呈现应用程序数据的视图。您可以通过定义 structure 参数定制 TreeGrid 的视图。有两种不同的 TreeGrid 视图。列式 TreeGrid 的布局更像典型的树风格,如图 3 所示。该视图在为 TreeGrid 指定 TreeModel 时创建。


图 3. 列式 TreeGrid
显示数据列的 TreeGrid,包含以下标题:Name、Population 和 Timezone

另一种 TreeGrid 视图是嵌套的 TreeGrid,它由嵌套的 structure 定义,如下所示。


图 4. 嵌套的 TreeGrid
显示嵌套数据的 TreeGrid,其标题与图 1 中的一样

控制器响应并处理事件。TreeGrid 继承自 dojo.grid.DataGrid,因此所有事件处理程序都与这里应用的 DataGrid 相关。您还可以通过将函数绑定到网格事件来定制事件处理程序,从而更加高效地控制数据和行为。

用法

可以在 HTML 中以声明的方式或以编程的方式定义 TreeGridTreeGrid 的大部分属性都是可选的,但 structurestore(或 treeModel,如果您需要创建列式 TreeGrid)除外。 Structure 是定义 TreeGrid 视图布局的 JSON 对象。如果在 HTML 中以声明的方式定义了 TreeGrid,该对象还可以通过标记表示出来。store 的值应该是 JavaScript 变量的名称,而该变量包含用于为 TreeGrid 获取数据的储存对象。清单 1 显示了以声明的方式定义的 TreeGrid 的定义。


清单 1. 样例 TreeGrid 定义
				 <table dojoType="dojox.grid.TreeGrid" store="storeId">   <thead>     <tr>       <th field="field1" width="200px">Field 1</th>       <th field="childAttr">         <table>           <thead>             <tr>               <th field="cField1" width="200px">Child Field 1</th>               <th field="cField2" width="200px">Child Field 2</th>             </tr>           </thead>         </table>       </th>     </tr>   </thead> </table> 

回页首

构建 Process Server 代理

WebSphere Process Server 提供各种编程接口来管理流程,比如 EJB、Web Service、JMS 和 REST。不过,只有 EJB API 提供完整的函数集。要利用 EJB API 的威力,您需要构建一个将 TreeGrid 连接到 Process Server 的代理。

创建样例流程应用程序

第一步是创建名为 SimpleSolution 的集成解决方案,它仅包含一个模块。为了让样例保持简单,我们构建只有一个接收/回复和一个人工任务的流程。人工任务只负责输入一个任意值作为回复操作的返回值。图 5 显示了该流程的定义。记住,您可以通过下面的 下载列表 下载本文使用的样例代码。


图 5. 流程定义
包含 Interface 和 Operations 部分的流程定义

使用 Process Server API 管理流程

首先假设您使用的 IDE 为 WebSphere Integration Developer,以及代理应用程序运行在 Process Server 上(否则,您需要将 Process Server 客户端安装在您的服务器上)。这个例子首先创建一个动态 web 项目。您将看到会自动地引用所需的 Process Server 库。


图 6. SimpleBridge 动态 web 项目
SimpleBridge 的目录结构

Process Server 提供丰富的 API 来处理流程。您需要找到 EJB 服务的位置才能够访问这些 API。清单 2 显示了如何访问业务流程管理器服务。


清单 2. 访问业务流程管理器服务
				 // Obtain the default initial JNDI context InitialContext initialContext = new InitialContext(); // Lookup the remote home interface of the BusinessFlowManager bean Object result = initialContext.lookup("com/ibm/bpe/api/BusinessFlowManagerHome"); // Convert the lookup result to the proper type BusinessFlowManagerHome processHome =    (BusinessFlowManagerHome) javax.rmi.PortableRemoteObject.narrow(result,        BusinessFlowManagerHome.class); BusinessFlowManager processManager = processHome.create(); 

在获得了 BusinessWorkflowManager 的实例之后,就可以创建、处理和完成流程了。您可以使用清单 3 中的代码来访问流程模板。


清单 3. 访问流程模板
				 ProcessTemplateData[] processTemplates =    processManager.queryProcessTemplates(null, null, 0, null); for(int i = 0; i < processTemplates.length; i++){   //Do something to the process template } 

使用清单 4 中的代码创建一个带有流程模板的流程实例,并为初始输入参数指定一个值。


清单 4. 创建流程实例
				 ProcessTemplateData template = processManager.getProcessTemplate(templateName); if(template != null){   // create a message for the single starting receive activity   ClientObjectWrapper input = processManager.createMessage(template.getID(),      template.getInputMessageTypeName());   DataObject myMessage = null;   if (input.getObject() != null && input.getObject() instanceof DataObject) {     myMessage = (DataObject) input.getObject();     // set the strings in the message, for example, a parameter named “input”     myMessage.setString("input", initialString);   }   // start the process   PIID piid = processManager.initiate(template.getName(), instanceName, input); } 

完成以上步骤之后,转到 http://localhost:9080/bpc 并单击 Started By Me。这时可以看到刚才创建的实例,如下所示。


图 7. 样例流程实例
'Process Instances Started By Me' 界面的屏幕截图,显示列表中的 SimpleProcess

转到 My To-dos 可以看到一个需要处理的人工任务,如图 8 所示。这是在流程定义中定义的人工任务。


图 8. 需要处理的人工任务
'My To-dos' 界面的屏幕截图,显示需要处理的 SimpleTask

要处理人工任务,您必须先找到它。可以使用流程管理器的 query 方法来获取所需的任务,如清单 5 所示。


清单 5. 获取 To-do 任务
				 QueryResultSet result = processManager.query(     "ACTIVITY.AIID, TASK.NAME",      "ACTIVITY.STATE = ACTIVITY.STATE.STATE_READY AND " +     "ACTIVITY.KIND = ACTIVITY.KIND.KIND_STAFF AND " +     "WORK_ITEM.REASON = WORK_ITEM.REASON.REASON_POTENTIAL_OWNER AND " +     "PROCESS_INSTANCE.NAME = '" + entity.getAttributeValue("NAME") + "'",     (String)null, (Integer)null, (TimeZone)null);  for(int k = 0; k < result.size(); k++){   // Get the AIID and the name of the task   result.next();   out.print("{id:'" + result.getOID(1) + "',");   out.print("label:'" + result.getString(2) + "'}"); } 

要处理该任务,必须先声明它。只有通过声明它才能获取输入参数的值并完成任务。清单 6 显示了如何声明任务并获取输入参数的值。


清单 6. 声明任务并获取输入参数的值
				 ClientObjectWrapper input = processManager.claim(aiid); DataObject activityInput = null; if (input.getObject() != null && input.getObject() instanceof DataObject) {   activityInput = (DataObject) input.getObject();   String inputStr = activityInput.getString("input"); } processManager.cancelClaim(aiid); 

至此,您可以处理任务并完成它了。清单 7 显示了一个例子。


清单 7. 处理任务
				 ActivityInstanceData activity = processManager.getActivityInstance(aiid); ClientObjectWrapper output = processManager.createMessage(aiid,    activity.getOutputMessageTypeName()); DataObject myMessage = null ; if(output.getObject() != null && output.getObject() instanceof DataObject) {   myMessage = (DataObject) output.getObject();   // set the parts in your message, for example, an order number   myMessage.setString("output", msg); } //complete the activity processManager.complete(aiid, output); Define the data exchange format 

JSON 无疑是最佳的数据转换格式。您需要以 JSON 对象树的方式返回数据,这样 TreeGrid 才能够接收它。这种数据的结构非常直观。Template 是与模板相关联的流程实例的父节点;to-do 任务是流程实例的子节点。


清单 8. 数据格式
				 {   identifier: "id",   label: "label",   items: [{     id: "1",     label: "Template 1",     instances: [{       id: "2",       label: "Instance 1",       tasks: [{         id: "3",         label: "ToDo 1",       },       {         id: "4",         label: "ToDo 2",       }]     }]   } } 

回页首

使用 Dojo TreeGrid 管理流程

在设置好 WebSphere Process Server 之后,可以创建一个 TreeGrid 来接收和呈现 Process Server 提供的流程数据。可以为 TreeGrid 添加一些控件来管理这些流程。

连接到流程代理

如前所述,<table> 标记中的 store 属性(参见 清单 1)表明您希望使用哪个 DataStore 来获取数据。由于需要连接到流程代理,我们通过一个例子来解释如何进行连接。JsonRestStore 是一个 Dojo 数据存储接口,它连接到支持以 GET、PUT、POST 和 DELETE 方式进行读写的 JSON HTTP/REST web 储存服务。还可以在用 HTML 标记定义 JsonRestStore,如清单 9 所示。


清单 9. JsonRestStore 声明
				 <span dojoType="dojox.data.JsonRestStore"     jsId="jsonStore" target="SimpleSolution/ShowAll/"> </span> 

target 属性表明服务器端数据源的目标 URL。它假设用户在相同的域中,因此 target 的值应该是一个相对路径。jsId 是该储存仓库的标识符。

创建 TreeGrid

在这个例子中,在 HTML 中使用 <table> 标记以声明的方式定义 TreeGrid。嵌套的 <th> 标记定义表中的列。清单 10 显示 TreeGrid 的声明。该结构对于上面的数据格式。


清单 10. TreeGrid 声明
				 <table dojoType="dojox.grid.TreeGrid" class="grid" autoHeight="true" jsId="grid"     store="jsonStore" rowSelector="true" defaultOpen=true>   <thead>     <tr>       <th field="label" width="20em" formatter="processSummary">Process Template</th>       <th field="instances" aggregate="sum">         <table>           <thead>             <tr>               <th field="label" width="20em" formatter="instanceSummary">Instance</th>               <th field="tasks" aggregate="sum">                 <table>                   <thead>                     <tr>                       <th field="label" width="25em" formatter="taskSummary">Tasks</th>                       <th field="status" width="20em">Status</th>                     </tr>                   </thead>                 </table>                </th>              </tr>            </thead>          </table>       </tr>   </thead> </table> 

至此,您得到了一个 TreeGrid,如下所示。


图 9. 显示流程数据的 TreeGrid
包含以下标题的 TreeGrid:Process Template、Instance、Tasks、Description 和 Status

这个 TreeGrid 非常简单,但我们只完成了一半工作。下一步是给 TreeGrid 添加一些控件,使其能够与 WebSphere Process Server 通信以及处理流程。

与 WebSphere Process Server 通信

这个小节将给 TreeGrid 添加一些控件。从 Dojo 1.4 开始可以通过格式化程序(在网格单元格中显示返回值的 JavaScript 函数)将小部件添加到网格单元格。格式化程序还可以帮助格式化 TreeGrid 中的汇总单元格。

将通过格式化程序将两种类型的小部件添加到 TreeGrid,如清单 11 所示:

  • dijit.form.ComboBox,用于改变任务状态
  • dijit.form.Button,用于提交请求

清单 11. 控制器格式化程序
				 // create an object to save all these ComboBox var comboObj = {}; var fmtStatus = function(value, idx, treepath){   // summary:   //    format the cell to a comboBox Widget   // value: string   //    the attribute value of this cell   // idx: integer   //    row index, it would be negative if the cell is header cell or summary cell   if(idx >= 0) {     // get the identifier     var id = jsonStore.getIdentity(grid.getItem(treepath));     comboObj[id] = new dijit.form.ComboBox({       store: comboStore,        searchAttr:"status"     });     comboObj[id].setValue(value);     return comboObj[id];   }else{     // for summary cell     return "";   } } 		 var fmtSubmit = function(value, idx){   if(idx >= 0){     return new dijit.form.Button({       label: "submit",        onClick: dojo.hitch(null, "submit", value)});   }else{     return "";   } } 

您需要将格式化程序添加到 TreeGrid 的列,如下所示。


清单 12. 将格式化程序添加到列
				 <th field="status" width="20em" formatter=” fmtStatus”>Status</th> <th field="id" width="20em" formatter=” fmtSubmit”>Action</th> 

现在,TreeGrid 应该类似于图 10。


图 10. 带控制器的 TreeGrid
包含以下标题的 TreeGrid:Process Template、Instance、Tasks、Description、Status 和 Submit

可以引入 Dojo Ajax IO 函数 dojo.xhr* 来与 WebSphere Process Server 进行通信。单击 Submit 将向服务器发送 XHR 请求以提交新的状态。在收到服务器的响应之后,网格将进行刷新以正确地反映流程,如清单 13 所示。


清单 13. 与 WebSphere Process Server 通信
				 var submit = function(id){	   var status = comboObj[id].getValue();     dojo.xhrPost({       url: "SimpleSolution/" + status + "/" + id,       load: function(data){         if(data === "successful"){           grid.update();         }else{           console.warn("operation failed:", data);         }       },       error: function(error){         console.err(error);       }   }); } 

现在,每次单击 Submit 都会向 WebSphere Process Server 发送一个 XHR 请求。您将能够通过服务响应知道操作是否成功。

回页首

结束语

在本文中,您学习了如何使用 Dojo TreeGrid 处理 WebSphere Process Server 的流程。TreeGrid 本质上能够处理分层数据结构。您可以根据特定的应用程序需求定制 TreeGrid,从而得到便于操作数据的 Web 2.0 风格的 UI。


回页首

下载

描述 名字 大小 下载方法
本文样例代码 code.zip 26KB HTTP

关于下载方法的信息


参考资料

学习

你可能感兴趣的:(websphere)