表 6. 使用 JSP 实现的系统界面
名称 |
访问路径 |
描述 |
approver.jsp |
/approver/approver.jsp |
页面启动时向后台 LoadApproveData 请求并展示需要审核的发票数据,并向 ApproverServlet 发送审核请求 |
basic_index.jsp |
/indexer/basic_index.jsp |
发票录入员所示用的发票数据录入页面,向 DisposeIndexServlet 发送请求数据,其包含两个标签页,区分待审核数据和基本的流程数据 |
index_list.jsp |
/indexer/index_list.jsp |
系统起始页面,用于展示当前所有活动的流程实例的列表,通过向 LoadProcessListData 发送请求获取数据 |
调用 WebAPI 必须包含的两个主要的 Jar 包,其中 teamworks-client-sample.jar 是使用 WebAPI 的辅助类,可以在 IBM BPM 的安装目录下找到,其中的 lib 目录下包含了使用该 Jar 包所依赖的其他的 Jar 包。webapi.jar 是连接 IBM BPM 的功能包,可以在服务端安装目录下直接找到。将所需包导入到工程的 Class Path 下。
新建一个普通 Java 类,命名为 WebAPIUtil,该类利用 teamworks-client-sample.jar 所提供的功能,产生 WebAPI 的实例,详细代码可查看示例程序程序中的 WebAPIUtil.java,下面是关键代码:
WebAPIFactory factory = WebAPIFactory.newInstance(properties); // Create a new WebAPI client stub factory.setProperty(Stub.USERNAME_PROPERTY, username); factory.setProperty(Stub.PASSWORD_PROPERTY, password); webAPI = factory.newWebAPI();
|
上面这段代码展示了通过 WebAPIFactory 产生 WebAPI 连接实例的过程,其中 username、password 用于连接 IBM BPM 的服务端,必须是合法的用户名 / 密码对,properties 对象通过 properties 配置文件产生,可参考示例程序中的 WebAPIFactory.properties 文件,内容如下:
清单 2. WebAPIFactory.properties 配置文件内容片段
Wjavax.xml.rpc.service.endpoint.address= http://[ibm-bpm-host]:[port]/webapi/services/WebAPIService javax.xml.rpc.session.maintain=true com.lombardisoftware.includeNullArrayElements=true
|
其中第一条配置信息包含了要访问的 WSDL 文件的地址,[ibm-bpm-host]:[port] 分别是 IBM BPM 的服务器地址和端口号。
新建一个 Servlet,取名为 LoadProcessListData,该程序创建一个查询(Search),查询出当前服务器所有活动的流程实例,详细代码可查看示例程序中的 LoadProcessListData.java,关键代码如下:
清单 3. LoadProcessListData.java 代码片段
WwebAPI = WebAPIUtil.getWebAPIConnection(username, password,webAPIProperty); // execute query to get the process instance list SearchResultRow[] rrs = getActiveInstanceList(); // generate XML data String xmloutput = getXMLDataFromSearch(rrs);
|
其中第一行代码展示了通过先前创建的辅助工具类获取 WebAPI 的实例,第三个参数为配置文件所在的路径。第二行代码通过调用一个方法获取查询的结果了数组,最后通过该数组生成需要返回的 XML 字符串,其中获取查询结果的代码如下:
Search se = new Search(); se.setOrganizedByType(“ProcessInstance”); SearchResults sr = null;
// set search column for the search and search result SearchColumn searchColumn1 = new SearchColumn(); searchColumn1.setType(“ProcessInstance”); searchColumn1.setName(SearchableProcessInstanceColumn._Id); SearchColumn searchColumn2 = new SearchColumn(); searchColumn2.setType(“ProcessInstance”); searchColumn2.setName(SearchableProcessInstanceColumn._Name);
// set the condition SearchColumn searchColumn3 = new SearchColumn(); searchColumn3.setType(“ProcessInstance”); searchColumn3.setName(SearchableProcessInstanceColumn._Status); SearchCondition searchCondition1 = new SearchCondition(); searchCondition1.setColumn(searchColumn3); searchCondition1.setOperator(“EQUALS”); searchCondition1.setValue(“Active”);
// create data SearchColumn[] scs = new SearchColumn[2]; scs[0] = searchColumn1; scs[1] = searchColumn2; SearchCondition[] sCond = new SearchCondition[1]; sCond[0] = searchCondition1;
// do the search se.setColumns(scs); se.setConditions(sCond); try { sr = webAPI.executeSearch(se, null, null); } catch (RemoteException e) { e.printStackTrace(); } return sr.getRows();
|
此段代码先创建一个 Search 对象,然后将结果的组织类型设置为根据”ProcessInstance”的方式,及以 Process 实例为基本单位获取结果,5 至 10 行创建需要展示的结果的列,12 至 18 行创建需要查询的条件,20 至 24 行设置查询数据,最后调用 WebAPI 的方法执行查询并返回结果。
当然,调用 Search 的方式除了上面介绍的通过代码硬编码的方式以外,还可以通过 IBM BPM 的 Portal 创建 Saved Search,然后通过 WebAPI 直接调用,类似于调用数据库中的存储过程。
此时通过界面即可查看当前的活动的实例列表,界面详细代码可查看示例程序中 index_list.jsp 及 process_instance_list.js 文件。
新建一个 Servlet,命名为 DisposeIndexServlet,该 Servlet 会接受页面参数,将参数通过”COCE_GIW_ALL_Index”活动传入到流程中,并将流程从当前活动推动到下一个指定的活动节点上,详细代码可查看示例程序中的 DisposeIndexServlet.java,下面是关键代码:
清单 5. DisposeIndexServlet.java 代码片段
int variableLength = 5; // variable length need to // initialize the varaibles Variable[] vars = new Variable[variableLength]; for(int i=0; i<vars.length; i++){ vars[i] = new Variable(); } vars[0].setName(“maxNumberApprovers”); vars[0].setValue(numApprs); try { vars[1] = makeApproverName(approvers); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } vars[2].setName(“duplicateCheck”); vars[2].setValue(duplicateCheck); …… vars[3] = makeContentList(contents);
// dispose the complex value ComplexValue cv = (ComplexValue)vars[3].getValue(); MessageElement arrayOfStr = cv.get_any()[0].getRealElement(); if(null != arrayOfString){ List<MessageElement> elementList = arrayOfStr.getChildren(); for(MessageElement strEle : stringElementList){ Text e = (Text) strEle.getChildren().get(0); e.setValue(mailContent); } } vars[4] = makeInvoiceData(data);
|
如上所示,程序首先创建 Variable 类型的数组,程序通过该数组给 Process 实例传递参数,对于简单参数,只需要调用 Variable 对象的 setName 和 setValue 为设置名称和对应的值,名称必须和活动中的参数名称相同。代码中 vars[1]、vars[3] 和 vars[4] 比较特殊,因为他们都是复杂类型的数据,类似于 C/C++ 中的结构体,需要通过反序列化的方式,其中 vars[1] 对应了流程定义中的参数 approverNames,它是一个 String 的列表类型,但是不同于 Java 的 String[] 或是 List<String> 及其子类型 , 后面会有详细的介绍,vars[3] 对应了 BPD 中的 mailContents 参数,也是 String 列表类型,vars[4] 对应了 BPD 中的 InvoiceDataModel 类型,同样是复杂类型的数据结构,下面以 InvoiceDataModel 为例,介绍一下 makeInvoiceData 方法中的序列化代码,如下:
Variable v = null; StringBuffer outputXml = new StringBuffer(“<InvoiceDataModel xmlns=\”http://www.w3.org/2001/XMLSchema\”>”); outputXml.append(“<Source>” + data.source + “</Source>>”); outputXml.append(“<UserID>” + data.userid + “</UserID>”); outputXml.append(“<Timestamp>” + data.Timestamp + “</Timestamp>”); outputXml.append(“<D_DocStatus>” + data.d_DocStatus + “</D_DocStatus>”); outputXml.append(“<ORIGIN_ITEM_ID>” + data.origin_item_id + “</ORIGIN_ITEM_ID>”); outputXml.append(“<OLD_CREATETS>” + data.old_creates + “</OLD_CREATETS>”); outputXml.append(“</InvoiceDataModel>”); // create variable v = new Variable(“invoiceData”, ClientUtilities.toComplexValue(outputXml.toString())); return v;
|
在构建流程定义的过程中,我们创建了复杂的数据类型 InvoiceDataModel,图 26 展示了该数据类型的 Schema 定义,上面的代码即根据该 Schame 的定义构建复杂数据类型的结构,最后通过 ClientUtilities 将 XML 转换成一个
以下文章点击率最高
Loading…