如果您正在使用 IBM WebSphere Process Server,那么肯定了解它的许多特性。在本文中,学习如何使用强大的 Dojo TreeWidget
来管理 WebSphere Process Server 中的流程。本文通过一个例子探索如何处理分层数据,并通过创建 Web 2.0 风格的用户界面(UI)来管理数据。
您还可以通过下面的 下载列表 下载本文的样例代码。
dojox.Grid 是 Dojo 小部件的重要组件之一,它允许您轻松地操作和呈现远程数据和来自 web 页面的数据。TreeGrid
同时具备 dijit.Tree 和 dojox.Grid 的优点:它能够像 dijit.Tree 一样处理分层数据结构,也能够像 dojox.Grid 一样呈现数据。与 dojox.Grid 一样,TreeGrid
可以通过两种方式来构建 TreeGrid
:声明式或编程式。图 1 显示了一个简单的 TreeGrid
。
TreeGrid
采用 Model-View-Controller (MVC) 设计模式,如下所示。
TreeGrid
维护一个数据模型,该模型管理 TreeGrid
用于通过 UI 呈现数据的原始数据。TreeGrid
能够通过 dojo.data.api 提供的 API 访问数据存储以获取或处理数据,这是访问 Dojo 中的数据的标准方式。Dojo 提供许多以实现了 dojo.data.api 的 API 的数据存储,包括:ItemFileReadStore
和 ItemFileWriteStore
(用户可以使用它们读取和处理 JSON 数据);用于其它数据格式的 XmlStore、CsvStore 和 OpmlStore;以及其他数据存储。表 1 列出了所有数据存储。
数据存储 | 作用 |
---|---|
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
时创建。
另一种 TreeGrid
视图是嵌套的 TreeGrid
,它由嵌套的 structure
定义,如下所示。
控制器响应并处理事件。TreeGrid
继承自 dojo.grid.DataGrid,因此所有事件处理程序都与这里应用的 DataGrid 相关。您还可以通过将函数绑定到网格事件来定制事件处理程序,从而更加高效地控制数据和行为。
可以在 HTML 中以声明的方式或以编程的方式定义 TreeGrid
。TreeGrid
的大部分属性都是可选的,但 structure
和 store
(或 treeModel
,如果您需要创建列式 TreeGrid
)除外。 Structure
是定义 TreeGrid
视图布局的 JSON 对象。如果在 HTML 中以声明的方式定义了 TreeGrid
,该对象还可以通过标记表示出来。store
的值应该是 JavaScript 变量的名称,而该变量包含用于为 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> |
WebSphere Process Server 提供各种编程接口来管理流程,比如 EJB、Web Service、JMS 和 REST。不过,只有 EJB API 提供完整的函数集。要利用 EJB API 的威力,您需要构建一个将 TreeGrid
连接到 Process Server 的代理。
第一步是创建名为 SimpleSolution 的集成解决方案,它仅包含一个模块。为了让样例保持简单,我们构建只有一个接收/回复和一个人工任务的流程。人工任务只负责输入一个任意值作为回复操作的返回值。图 5 显示了该流程的定义。记住,您可以通过下面的 下载列表 下载本文使用的样例代码。
首先假设您使用的 IDE 为 WebSphere Integration Developer,以及代理应用程序运行在 Process Server 上(否则,您需要将 Process Server 客户端安装在您的服务器上)。这个例子首先创建一个动态 web 项目。您将看到会自动地引用所需的 Process Server 库。
Process Server 提供丰富的 API 来处理流程。您需要找到 EJB 服务的位置才能够访问这些 API。清单 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 中的代码来访问流程模板。
ProcessTemplateData[] processTemplates = processManager.queryProcessTemplates(null, null, 0, null); for(int i = 0; i < processTemplates.length; i++){ //Do something to the process template } |
使用清单 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。这时可以看到刚才创建的实例,如下所示。
转到 My To-dos 可以看到一个需要处理的人工任务,如图 8 所示。这是在流程定义中定义的人工任务。
要处理人工任务,您必须先找到它。可以使用流程管理器的 query
方法来获取所需的任务,如清单 5 所示。
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 显示了如何声明任务并获取输入参数的值。
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 显示了一个例子。
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 任务是流程实例的子节点。
{ 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", }] }] } } |
在设置好 WebSphere Process Server 之后,可以创建一个 TreeGrid
来接收和呈现 Process Server 提供的流程数据。可以为 TreeGrid
添加一些控件来管理这些流程。
如前所述,<table> 标记中的 store
属性(参见 清单 1)表明您希望使用哪个 DataStore 来获取数据。由于需要连接到流程代理,我们通过一个例子来解释如何进行连接。JsonRestStore
是一个 Dojo 数据存储接口,它连接到支持以 GET、PUT、POST 和 DELETE 方式进行读写的 JSON HTTP/REST web 储存服务。还可以在用 HTML 标记定义 JsonRestStore
,如清单 9 所示。
<span dojoType="dojox.data.JsonRestStore" jsId="jsonStore" target="SimpleSolution/ShowAll/"> </span> |
target
属性表明服务器端数据源的目标 URL。它假设用户在相同的域中,因此 target
的值应该是一个相对路径。jsId
是该储存仓库的标识符。
在这个例子中,在 HTML 中使用 <table> 标记以声明的方式定义 TreeGrid
。嵌套的 <th> 标记定义表中的列。清单 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
,如下所示。
这个 TreeGrid 非常简单,但我们只完成了一半工作。下一步是给 TreeGrid
添加一些控件,使其能够与 WebSphere Process Server 通信以及处理流程。
这个小节将给 TreeGrid
添加一些控件。从 Dojo 1.4 开始可以通过格式化程序(在网格单元格中显示返回值的 JavaScript 函数)将小部件添加到网格单元格。格式化程序还可以帮助格式化 TreeGrid
中的汇总单元格。
将通过格式化程序将两种类型的小部件添加到 TreeGrid
,如清单 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
的列,如下所示。
<th field="status" width="20em" formatter=” fmtStatus”>Status</th> <th field="id" width="20em" formatter=” fmtSubmit”>Action</th> |
现在,TreeGrid
应该类似于图 10。
可以引入 Dojo Ajax IO 函数 dojo.xhr* 来与 WebSphere Process Server 进行通信。单击 Submit 将向服务器发送 XHR 请求以提交新的状态。在收到服务器的响应之后,网格将进行刷新以正确地反映流程,如清单 13 所示。
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 |
学习