级别: 中级 喻 星 (yuxing@cn.ibm.com), 软件工程师, IBM 郑 溪龙 (zhengxil@cn.ibm.com), 软件工程师, IBM 徐 方 (fangerrr@163.com), 软件工程师, 自由职业
2009 年 3 月 19 日 本文介绍了如何利用 SCA 向内容管理系统传递附件。目前的内容管理系统通常都为开发人员提供了一套完整的 API,开发人员需要一定的学习曲线才能够掌握。而 SCA 可以将连接内容管理系统的操作封装成独立的服务,使开发人员可以更简单的进行服务调用。在封装的过程中,本文针对 SCA 不能处理大数据量文件附件的问题给出了一种解决方案,实现了一个名为 CMWI(Content Manager Web Interface)的应用。该应用为内容管理系统提供了一个 Web 服务接口,可以通过调用这个 Web 服务来向内容管理系统中存取文件,而不必学习内容管理系统的 API。
简介
内容管理系统(Content Management System,简称 CMS)是一种用来管理不同种类“内容”资源的计算机软件系统。CMS 管理的内容除了一般的文档、多媒体文件、流媒体文件以外,还包括网页、二进制程序、软件等一切数字资源,重点解决各种非结构化或半结构化的数字资源在数据采集、管理、有效利用、无损传递以及增值等方面的问题。例如内容管理系统可以帮助 SAP 系统存储企业合同、根据用户不同的需求查询相关的文档信息、提交改进方案等。目前很多公司都开发了自己的内容管理系统,其中包括 IBM Content Manager V8,还有国内比较常用的 TurboCMS,以及一些开源的 CMS,读者可以通过 Open Source 网站 获取更多的开源 CMS 信息。
由于不同应用对其相关内容资源的处理过程并不完全相同,CMS 通常提供一套完整的 API,应用程序开发人员可以调用相应的 API 以完成对 CMS 中内容资源的访问。传统的 CMS 调用方式需要对每一个应用配置 CMS 的相关参数,而开发人员也需要耗费大量的时间学习 CMS 的 API,增加了开发的时间,同时也提高了开发的复杂度。
为了简化开发人员的工作,更简便的调用内容管理系统,本文提出了通过 SCA 模块访问 CMS 的方法。采用 SCA 封装 CMS 的 API,向 CMS 中存取文件,传递附件。这样不仅可以屏蔽掉具体的实现技术,将服务接口暴露出来,方便开发人员调用,还可以省去配置 CMS 的细节。此外,如果 CMS 的 API 发生变化也无需对每个应用进行修改,可以大大减轻应用程序开发人员的工作量。在本文的示例程序中,我们构建了一个名为 CMWIModule 的 SCA 模块,提供了一系列与 CMS 相关的基本调用服务,比如上传(syncCMDocuments)、下载(getCMDocuments),并将这些服务以 Web 服务的形式暴露出来。这样的架构使开发人员只要知道相应的 Web 服务接口就能够完成对 CMS 的访问。
由于对 CMS 的访问涉及到大量的文档和图片,而 SCA 对于处理大数据量的文件并没有给出合适的解决方案,本文中我们分别针对小数据量附件和大数据量附件提出了两种不同的处理方式,以保证对 CMS 更加有效的利用。下面我们将首先介绍调用 CMS 的传统方法,然后给出 CMWI 应用的体系结构,接下来分别说明如何利用 SCA 模块传输不同大小的附件,最后介绍如何调用 CMWI。
调用CMS的传统方法
在本文的示例程序中,我们使用的内容管理系统是 IBM Content Manager V8(以下简称 CM),下面以连接该内容管理系统为例介绍在应用程序中调用 CM 的传统方法。
1. 配置 CM。
新建一个名为 cmbcmenv.properties 的配置文件,文件内容如 清单 1 所示。
清单 1. cmbcmenv.properties
CMCFGDIR = C:/DSW/WPS/cmicfg/connectors
CM_SERVER = CM_Test_Server
CM_APP_NAME = CM_Test_Application_Name
CM_APP_ID = CM_Test_Application_ID
ITEM = CM_Test_Item |
其中,CMCFGDIR 指定了 CM 配置文件所在的目录位置,该目录中应包含 cmbrm.ini,cmbicmsrvs.ini 和 cmbicmenv.ini 三个文件,这些文件说明了 CM 服务器的具体位置以及与访问 CM 相关的参数。对 CM 的配置并非本文介绍的重点,感兴趣的读者可以通过 IBM Content Manager 信息中心 获得相关的配置信息。
2. 引入 CM 相关的 jar 文件。
将 CM API 相关的 jar 文件复制到项目中,本示例中有4个相关的 jar 文件,分别为 cmb81.jar、cmbcm81.jar、cmbicm81.jar 和 cmbsdk81.jar,如 图 1 所示。
图 1. 需要引入的 jar 文件
3. 调用 CM 的 API。
以从 CM 中读取文件为例,需要在应用程序中添加如 清单 2 代码以访问 CM。
清单 2. 访问 CM 示例代码
// 第1步,建立与 CM 的连接。
DKDatastoreICM dsICM = new DKDatastoreICM();
dsICM.connect(database,userName,password,options);
// 第2步,获取指定 Item 的结果信息,存储在 DKResults 类型的 results 变量中。
String query = "/*[@ITEMID=\""+itemId+"\"]"; // 例如 /*[@ITEMID=\"A1001001A0\"];
options = new DKNVPair[3];
options[0] = new DKNVPair(DKConstant.DK_CM_PARM_MAX_RESULTS, "1");
options[1] = new DKNVPair(DKConstant.DK_CM_PARM_RETRIEVE, dkRetrieveOptions);
options[2] = new DKNVPair(DKConstant.DK_CM_PARM_END, null);
DKResults results =
(DKResults)dsICM.evaluate(query, DKConstantICM.DK_CM_XQPE_QL_TYPE, options);
// 第3步,获取 results 变量中的文件内容。
DKLobICM part = (DKLobICM) results.createIterator().next();
byte[] content = part.getContent();
// 第4步,关闭与 CM 的连接。
dsICM.disconnect();
dsICM.destroy();
|
上面介绍的只是获取 CM 中内容的一些关键步骤,实际的应用要复杂很多,这里不再一一赘述,感兴趣的读者可以参考 IBM Content Manager 信息中心 中有关 Java API 的介绍。
可以看到,按照传统的方法访问 CM ,我们不仅需要在每一个应用程序中配置访问 CM 的相关参数,将相应的 jar 文件复制到应用程序中,还需要应用程序的开发人员学习 CM 的 API。如果 CM 的 API 发生变化或者需要更换其他厂商的内容管理产品,那么就需要开发人员在每个应用程序中对涉及到 CM API 的地方进行修改,增加了程序的耦合度。因此,我们希望通过 CMWI 应用来降低开发人员的工作量,使调用 CM 更为简便。
CMWI 应用的体系结构
CMWI 应用架构在客户端与 CM 之间,客户端通过访问 CMWI 提供的接口完成与 CM 的通讯。在示例程序中,CMWI 提供了两个 Web 服务接口,分别实现文件上传(syncDocuments)和文件下载(getDocuments)的功能,客户端可以通过调用这两个接口将内容文件存储到 CM 中或从 CM 中下载内容文件。CMWI 应用的体系结构分为三层,如 图 2 所示。
图 2. CMWI 应用的体系结构
客户端层
客户端可以是一个 Web 应用或是 Java 应用,用来提出对 CM 的访问请求。
SCA 层
该层是 CMWI 的核心,CMComponent 负责处理客户端的请求并将请求传递给 CM,在这一层中实现了所有与内容管理有关的业务逻辑,将 CM 的 API 完好的封装起来。客户端通过 Web 服务接口访问 SCA 组件。
CM 层
该层可以看成是 CMWI 应用的基础,提供的内容文件的存储。SCA 层通过该层提供的 API 访问 CM。
如何在 SCA 中传递附件
用户对 CM 的访问必然涉及到文件的传递,CMWI 需要解决的主要问题是如何通过 SCA 实现与 CM 的文件传递。对于数据量较小的文件,我们可以直接采用十六进制编码或者 BASE64 编码,这是 SCA 支持的两种编码格式,内容文件可以作为 XML 的一部分在 SOAP 消息中传递。在空间占用上,BASE64 编码的数据比未编码的数据大30%,而十六进制编码的数据则是未编码的数据的一倍。因此对于数据量较大的文件,十六进制编码或者 BASE64 编码就不太适合了。我们可以采用附件的形式传递文件,即利用带附件的 SOAP 协议,从 SOAP 的 XML 中去掉二进制形式的文件而将文件直接作为 multipart/related MIME 内容放在 HTTP 请求中。下面将分别介绍如何处理小数据量文件和大数据量文件。
处理小数据量文件
在处理小数据量文件的时候,我们用 SCA 模块封装 CM 的 API,将要上传/下载的文件编码成 SOAP 消息的一部分,客户端应用程序通过SOAP消息直接访问 SCA 模块。采用这种方法,我们只需要实现 SCA 组件中的上传(syncDocuments)和下载(getDocuments)两个接口,通过导出 Web 服务绑定的方式提供 Web 服务,这样客户端应用就能够通过 Web 服务访问 SCA 模块,从而实现与 CM 的小数据量文件传递。
为了更好的封装文件相关属性,我们在 CMWI 应用中声明了一个名为 CMDocumentType 的业务对象,如 图 3 所示。
图 3. CMDocumentType 业务对象
其中 ItemType 和 SAPDocId 用来唯一标记CM中的某一篇文档;MimeType 用来指定文档的打开方式;Document 用来存储需要上传的文件或是要从 CM 中下载的文件,本示例采用十六进制编码;StatusCode 是操作是否成功的状态标志;Message 用来存储操作是否成功的相关消息。
对于如何建立一个 SCA 组件,读者可以参考文章 SCA(Service Component Architecture)编程模型入门 ,这里不再赘述。使用 WebSphere Integrated Developer(WID)可以自动生成 getCMDocument 方法和 syncCMDocument 方法的框架代码,如 图 4 所示。
图 4. CMComponent 的框架代码
在 CMWI 应用中,我们将 CM 的 API 封装在 ContentManagerService 对象中,通过 ContentManagerService 对象提供的 retrieveDocument 方法获得下载的文件内容;通过 storeDocument 方法将文件上传到 CM 中,关键代码如 清单 3 所示,这样就完成了 CMComponent 的构建。完整的代码读者可以参考 下载 中的示例程序。
清单 3. 将文件上传到 CM 示例代码
public DataObject getCMDocuments(DataObject getCMDocument) {
...
ContentManagerService cmiService = new ContentManagerService();
byte[] document = cmiService.retrieveDocument(item_type, attrs, mimeType, fileName);
String msg = "Download document successful.";
...
}
public DataObject syncCMDocuments(DataObject syncCMDocument) {
...
ContentManagerService cmiService = new ContentManagerService();
cmiService.storeDocument(item_type, attrs, document, mime_type);
String msg = "Document has been stored in CM successfully.";
...
}
|
为了使 SCA 模块外部的应用可以调用 SCA 模块内部的服务组件,SCA 提供了三种导出绑定方式,JMS 绑定,SCA 绑定和 Web 服务绑定。本示例中我们选择导出 Web 服务绑定。可以在 CMComponent 模块上单击右键,选择 Export... -> Web Service Binding,如 图 5 所示。
图 5. 从 CMComponent 导出 Web 服务绑定
将导出的 Web 服务绑定重命名为 CMComponentExport,如 图 6 所示。
图 6. 重命名 Web 服务绑定
此时,WID 会自动生成一个名为 CMComponentExport_CMWebInterfaceHttp_Service.wsdl 的 WSDL 文件,该文件描述了 CMWI 应用提供的 Web 服务。至此,处理小附件的 CMWI 应用已构建完毕。我们需要将这个 Web 服务发布到服务器上,并验证这个 Web 服务是否可用。根据生成的 WSDL 文件中 Web 服务的位置进行访问,得到 图 7 所示的页面,说明这个 Web 服务已经可以被成功访问。这样,不同的客户端应用程序就可以访问 Web 服务的文件上传以及下载功能,具体的调用步骤我们将在下面的 调用 CMWI 应用 部分进行介绍。
图 7. 访问处理小附件的Web服务
处理大数据量文件
在 SCA 中传递大数据量文件是本文需要解决的主要问题。对于数据量比较大的文件,如果将其编码后再进行传递,花费的时间较长代价也较大,根据我们的研究,用附件的方式传递大数据量文件是一种比较好的解决方法。但是 SCA 并不支持传递附件,即不能在 SCA 中直接用 javax.activation.DataHandler 类型表示文件,所以我们在 CMWI 应用中通过引入了一个名为 CMWIHttpService 的 Web 服务对文件进行转化。
Web 服务可以支持 javax.activation.DataHandler,可以使用带附件的 SOAP 消息来传递附件。带附件的 SOAP 消息将需要传递的附件以 MIME 格式放置在 SOAP 消息之外,只通过 MIME 报头的 Content-ID 或 Content-Location 与 SOAP 消息主体进行关联。由于不需要将文件编码到 SOAP 消息中,因此可以有效的解决传输大数据量文件的问题。关于向 Web 服务传递文件的其他方式,感兴趣的读者可以参考文章 技巧: 向 Web 服务传递文件 以获得更多的相关知识。
由于在 SCA 组件和客户端之间增加了一个 Web 服务,客户端不再直接访问 SCA 组件,而是访问 CMWIHttpService 这个 Web 服务,CMWIHttpService 会调用 SCA 组件实现文件的上传和下载。如 图 8 所示。
图 8. 处理大附件的CMWI
在执行文件上传时:
-
客户端应用指定一个文件,将该文件初始化为一个 DataHandler 对象,然后通过带附件的 SOAP 协议将其传递给 Web 服务。
-
Web 服务(本示例中为 CMWIHttpService)接收到请求之后,将 DataHandler 对象转化为字节数组(byte[]),然后通过 Standalone Reference 调用 SCA 组件中的上传功能。
-
SCA 组件(本示例中为CMComponent)接收到字节形式的文件之后,调用相应的 CM API,将文件存储到 CM 中。
在执行文件下载时:
-
客户端应用调用下载文件的 Web 服务接口,请求一个文件。
-
Web 服务(本示例中为 CMWIHttpService)将客户端的请求传递给 SCA 组件。
-
SCA 组件(本示例中为 CMComponent)调用相应的 CM API,从 CM 中找到指定文件,并以字节形式将其传给 Web 服务。
-
Web 服务(本示例中为CMWIHttpService)将字节形式的文件转换为 DataHandler 对象,然后将该对象回传给客户端应用。
CMWIHttpService 的构建方法如 清单 4 所示。
清单 4. CMWIHttpService 的构建方法
public class CMWIHttpService {
BOFactory bof =
(BOFactory) new ServiceManager().locateService("com/ibm/websphere/bo/BOFactory");
public CMDocumentType getCMDocuments(CMDocumentType getCMDocument,
DataHandler document){
System.out.println("Entering method CMWIHttpService.getCMDocuments()");
// 获得 DataObject 对象
DataObject da = bof.create("http://CMWIModule", "CMDocumentType");
String itemType = getCMDocument.getItemType();
String sapDocId = getCMDocument.getSAPDocId();
// 初始化 showCMDocument 变量,类型为 CMDocumentType
CMDocumentType showCMDocument = new CMDocumentType();
if(itemType != null) {
da.setString("ItemType", itemType);
}
if(sapDocId != null) {
da.setString("SAPDocId",sapDocId);
}
// 通过引用名称,调用 CMWI 模块中的 getCMDocuments 方法
ServiceManager serviceManager = new ServiceManager();
CMWebInterface service =
(CMWebInterface) serviceManager.locateService("CMWebInterfacePartner");
da = service.getCMDocuments(da);
String itemtype = da.getString("ItemType");
showCMDocument.setItemType(itemtype);
showCMDocument.setStatusCode(new Integer(da.getInt("StatusCode")));
showCMDocument.setMessage(da.getString("Message"));
if(showCMDocument.getStatusCode().intValue() == 0){
// 获得 byte[] 类型的文件
final byte[] content = da.getBytes("Document");
final String mime_type = da.getString("MimeType");
// 将 byte[] 类型的文件转化为 DataHandler 类型
DataSource ds = new DataSource(){
public InputStream getInputStream(){
return new ByteArrayInputStream(content) ;
}
public OutputStream getOutputStream(){
return null;
}
public String getContentType(){
return mime_type;
}
public String getName(){
return "";
}
};
document = new DataHandler(ds);
showCMDocument.setDocument(document);
showCMDocument.setMimeType(da.getString("MimeType"));
}
System.out.println("Exit CMWIHttpService.getCMDocuments().");
return showCMDocument;
}
public CMDocumentType syncCMDocuments(CMDocumentType syncCMDocument,
DataHandler document){
System.out.println("Entering method CMWIHttpService.syncCMDocuments().");
DataObject da = bof.create("http://CMWIModule", "CMDocumentType");
String itemType = syncCMDocument.getItemType();
String sapDocId = syncCMDocument.getSAPDocId();
if(itemType != null){
da.setString("ItemType", itemType);
}
if(sapDocId != null) {
da.setString("SAPDocId",sapDocId);
}
// 将 DataHandler 类型的文件转化为 byte[] 类型
try {
InputStream in = document.getInputStream();
byte[] content = new byte[in.available()];
in.read(content);
da.setBytes("Document", content);
} catch (IOException e) {
e.printStackTrace();
}
// 通过引用名称,调用 CMWI 模块中的 syncCMDocuments 方法
ServiceManager serviceManager = new ServiceManager();
CMWebInterface service =
(CMWebInterface) serviceManager.locateService("CMWebInterfacePartner");
da = service.syncCMDocuments(da);
// 初始化 acknowledgeCMDocument 变量,类型为 CMDocumentType
CMDocumentType acknowledgeCMDocument = new CMDocumentType();
String itemtype = da.getString("ItemType");
acknowledgeCMDocument.setItemType(itemtype);
acknowledgeCMDocument.setStatusCode(new Integer(da.getInt("StatusCode")));
acknowledgeCMDocument.setMessage(da.getString("Message"));
System.out.println("Exit CMWIHttpService.syncCMDocuments().");
return acknowledgeCMDocument;
}
} |
可以看到,CMWIHttpService 中提供了 getCMDocuments 以及 syncCMDocuments 两个方法。其中调用 getCMDocuments 方法需要提供一个 CMDocumentType 类型的参数,设置好 ItemType 和 SAPDocId 的值,并将 DataHandler 参数设置为null,该方法负责调用 SCA 组件中的下载程序获得 byte[] 类型文件,再将其转化为 DataHandler 类型返回给客户端。调用 syncCMDocuments 方法则需要提供 DataHandler 类型的文件,该方法先将其转化为 byte[] 类型,再调用 SCA 组件中的上传程序将其传递给存储到 CM 中。
在这个 Web 服务中,我们用到一个名为 CMDocumentType 的 Java Bean,负责存储文件内容以及相关信息,其中 document 为 DataHandler 类型,如 清单 5 所示。
清单 5. Java Bean 文件
public class CMDocumentType {
private String itemType;
private String SAPDocId;
private String mimeType;
private DataHandler document;
private Integer statusCode;
private String message;
public CMDocumentType() {
}
public String getItemType() {
return itemType;
}
public void setItemType(String itemType) {
this.itemType = itemType;
}
public String getSAPDocId() {
return SAPDocId;
}
public void setSAPDocId(String SAPDocId) {
this.SAPDocId = SAPDocId;
}
public String getMimeType() {
return mimeType;
}
public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}
public DataHandler getDocument() {
return document;
}
public void setDocument(DataHandler document) {
this.document = document;
}
public Integer getStatusCode() {
return statusCode;
}
public void setStatusCode(Integer statusCode) {
this.statusCode = statusCode;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
} |
另外,在 CMWIHttpService 中,我们通过一个名为 CMWebInterfacePartner 的引用调用 CMWI 模块。因为在 SCA 中,模块中的服务组件是不能直接被外部 Java 代码使用的,WID 工具在模块中提供了一个叫做 Standalone Reference 的特殊端点,只要把这个端点的引用连接到需要调用的服务组件的接口,外部的 Java 代码就可以通过这个引用名称调用相应的服务组件。读者可以根据文章 SCA(Service Component Architecture)编程模型入门 的步骤建立Standalone Reference。
此外, CMWIHttpService 并不能直接作为 Web 服务被客户端调用,WID 工具提供了根据 Java 程序生成 Web 服务的方法。右键单击 CMWIHttpService.java,选择 Web Services -> Create Web Service,然后根据提示步骤生成相应的Web服务。
图 9. 创建 Web 服务
CMWIHttpService 作为选中的对象。
图 10. 选择对象
设置 Web 服务的部署信息。
图 11. 服务部署配置
生成服务端点接口。
图 12. 选择服务端点接口
确认生成 Web 服务的一些信息。选择 Document/literal 的编码方式,使用 Document 编码方式可以充分利用 XML 文件来描述和验证一份业务文档,比 RPC 方式更有优势;另外选中 Use WSDL 1.1 Mime attachments exclusively 使用带附件的 SOAP 协议。
图 13. Java Bean Identify
生成的代码中包括:
-
CMDocumentType 的反序列化(deserializer)文件 CMDocumentType_Deser.java、序列化(serializer)文件 CMDocumentType_Ser.java 和 helper 文件 CMDocumentType_Helper.java,用于将输入的 XML 信息转换成 Java 语言并将输出的 Java 语言转换为 XML。
-
用来表示 Web 服务的服务端点接口文件(Service Endpoint Interface,SEI),SEI 主要是将 WSDL portType 映射到 Java 类型,从而让用户通过本地 Java 代理类访问 Web 服务,或者是通过执行 SEI 来提供 Web 服务。
-
Web Content 目录下的 CMWIHttpService.wsdl文件,WSDL文件提供了部署在服务器上的Web服务的相关信息,客户端只需要根据这些信息生成相应的调用代码就可以轻松的访问到Web服务。
读者可以通过 示例程序 获得完整的代码。
至此,处理大附件的 CMWI 应用已经构建完毕,根据 WSDL 文件中 Web 服务的位置进行访问,得到如图 14 所示的返回页面,说明这个 Web 服务已经可以被成功访问。
图 14. 访问处理大附件的 Web 服务
调用 CMWI 应用
为了使客户端的应用更加方便的调用 CMWI 组件,WID 可以帮助我们根据 WSDL 文件生成相应的客户端代码。下面分别讨论如何调用处理小数据量文件的 CMWI 应用和处理大数据量文件的 CMWI 应用。
调用处理小数据量文件的 CMWI 应用
对于处理小数据量文件的情况,选择 CMComponentExport_CMWebInterfaceHttp_Service.wsdl 文件,通过右键菜单启动 Web 服务客户端创建向导,如图 15 所示。
图 15. 生成 Web 服务客户端
WID 根据 WSDL 文件在 CMWIModule 目录下生成了一系列 Java 文件,如图 16。在这里我们用到的是 CMWebInterfaceExport1_CMWebInterfaceHttpServiceLocator.java、CMWebInterface.java 以及 CMDocumentType.java,其中 ServiceLocator 用来获得 Web 服务的定位,CMWebInterface 用来调用远程的 Web 服务,而 CMDocumentType 则是我们需要向 Web 服务中传递的数据类型。此外,我们还创建了 Test.java 来调用 WID 生成的客户端代码以测试 CMWI 应用,以下载小附件的方法 getCMDocument()为例,代码片段如 清单 6 所示。
图 16. 生成的 Web 服务客户端 Java 文件
清单 6. 下载小附件的方法
// 定位 Web 服务
CMWebInterfaceExport1_CMWebInterfaceHttpServiceLocator sl
= new CMWebInterfaceExport1_CMWebInterfaceHttpServiceLocator();
// 定义 Web 服务
CMWebInterface service = sl.getCMComponentExport_CMWebInterfaceHttpPort();
// 声明传递的数据类型
CMDocumentType getCMDocument = new CMDocumentType();
// 初始化 ItemType 的值
getCMDocument.setItemType("CMDocuments");
// 初始化 SAPDocId 的值
getCMDocument.setSAPDocId("20081291008109613A7C8E122FD28E12938EA7D");
// 调用远程服务的 getCMDocuments()方法,获取 CM 中相应文件
CMDocumentType showCMDocument = service.getCMDocuments(getCMDocument);
// 获得文件内容
byte[] document = showCMDocument.getDocument();
// 将文件存储到本地
if(document != null && document.length > 0){
FileOutputStream fos = new FileOutputStream("C:/temp/resultDocument.pdf");
fos.write(document);
fos.flush();
fos.close();
} |
在执行测试的Java客户端之前,我们首先通过 CM 客户端,查询到在 CM 中存在一篇 ID 为20081291008109613A7C8E122FD28E12938EA7D的文件,如图 17 所示。然后执行 清单 6 中的 Java 测试客户端,将文件下载到本地,存储在C:/temp/resultDocument.pdf,如 图 13 所示。
图 17. 通过 CM 客户端查询
图 18. 调用Java 测试客户端将文件下载到本地
调用处理大数据量文件的 CMWI 应用
对于处理大数据量文件的情况,我们需要根据 CMWIHttpService.wsdl 生成相应的客户端代码,生成的代码如图 19 所示。
图 19. 生成的 Web 服务客户端 Java 文件
创建 TestLargeFile.java 来调用 WID 生成的客户端代码以测试 CMWI 应用,下面以调用上传大附件的方法 syncCMDocuments()为例,演示客户端的代码片段,如 清单 7 所示。
清单 7. 客户端的代码
// 将本地需要上传的文件转化为 DataHandler 类型
FileDataSource fds = new FileDataSource("C:/temp/resultDocument.pdf");
DataHandler dh = new DataHandler(fds);
// 设置文件相关信息
CMDocumentType storeCMDocument = new CMDocumentType();
storeCMDocument.setDocument(dh);
storeCMDocument.setItemType("CMDocuments");
storeCMDocument.setSAPDocId("TestSeq006");
// 定位 CMWIHttpService 服务
CMWIHttpServiceServiceLocator sl = new CMWIHttpServiceServiceLocator();
// 定义 CMWIHttpService 服务
CMWIHttpService service = sl.getCMWIHttpService();
// 调用 CMWIHttpService 服务的 syncCMDocuments()方法
service.syncCMDocuments(storeCMDocument, dh); |
得到如下的输出信息,说明程序执行成功。
图 20. 程序执行成功页面
我们可以通过 CM 客户端进行检索,可以看到 ID 为 TestSeq006 的文件已经被存储到 CM 中。
图 21. 通过 CM 客户端进行检索
图 22. 检索结果
可以看到,在采用 SCA 封装了 CM API 后,客户端的工作得到了极大的简化。只要获得相应的 WSDL 文件然后调用相应的 Web 服务,就可以实现对 CM 的访问。相比于传统的方法访问 CM,这种方法要简便很多。
结语
本文实现了一个通过 SCA 向内容管理系统中传递附件的方案 —— CMWI 组件。通过调用该组件,客户端应用程序不再需要对 CM 进行配置、引入 CM 的 jar 文件,更主要的是应用程序的开发人员无需学习 CM 的 API。在本示例中,CMWI 通过导出一个 Web 服务为应用程序提供了传递小数据量附件的接口,用户也可以根据应用的具体情况选择 SCA 提供的其它导出方式。此外,为了解决向 SCA 组件传输大数据量附件的问题,CMWI 针对大数据量的附件内容给出了另外一种解决方案,通过一个中介的 Web 服务(CMWIHttpService)以 SOAP 附件的形式传递大数据量文件,使客户端应用可以简单、方便、高效的使用 SCA 来向 CM 中传递附件。
值得注意的是,本文只是给出了一种利用 SCA 向 CM 中传递附件的方法,并不能保证可以完美地解决所有的问题。如果读者希望采用本方案,请参考 SCA 以及 CM 的文档以了解更多的信息。
下载 | 描述 | 名字 | 大小 | 下载方法 |
|---|
| 处理小数据量文件的 CMWI 示例程序 | ForSmallFile.zip | 20,771KB | HTTP |
|---|
| 处理大数据量文件的 CMWI 示例程序 | ForLargeFile.zip | 22,452KB | HTTP |
|---|
参考资料
作者简介  | |  | 喻星是一位 IBM 软件工程师,工作在 IBM 中国软件开发实验室企业应用开发部门,在 Java 开发和 Web 开发方面有丰富的经验,现在正从事企业电子商务应用的开发和支持工作, 您可以通过 yuxing@cn.ibm.com 与她联系。 |
 | |  | 郑溪龙是一位 IBM 中国软件开发中心(CSDL)的软件工程师,专注于 web 应用开发。目前从事电子商务类应用的开发,对于快速开发框架,测试驱动开发有浓厚的兴趣。您可以通过邮件 zhengxil@cn.ibm.com 和作者取得联系。 |
 | |  | 徐方是北京师范大学信息管理专业研究生,曾在 IBM CSDL 北京的 Enterprise Application Development 组实习。熟悉 DB2,J2EE 等技术,对 Web 应用、Java 技术很感兴趣。 |
对本文的评价
|