使用 XMLBeans 创建 Web 服务客户机

使用 XMLBeans 技术编写要求使用自定义数据类型作为方法输入的 Web 服务客户机。通过使用 XMLBeans,您不必在客户端生成静态存根。我们将详细讨论这个好处。

Shailesh K. Mishra (shailekm@in.ibm.com), 软件工程师, IBM 

Shailesh K. Mishra是位于印度古尔加翁的 IBM Software Lab 的一位软件工程师。他目前正在参与“BizPortlets”项目的相关工作,他主要感兴趣的领域是业务集成。



2006 年 9 月 25 日

引言

Apache XMLBeans 是开源的,基于 StAX 规范的 XML 与 Java 绑定工具。XMLBeans 可以用于从 XML 模式生成 Java 类和接口。可将生成的 Java 类用于分析或生成符合模式的 XML 文档;幸运的是,XMLBeans 提供了直观的方法来处理 XML,从而更容易使用 Java 访问和操作 XML 数据和文档。

让我们对其进行分解,看一看 XMLBeans 用于处理 XML 的方法的一些特征。

  • XMLBeans 提供了类似于基于 Java 对象的 XML 数据视图,并同时保留了对原始的本机 XML 结构的访问。
  • XML 作为文档的完整性通过 XMLBeans 得到了保留。面向 XML 的 API 通常会将 XML 化整为零,以便绑定到各个部分。通过使用 XMLBeans,可以将整个 XML 实例文档作为整体处理。XML 数据作为 XML 存储在内存中。这意味着文档顺序以及包含空格的原始元素内容将被保留。
  • 有了从模式生成的各种类型,可以通过类似于 JavaBean 的访问器使用 get 和 set 方法对 XML 实例进行访问。
  • XMLBeans 的设计一开始就充分考虑了 XML 模式——XMLBean 支持所有 XML 模式定义。
  • 可快速访问 XML。

XML 模式是 XMLBean 开发的起点。XML 模式规范(请参见参考资料部分)提供了一个丰富的数据模型,允许对数据上的复杂结构和约束进行表述。例如,XML 模式可以控制文档中的数据的排列顺序以及对特定值的约束。例如,输入的日期必须晚于 2000 年。在 Java 中,通常需要自定义代码来执行这样的规则。XMLBeans 可以实现模式约束。

可以使用 XMLBeans 技术来为 WSDL 文件中的类型定义生成 Java 类和接口。为此,请运行 WSDLTypes_To_JAVATypes 类(请参见下载部分)。您需要在此类的 main 方法中更改 WSDL URL。此步骤非常重要,因为将在此步骤生成相应的 Java 类和接口,以便准备用于调用 Web 服务的 SOAP 消息。为 WSDL 中的类型定义生成 Java 类和接口部分将详细讨论 WSDLTypes_To_JAVATypes 类。


配置您的工作区,以使用 XMLBeans

我们需要进行的第一步是下载 XMLBeans 的二进制分发版,可以在 apache.org 的 XML 页上找到。然后,将存档提取到目录中。将 XMLBeans 分发版中包含的 .jar 文件添加到项目中。


为 WSDL 中的类型定义生成 Java 类和接口

XMLBeans 框架提供了将 WSDL 文件编译为 Java 对象所需的功能。通过使用此工具,我们可以生成与 WSDL 中定义的数据类型关联的 Java 类和接口,它们可供 Web 服务客户机使用。这种动态解释 WSDL 文档的能力提供了比静态 XML 分析和处理技术更强大的功能。

下面的代码清单显示了 WSDLTypes_To_JAVATypes 类文件,此代码清单摘自文章 Using Java to Handle Custom WSDLData Types,可在参考资料部分找到这篇文章。您将了解如何从 WSDL 文件中定义的数据类型生成模式。

清单 1. generateSchemas 方法
generateSchemas(String schemadir, String classesdir,
 String javasrcdir, String wsdlFileName) {
   boolean doNotValidateContents = false;
   XmlObject wsdlDoc = null;
   MyEntityResolver myentityResolver = new MyEntityResolver();
   ArrayList outerrlistener = new ArrayList();
   XmlErrorWatcher errlistener = new XmlErrorWatcher(outerrlistener);
   ArrayList schemalist = new ArrayList();
   try {
	SchemaTypeLoader loader =
	 XmlBeans.typeLoaderForClassLoader(SchemaDocument.class.getClassLoader());
				.................................	
				................................
	addWsdlSchemas(wsdlFileName,
	 (DefinitionsDocument)wsdlDoc,errlistener,doNotValidateContents,schemalist);
				.................................

addWsdlSchemas 方法生成模式,并对其进行验证,然后将其添加到数组列表中。

清单 2. addWsdlSchemas 方法
addWsdlSchemas(String wsdlFileName,DefinitionsDocument definitionsDocument,
    XmlErrorWatcher  errlistener, boolean doNotValidateContents,ArrayList schemalist){
                         
      XmlObject[]types = definitionsDocument.getDefinitions().getTypesArray();
for (int j = 0; j < types.length; j++) {
	XmlObject[] schemas = types[j].selectPath("declare namespace"
        + " xs=\"http://www.w3.org/2001/XMLSchema\""        
		+ " xs:schema");
			if (schemas.length == 0) {
	StscState.addWarning(errlistener, "The WSDL " + wsdlFileName
		+ " has no schema documents in namespace "
		+ "'http://www.w3.org/2001/XMLSchema'",
	  XmlErrorCodes.GENERIC_ERROR,definitionsDocument);
	continue;
	}
for (int k = 0; k < schemas.length; k++) {
if (schemas[k] instanceof SchemaDocument.Schema) {
SchemaDocumentImpl.SchemaImpl schemaImpl = (SchemaDocumentImpl.SchemaImpl) schemas[k];
System.out.println ("Validating schema...");
if (schemaImpl.validate(opts)) {
	System.out.println("Schema passed validation");
	schemalist.add(schemas[k]);
	}else {
	 System.out.println("Schema failed validation");
	 schemalist.add(schemas[k]);
	}
}

compileSchema 和 generateJavaSource 方法将分别编译生成的模式和生成 Java 文件。最后,CompileJavaSource 方法将编译 Java 源文件。

清单 3. compileSchemas、generateJavaSource、CompileJavaSource 方法
SchemaTypeSystem compileSchemas(String schemadir,ArrayList schemalist, MyEntityResolver 
    myentityResolver,XmlErrorWatcher errlistener) 
{
    SchemaDocument.Schema[] sdocs = (SchemaDocument.Schema[]) schemalist
       .toArray(new SchemaDocument.Schema[schemalist.size()]);
    ResourceLoader cpResourceLoader = null;
    SchemaTypeLoader linkTo = SchemaTypeLoaderImpl.build (null, cpResourceLoader, null);.
	.................
	.................
	SchemaTypeSystem sts = SchemaTypeSystemCompiler.compile (params);
	....................


generateJavaSource(String classesdir,String javasrcdir, SchemaTypeSystem sts) {
	File classesDir = new File(classesdir);
	File srcDir = IOUtil.createDir(new File("."), javasrcdir);
		
	// now, generate the source files
	XmlOptions options = new XmlOptions();
	boolean verbose = false;
	boolean incrSrcGen = false;
	Repackager repackager = null;
	FilerImpl filer = new FilerImpl(classesDir, srcDir, repackager,
		verbose, incrSrcGen);

	System.out.println ("Generating Java source...");
	if (SchemaTypeSystemCompiler.generateTypes(sts, filer, options)) {
	............................
	...............................

CompileJavaSource(List sourceFiles, String classesDirName) {
	File classesDir = new File(classesDirName);
	boolean debug = false;
	System.out.println ("Compiling Java source files...");
	If (CodeGenUtil.externalCompile (sourceFiles, classesDir, null, debug)) {	
	..................
	..................

为 Web 服务编写客户机

要使用 XMLBeans 编写 Web 服务客户机,我们将直接准备一个 SOAP 消息,并将此 SOAP 消息发送到一个 Web 服务 URL。

准备 SOAP 消息

  • 步骤 1.通过进行以下调用创建 SOAPMessaage 实例

    SOAPMessage smsg =MessageFactory.newInstance ().createMessage ()
  • 步骤 2.创建 SOAP 信封和主体

    SOAPPart prt = smsg.getSOAPPart ();
    SOAPEnvelope env = prt.getEnvelope ();
    SOAPBody bdy = env.getBody ();

  • 步骤 3.为方法的输入类型实例化类

    GetPlacedOrderDocument Placedorderdoc=GetPlacedOrderDocument.Factory.newInstance ();
    GetPlacedOrderDocument.GetPlacedOrder order=placedorderdoc.addNewGetPlacedOrder ();
    Customer customer=order.addNewCust ();
    customer.setId (835163);
    customer.setFname ("Jerry");
    customer.setLname ("tukker");
    customer.setLocation ("abcd..");

  • 步骤 4.将上述类实例添加到 SOAP 消息的主体

    Node nd= placedorderdoc.getDomNode ();
    SOAPBodyElement ele = bdy.addDocument ((Document) nd);

  • 步骤 5.将 SOAP 消息发送到 Web 服务端点

    URL endpoint = new URL ("http://localhost:9080/Sample/services/SampleWebService");
    SOAPMessage response = con.call (smsg, endpoint);

下面的代码清单显示了执行完上述步骤后的代码:

清单 4. SOAP 客户机

点击查看代码清单

清单 4. SOAP 客户机

MessageFactory mfact = MessageFactory.newInstance();
			SOAPMessage smsg = mfact.createMessage();

			SOAPPart prt = smsg.getSOAPPart();
			SOAPEnvelope env = prt.getEnvelope();
			SOAPBody bdy = env.getBody();

GetPlacedOrderDocument placedorderdoc=GetPlacedOrderDocument.Factory.newInstance();
			GetPlacedOrderDocument.GetPlacedOrder order=placedorderdoc.addNewGetPlacedOrder();
			Customer customer=order.addNewCust();
			customer.setId(835163);
			customer.setFname("Jerry");
			customer.setLname("tukker");
			customer.setLocation ("abcd...");
			smsg.writeTo(System.out);
			System.out.println();
			Node nd = placedorderdoc.getDomNode();
			SOAPBodyElement ele = bdy.addDocument((Document) nd); 
.............................
URL endpoint = new URL("http://localhost:9080/Sample/services/SampleWebService");
			
                                           //Send the message
			SOAPMessage response = con.call(smsg, endpoint);
			response.writeTo(System.out);
...........................

在上面的代码清单中,GetPlacedOrderDocument 是在运行 WSDLTypes_To_JAVATypes 类后从 WSDL 文件(来自用于测试代码的示例 Web 服务)生成的接口。此 Web 服务有一个 getPlacedOrder 方法,以 Customer 类作为参数。Customer 类具有四个属性 id、fname、lname 和 location


结束语

本教程帮助您使用 XMLBeans 编写了一个 Web 服务客户机。我们从 WSDL 文件生成模式,并对其进行编译,最后从经过编译的模式生成 Java 源代码。准备好 Java 源代码后,我们可以方便地准备 SOAP 消息,并将其发送到 Web 服务 URL。这样,您就不必手动创建 SOAP 消息,也不必进行自定义 Java 对象的序列化和反序列化。

作者非常感谢 WebSphere Community Edition/Geronimo L3 Support Lead 的 Krishnakumar Balachandar (KK) 对本文进行审阅并提出了宝贵的意见。


下载

描述名字大小
Sample codexmlbeansample.zip96KB

参考资料

条评论

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=SOA and web services
ArticleID=162323
ArticleTitle=使用 XMLBeans 创建 Web 服务客户机
publish-date=09252006