案例研究:使用 IBM 业务流程管理器对发票进行处理,第 2 部分: 系统集成

本系列文章由两个部分组成,提供了一个真实的 IBM Business Process Manager V8.0.1 发票处理解决方案的案例研究,该案例使用 Web 服务和 Java™ 集成自动执行一个跨多个供应商和操作系统的过程。第 2 部分侧重于 Java 和 Web 服务集成,以及该解决方案中所涉及到的用户界面和图像处理技术。 本文来自于 IBM WebSphere Developer Technical Journal 中文版

Scott Glen, 认证的 IT 架构师, IBM

Scott Glen 是 IBM 的 Business Performance and Service Optimization (BPSO) 团队的一名认证 IT 架构师。他在面向对象的系统的架构、设计和开发方面拥有超过 19 年的丰富经验,曾为金融、政府、电信和媒体部门提供过咨询服务。他对 WebSphere、Java EE 架构和关联的设计模式有着特别浓厚的兴趣,现在主攻 SOA 和 BPM 技术,为整个欧洲、中东和非洲地区的客户提供咨询和实现服务。



2013 年 8 月 21 日

解决方案简要回顾

在这个由两部分组成的系列文章的第一部分,我们介绍了一个基于 IBM 业务流程管理器 (BPM) 标准 V8.0.1 的发票处理解决方案。我们介绍了与多个第三方供应商进行交互时遇到的业务挑战,还定义了一个业务过程模型,该模型具有支持的数据结构,是可重复使用的解决方案的支柱力量。图 1 显示了该解决方案的概述。

图 1. 解决方案概述
解决方案概述

集成技术

在本文中,我们将重点介绍该解决方案的技术方面,尤其会查看 Java 和 Web 服务集成,以及该解决方案中所涉及到的用户界面和图像处理技术。具体而言,我们将介绍 TWObjectTWList 对象如何支持与 Java 的复杂集成,该集成可以扩展 BPM 解决方案的功能。

Java 集成

在整个解决方案中,会使用 Java 代码询问和处理由扫描和索引供应商所提供的发票文件的内容。最有趣的方面涉及到 BPM 中复杂业务对象与其 Java 表示(已从关联的 XML 结构派生)之间的映射。

本系列的 第 1 部分 介绍了 TEAPPS,它是一个用于描述发票的基于 XML 的行业标准,第 1 部分还演示了如何使用 JAXB 来编组 Java 和 XML 表示之间的 TEAPPS 数据。在本文中,我们将使用 TWObjectTWList 类检查 Java 和 BPM 之间的关系,特别是 Java 中 BPM 数据结构的表示。这些类是 BPM 提供的常规 Java 类,您可以使用这些类帮助实现与业务对象的复杂集成。

首先,让我们快速回顾一下 TEAPPS 结构,如清单 1 所示。

清单 1. TEAPPS XML 片段
<?xml version="1.0" encoding="ISO-8859-1"?>
<INVOICE_CENTER>
	<TRANSPORT_FRAME>
		<TF_CODE>TF01</TF_CODE>
		<TIMESTAMP>20130119142648753</TIMESTAMP>
		<BATCH_ID>13777339</BATCH_ID>
		<CONTENT_RECEIVER>
			<RECEIVER_REF>BWEISE-0012928</RECEIVER_REF>
			<CONTENT_REF>BPMS-Invoice11</CONTENT_REF>
		</CONTENT_RECEIVER>
		<SENDER>BW003705925424</SENDER>
		<FB_REQUEST>1</FB_REQUEST>
	</TRANSPORT_FRAME>
	…

TEAPPS 文件的这一部分显示了 <TRANSPORT_FRAME> 标头元素,该元素包含一个嵌套的 <CONTENT_RECEIVER> 元素。映射到该元素的 JAXB 类如清单 2 所示。

清单 2. TEAPPS_ContentReceiver 类
publicclass TEAPPS_ContentReceiver 
{
	private String receiverRef;
	private String contentRef;

	@XmlElement (name="RECEIVER_REF")
	public String getReceiverRef() {
		return receiverRef;
	}

	@XmlElement (name="CONTENT_REF")
	public String getContentRef() {
		return contentRef;
	}

	publicvoid setReceiverRef(String receiverRef) {
		this.receiverRef = receiverRef;
	}

	publicvoid setContentRef(String contentRef) {
		this.contentRef = contentRef;
	}
}

BPM 流程需要访问该信息,因为 contentRef 属性包含一个惟一值,用于标识 TEAPPS 格式的发票。通过使用 Java 集成,可以通过 InvoiceManager 类中包含的 checkForIndexedResponse 方法访问该数据。该集成是在 BPM 中配置的,如图 2 所示。

图 2. CheckForIndexingResponse API
CheckForIndexingResponse API

该方法监视 incoming 目录并解压缩位于此处的所有 TEAPPS 文件的内容,然后将该内容传输到 processed 目录。随后将结果返回给 BPM 并存储在 indexedDocuments 变量中,该变量是 IndexedDocuments 业务对象的一个实例,如图 3 所示。

图 3. IndexedDocuments 业务对象
IndexedDocuments 业务对象

该对象包含 IndexedDocument(单数)对象列表,每个对象本质上都是围绕 第 1 部分 介绍的中心 Invoice 对象的包装类。checkForIndexingResponse 方法(填充该数据结构)中令人感兴趣的关键元素如清单 3 所示。

清单 3. CheckForIndexingResponse 方法
public TWObject checkForIndexingResponse (String incomingDir, String processedDir)
{
  // create BPM results object
  TWObject results = TWObjectFactory.createObject ("IndexedDocuments");
	
  // create list of document objects 
  TWList docList = TWObjectFactory.createList ("IndexedDocument");
					
  // for each incoming response file
  for (int i = 0; i < listOfFiles.length; i++)
  {
    // get top level TEAPPS element				
    TEAPPS_InvoiceCenter tic = tm.getInvoiceCenter (listOfFiles[i].getName());
	
    // move file to processed dir
    FileUtilities.moveFile (incomingDir, processedDir, listOfFiles[i]);
								
    // format for BPM objects
    TWObject indexedDoc = TWObjectFactory.createObject ("IndexedDocument");
    TWObject invoice = TWObjectFactory.createObject ("Invoice");
					
    // populate invoice - get key field for correlation
invoice.setPropertyValue ("inputDocId", 
	tic.getTransportFrame().getContentReceiver().getContentRef());
						
    // populate remaining invoice fields
invoice.setPropertyValue ("receiverRef", 
	tic.getTransportFrame().getContentReceiver().getReceiverRef());
		…
		…	
		
    // populate invoice line details	
    TWList invoiceLines = TWObjectFactory.createList ("InvoiceLine");
    if (tic.getContentFrame().getInvoices().getInvoice().getRows() != null)
    {
      // for each row in the invoice					 
      List<TEAPPS_Row> rows = tic.getContentFrame().getInvoices().
					getInvoice().getRows().getRows();
      for (int j = 0; j < rows.size(); j++)
      {
        // get line data
        TWObject line = TWObjectFactory.createObject("InvoiceLine");
        line.setPropertyValue("lineNumber",rows.get(j).getRowNumber());
		…
		…
	 // add (line) TWObject to (lines) TWList  
        invoiceLines.addArrayData(line);
      }
    }
	
    // vendor data
    TWObject vendor = TWObjectFactory.createObject ("Vendor");
    vendor.setPropertyValue ("number", 
	tic.getContentFrame().getInvoices().getInvoice().
	getPayee().getCustomerInformation().getCustomerId());
		…
		…					
    // add lines (TWList) to invoice (TWObject) 
    invoice.setPropertyValue ("invoiceLines", invoiceLines);
						
    // add invoice to indexed Doc
    indexedDoc.setPropertyValue ("invoice", invoice);  		
						
    // add indexed doc (TWObject) to docList (TWList)
    docList.addArrayData(indexedDoc);
  }
					
  // finally add indexed doc list to single results object
  results.setPropertyValue ("indexedDocumentList", docList);			
  return results;
}

首先,我们会注意到,该方法签名与 BPM 中 Java 集成的配置相匹配。它接受两个字符串并返回一个常规的 TWObject(实际上它是 IndexedDocuments(复数)对象的一个实例),它包含在本地 results 变量中。如 图 2 所示,该业务对象包含 IndexedDocument(单数)对象列表。因此,该代码创建了一个 TWList,名为 docList,用于标识该数据结构。

后来,在该方法中创建了很多不同的 TWObjectTWList 对象,用于表示 TEAPPS 文件的嵌套结构以及关联的 BPM 对象。该代码和该数据结构之间的关系如图 4 所示。

最外层的 IndexedDocuments 结构实际上是一个包装类,它包含 Indexed Document 对象列表,每个对象都被映射到该批次中的一个 Invoice。这个 Invoice 元素本身是一个包装类,它包含 Vendor 详细信息元素以及 Invoice Line 元素(表示与 Invoice 有关的各个产品或服务)的列表。

图 4. IndexedDocuments 结构
IndexedDocuments 结构

图 4 中定义的每个元素都包含 清单 3 中的一个与之匹配的代码行(以红色突出显示),该代码行创建关联的对象并逐步建立总体结构。虽然这表示我们看到的最复杂的 Java 到 BPM 映射之一,但我们将重点介绍一个模式,在该模式中,可以使用嵌套的 TWObjectTWList 对象表示一个重复的有层次的数据结构。

Web 服务集成

通过比较发现 Web 服务集成相对来说比较简单。由于业务合作伙伴执行其发票处理所花费的时间是未知的,因此该 Web 服务模型是异步的。使用的模式涉及一个单向 Web 服务请求,之后是一个由中间消息事件实现的等待活动。然后,BPM 会提供一个单独的 BPM Web 服务来帮助实现该响应,该响应通过秘密代理 (Undercover Agent,UCA) 与等待过程相关联。

图 5. Post Invoice 过程
Post Invoice 过程

在图 5 所示的 Post Invoice 过程中,传出的 Web 服务请求(在 Update ERP 任务中)非常简单,它传递一个 Invoice 业务对象,该对象包含一个关联标识符。图 6 显示了传入的 Web 服务(处理响应)的结构。

图 6. 剖析传入的 Web 服务
剖析传入的 Web 服务

该 Web 服务实际上是一个包含常规系统服务的包装类,它调用了一个 UCA,该 UCA 使用在此 Web 服务中传递的关联信息来查找 PostInvoice 过程的正确实例。在 图 5 中,该 UCA 将触发 “Wait for post notification” 事件,让 Post Invoice 过程能够继续进行。

图像处理

除了支持多种技术集成选项之外,该解决方案还必须显示从扫描供应商收到的数字图像。这样用户就可以验证光学字符识别 (Optical Character Recognition,OCR) 活动的结果,并且可以根据需要手动修正所有发票行。通常会提供 JPEG 或 PDF 格式的图像,但在设计时,BPM 并不知道,因此不可能是已部署的流程应用的一部分。

在运行时使用一个 Java 集成对图像进行编码,以便将图像从二进制格式转换为 Base64 ASCII 流,这个流格式使用某个自定义 HTML 控件将图像显示为 Coach UI 的一部分。该模式的关键元素如图 7 所示。

图 7. Verify Invoice 过程
Verify Invoice 过程

Verify Invoice 过程也非常简单;实际上该解决方案中的所有过程都非常小并且可以维护,从而最大程度地减少了更改所造成的影响。该过程最初建立了一些变量,因为图像位置是通过 Exposed Process Variables (EPV) 配置的,所以可以根据部署环境轻松地更改这些位置。然后通过一个 Java 集成使用图 8 所示的 API 调用这个 Base64 编码例程。

图 8. 对图像定义进行编码
对图像定义进行编码

该 API 接受图像的完全限定的文件名,并返回一个 Base64 编码的字符流,该字符流存储在本地,存储在图 9 所示的一个 image 参数中。

图 9. 对图像数据映射进行编码
对图像数据映射进行编码

image 变量不是一个特殊的结构,它只是 Base64Image 业务对象的一个实例,该对象是一个包含图像流以及关联的文件名的包装类,如图 10 所示。

图 10. Base64Image 业务对象
Base64Image 业务对象

扫描后的图像非常小,通常是 30K 左右,并且从我们测试的结果可以看出,BPM 已经成功对图像进行了处理。很明显,如果提供的图像较大,或者要求并发处理大量的发票,那么可能必须修订该方法,而修订该方法的同时也会增加服务器堆大小。

现在,我们已经在一个 BPM 变量中存储了图像,因此可以对该图像进行处理,就像是该图像是其他任何字符串值一样。实际上,BPM 和 Workflow Provider 之间的集成要求将整个图像以参数的形式传递给 Web 服务。现在可以使用 BPM 中的标准 Web 服务集成来实现此操作。

现在,还可以在标准的 BPM Coach 中显示已编码的图像。由于 BPM V8 中引入了新的 Coach 架构,所以对使用自定义 HTML 控件的方式进行了一些更改。在 V8 之前的版本中,可以在自定义 HTML 组件中使用图 11 所示的语法。

图 11. 自定义 HTML 控件(V8 之前)
自定义 HTML 控件(V8 之前)

在显示该控件之前,将对 <#= #> 标记中的 BPM 表达式求值,以便能够在 HTML <img> 标记中显示与 image 变量有关的数据,在本例中,将在该标记中显示图像。但是,在 BPM V8 中,不再支持该语法。可以使用很多办法来实现相同的结果。其中一个选项是使用 Javascript 在 Human Service 中动态生成整个 HTML 字符串,如清单 4 所示。

清单 4. 运行时 HTML 生成
tw.local.imageHTML = "<div id='imageDiv'><img id='invoiceImage' 
	src='data:image/jpg;base64," + tw.local.image.image + "'></div>";

这会在 VerifyInvoice Human Service 中初始化一个本地字符串变量,以包含动态 HTML 语句,该语句将在 <div> 元素中显示已编码的发票图像。然后,您可以将这个变量分配给 Coach 中的一个自定义 HTML 元素,如图 12 所示。

图 12. 将变量分配给自定义 HTML 控件
将变量分配给自定义 HTML 控件

最终结果是,扫描后的图像会根据需要嵌套在 Coach 中,如图 13 所示。

图 13. 图 13. 嵌套在 Coach 中的图像
嵌套在 Coach 中的图像

另一个需要注意的事项是,新的 Coach 与绑定到 Horizontal 或 Vertical Section 中某个重复表的列表变量的呈现有关。这是非常常见的模式,在这种模式中,会使用一个列表变量来表示与某个父对象有关的信息行。

例如,在图 13 所示的 Coach 中,Invoice Lines 区域显示 Horizontal Section 中单个行项目的表格。如果您将 invoiceLines 列表变量从调色板拖放到某个 Section 中的画布上,那么只会将该变量绑定到所得到的 Table,而且还会绑定到这个 Section 自身。这意味着,如果您在 invoiceLines 列表中有三个元素,那么您会有三个完整的 Section,每个 Section 都有一个包含三行的 Table!在某些方案中,这就是所需的行为,但在本例中,为了避免出现重复的 Section,我们只删除了该 Section 和列表变量之间的绑定,保留了该 Table 和该变量之间的绑定。感谢 Avijit Banerji 发现了那个问题!


业务监视

该解决方案的最后一个元素涉及创建一些报告,以提供对该过程的状态和性能的业务洞悉。很多资源中都概述了业务活动监视(Business Activity Monitoring,BAM)的功能,值得一提的是,John Alcorn 所撰写的一系列 developerWorks 文章中概述了这些功能,因此,我们在这里不再详细介绍。

该解决方案利用了 BPM 和 BAM 之间的即装即用集成,在该集成中,使用了流程设计器 (Process Designer) 来标识将在执行该过程时监视的一组变量。通过选择流程设计器 (Process Designer) 中的 File => Update Tracking Definitions 选项,可以使用这些 “被跟踪” 字段(如 图 14 所示)来生成和发布一个 IBM 业务监视器模型。

图 14. 被跟踪的字段
被跟踪的字段

执行该过程时,与这些变量关联的值被发送到业务监视器。利用这个信息,可在业务空间 (Business Space) 环境中创建很多预定义的报告和自定义的报告,如图 15 中所示的报告,该报告显示了所处理的发票的累积值,按业务部门进行划分。请注意,出于保密考虑,我们已经从 X 轴中删除了实际业务部门的名称。

图 15. Invoice Value 报告
Invoice Value 报告

在流程设计器中开发监视器模型非常方便,但它只提供与业务监视器的基本集成。如果需要更详细的模型,则需要使用集成设计器 (Integration Designer) 中的监视器工具包 (Monitor Toolkit)。这样就可以对自动生成的内容以及可以应用于报告维度的条件进行更具体地控制。


结束语

本文章系列提供了一个真实 BPM 项目的端对端案例研究,涉及多个合作的第三方以及各种技术集成技巧。从最初的分析到最后业务报告的生成,您已经看到了如何将 IBM BPM Standard V8.0.1 放置到复杂业务解决方案的核心,以及如何编排一系列自动化活动和人工活动。具体来说,本系列涉及的内容如下:

  • 在 Blueworks Live 中进行业务分析和流程映射
  • 开发一个涉及多个子流程实例的流程模型
  • 访问外部的基于 XML 的数据结构
  • Java 和 Web 服务集成
  • 流程关联
  • 图像处理,包括编码以及在 Coach 中的呈现
  • 业务活动监视

设计和开发整个解决方案并将它部署到外部托管的客户端环境中大约需要 15 个人工作一周的时间,这表明 IBM BPM 可以缩短开发周期,并能够快速实现复杂 BPM 解决方案的时间价值。

参考资料

学习

  • 了解 TEAPPS 发票消息
  • 学习 JAXB
  • developerWorks BPM 专区:获取有关 IBM BPM 解决方案的最新技术资源,包括下载、演示程序、文章、教程、事件、网络广播以及更多内容。
  • IBM BPM 期刊:获取本季度期刊中有关 BPM 解决方案的最新文章和专栏,这里还提供了 Kindle 和 PDF 版本。
  • IBM developerWorks 中国 WebSphere 专区:为使用 WebSphere 产品的开发人员准备的技术信息和资料。这里提供产品下载、how-to 信息、支持资源以及免费技术库,包含 2000 多份技术文章、教程、最佳实践、IBM Redbook 和在线产品手册。

获得产品和技术

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=WebSphere
ArticleID=941665
ArticleTitle=案例研究:使用 IBM 业务流程管理器对发票进行处理,第 2 部分: 系统集成
publish-date=08212013