BPM 应用系统开发案例实战4


表 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,下面是关键代码:


清单 1. 创建 WebAPI 实例代码片段

                

 

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 字符串,其中获取查询结果的代码如下:


清单 4. 获取查询结果的代码片段

                

 

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 方法中的序列化代码,如下:


清单 6. 序列化代码片段

                

 

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…


发表评论

邮箱地址不会被公开。 必填项已用*标注