漂泊的人

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
 我们都知道,为构建健壮的 Web 应用程序,.NET 平台提供了一组非常好的工具。然而,作为.NET开发人员,我们需要懂得如何才能把 .NET 的优良特性同其他平台和技术集成起来。我们经常发现客户将.NET和J2EE 技术在他们的架构中应用得都非常成功。

  最近我就遇到了这样的情况,并且我愿意在这篇共分两部分的文章中,同您一起分享我的一些经验。第1部分将讨论ASP.NET 和 BEA WebLogic 8.1之间的互操作性,以及如何使用XML Schemas 在平台之间传输数据。第2部分将讨论如何正确地处理SOAP 异常,上传和查看二进制数据,如何才能处理页面导航和应用程序工作流。本文的源代码可以在http://sys-con.com/weblogic/sourcec.cfm中找到。

  在一个近期项目中,客户决定使用J2EE 技术(特别是 BEA WebLogic 8.1)来支持核心的遗留应用程序。新的Web 应用程序允许供应商输入有效信息并将其直接传输到核心应用程序数据库中。WebLogic 将通过Web Service 提供业务功能。该客户有一些在Visual Studio.NET工具中用C#语言开发的应用程序,并且想利用ASP.NET 高效性来开发应用程序的表示层。

  我们可以使用很多技术来让.NET能够和J2EE进行通信。最流行的一种是XML Web Service。Web Service的主要优点是得到行业支持、工具支持并且易于开发。

  这里也有几种产品,例如Ja.NET (http://ja.net.intrinsyc.com/ja.net/info) 或Janeva (www.borland.com/janeva) ,该产品桥接了.NET 和J2EE 环境,从而允许双向通信、共享本地数据类型和有状态的通信。这些产品通过配置.NET Remoting 来桥接.NET 和 J2EE,其行为就像一个Java RMI/Corba 客户端或服务器。桥接.NET 和 J2EE 提供了更多健壮的功能并执行了比XML Web Service更好的服务。使用桥接技术的最大缺点是学习的复杂性、桥接产品的配置以及许可证费用。我们决定使用XML Web Service 是因为该web 应用程序不需要有状态的通信并且速度与开发时间和成本相比,不是最高优先级。

  该解决方案计划在表示层使用ASP.NET Web Form和驻留在WebLogic上的Web Service 进行通信,期间,WebLogic 将提供业务服务和数据持久性。表示层将对显示、捕获和执行简单的域验证。业务层将应用该业务规则,数据层将把数据保持到SQL Server 数据库中。ASP.NET Web Form将使用WebLogic Web Service同WebLogic 业务层进行通信。

  WebLogic Web Service 采用WebLogic Web Service 工具包构建。此工具包让您无需进行额外的编码,就可以公开一个作为Web Service 的Java 对象。WebLogic Web Service支持下列组件,将其作为Web Service的资源:

  • 无状态会话Enterprise Java Bean (EJB) 方法
  • Java 类方法
  • JMS 消息消费者或生产者

  BEA 建议您用无状态会话或Java类来执行Web Service 操作,不要使用JMS 生产者或消费者。

  在应用程序中,使用无状态会话bean作为面向业务逻辑和数据持久性逻辑的外观。我们遵循的是Session Facade 模式,该模式为应用程序功能提供一个单独的界面并且允许对业务对象进行过程消除访问。关于外观模式的更多信息,请参考http://java.sun.com/blueprints/patterns/SessionFacade.html

  我们也实现了一个中间类来担当业务代表,把业务组件从使用它们的代码中分离出来。特别是业务代表类通过抛弃来自EJB会话的应用程序异常,帮助我们处理执行异常,并且在业务代表类中捕获这些异常,然后该类就能构建一个自定义的SOAP异常。在SOAP 异常处理的章节,我们将对其进行详细讨论。关于业务代表模式的更多信息,请参考http://java.sun.com/blueprints/patterns/BusinessDelegate.htm

图1 显示了应用程序的整体架构。

 

  这里我们会面对一些挑战。我将在本文讨论其中的某些问题,决定如何在执行中处理它们,并且我们对任何人的建议都要使用相似的架构。

  我们验证了下列问题:

  • 需要确保开发的Web Service在ASP.NET 和BEA WebLogic 8.1之间具有互操作性。
  • 需要确定通过Web Service 在平台间传输数据的最佳方法。
  • 需要确定如何在两个平台之间进行异常处理。
  • 需要上传并查看图像,该图像请求传输并通过Web Service检索二进制信息(图像)。
  • 制定一个计划来处理页面导航和应用程序工作流程。

.NET 和 BEA WebLogic 8.1之间的互操作性

  使用XML Web Service 时,最主要的要求是能够在不同平台间提供正确的互操作性。为了讨论正确的互操作性,我们需要讨论Web Service 背后的一些技术。

  SOAP 规范指出,通过Web Service 发送的信息内容必须是基于XML格式的,但是该特定格式的使用对供应商是开放的。WebLogic 支持的两种最主要样式是RPC 样式和文档样式。SOAP 消息在RPC 样式消息中包含了参数和返回值。而SOAP消息在文档消息中包含了XML 文档。

  .NET XML Web Service的默认样式是文档。WebLogic Web Service工具包的默认样式是RPC (实际上是适用于Microsoft SOAP Toolkit v2),首选样式最容易引起争议。许多人感觉文档样式更加灵活。由于wsdl.exe 生成的代理类对两者提供支持,两种样式对ASP.NET 开发人员都是透明的。因为互操作性是个关键问题,所以我们选择RPC 样式,该样式长期以来得到了大多数工具包的支持,并且使Web Service 对调用者来说更像一个本地API。RPC样式也使我们设计的Web Service 界面,与我们在Java 或.NET使用的标准界面更加相似。

  作为SOAP消息的一部分发送的XML中,有两种对本地数据类型进行编码的样式——SOAP编码和文本编码。SOAP编码使用SOAP规范将本地数据类型映射到XML中。SOAP规范定义了支持的本地数据类型,而且您必须使用其中一种数据类型。文字编码使用XML Schema 为XML消息本身的所有非标准数据类型包含一个定义。文字编码在这个实例中显得更加灵活。

  RPC样式的WebLogic Web Service 操作必须使用SOAP编码。文档WebLogic Web Service 操作必须使用文字编码。在一个单独WebLogic Web Service (类) 中的所有操作必须都是RPC 样式或都是文档,WebLogic Server 不支持在同一个执行中混合两种样式。因为我们使用的是Web Service 的RPC 样式,所以WebLogic 中的所有Web Service 都使用SOAP 编码。

  在WebLogic 应用程序中,我们使用内置的数据类型来尽可能的减少开发工作量。JAX-RPC 规范对内置数据类型进行了详细说明。当使用内置数据类型时, WebLogic 自动处理XML和Java表示法之间的数据转换。如果Web Service 使用一个非内置的数据类型作为参数或返回值,您必须创建一个序列化类,在Java 和XML 之间转换数据。

表1 列出了WebLogic 支持的内置数据类型:

  在很大程度上,我们在ASP.NET 应用程序中使用WebLogic 8.1 Web Service时很少遇到不兼容性问题。需要注意的一个问题是SOAP encoding的使用。当WS-I Basic Profile 1.0 (BP) 请求RPC 样式和文字编码时,在WebLogic中使用RPC 样式需要SOAP 编码,这违背了WS-I Basic Profile 1.0。。我们还应当注意到,使用WebLogic Web Service 时,您不能把静态方法公开为一个Web Service服务;它们必须是类层次的方法。

通过Web Service传输数

  自从应用程序需要调用非.NET Web Service以来,我们用来传输数据的机制就不能使用特定于.NET的数据类型或对象。在以前的项目中,我们通过Web Service进行DataSet,并且把它们限定到Web 应用程序中的ASP.NET 组件。因为WebLogic 没有DataSet的概念, 所以不能使用这种方法。我们考虑过大量的替代方法。

  我们考虑过构建一个机制来生成XML,使其与DataSet生成的XML一致。这需要生成一个基于传输数据的动态XML 模式,然后基于动态模式来生成XML数据。我们决定采用这个解决方案,因为我们感到需要进行大量的编码工作,并且容易受到ADO.NET 未来变化的影响。

  另一个选择是使用值对象来传递数据。值对象基于“Value Object”模式,并且用属性和accessor/mutator (获取/设置)方法来表示简单的类。在J2EE架构中,值对象通常用于在层之间传递数据。在此例中,将在WebLogic Web Service 中示例一个值对象或值对象的收集,并且数据也将存储到这些类中。在ASP.NET 应用程序中,该数据将被接收为一个代理对象,此代理对象是Java类的客户表示。该类必须使用原语数据类型(或其他收集对象,比如在两种环境中都公认的ArrayList)。

  我们决定反对这个解决方案,原因是该解决方案的工作包括分解代理对象传递的数据。在这种方法下,一个.NET 开发人员需要编写代码来分解来自代理对象的值,并将它们放到DataSet中。编码相对比较简单,但这个步骤却相当乏味并且没有必要。每次从更改的Web Service 返回数据时,都需要更改这些代码。

  我们想找到这样一种解决方案:包含最少的编码工作,使用.NET 和WebLogic 中现有的技术,并且使ASP.NET 开发人员能将诸如DataGrid 或 DataList 这样的对象直接绑定到来自Web Service (同样的也可以在从.NET Web Service 向传递DataSet时执行)的返回数据。

  我们确定的方案是使用XML 模式作为解决方案的基础。我们为每个结果设置都构建了一个XML 模式来定义结果设置中的数据。为了在WebLogic环境中生成XML 数据,我们使用一个称为XMLBean的产品。XMLBeans 是一个Java-XML 绑定工具,能使您轻松的生成基于XML 模式的Java 对象,它在Java类中生成一个XML模式的对象表示法。BEA 在在WebLogic 本身广泛地使用XMLBean。 XMLBean 是开源产品,最初是由BEA开发的,并通过Apache 发布到开源社区。从http://dev2dev.bea.com/technologies /xmlbeans/index.jsp中,您可以了解到XMLBean的更多详细信息。您也可以从http://workshop.bea.com/xmlbeans/XsdUpload.jsp下载该BEA版本。

  使用XMLBean 时,我们生成一组Java 类来包含数据,然后使用XMLText 方法获取一个基于对象数据的XML文件实例。那么我们就可以通过Web Service 把XML 字符串传递到ASP.NET 应用程序.

  在这个ASP.NET 应用程序中,开发人员可以在XML 模式中实例化一个DataSet 负载,来定义DataSet 的结构,然后通过LoadXML 方法向DataSet装载 XML 文件。在基于Northwind数据库的例子中,我们构建了一个模式来表示一组客户和定单数据。该ClientOrders.xsd 模式显示在清单1中。为了生成一组基于ClientOrders.xsd 模式的Java 对象,,您需要下载并安装XMLBean 工具包。由于需要使用所有的Java 工具,在运行前您需要设置Java SDK 的正确路径。如果您已经安装了Java 产品(如JBuilder 或WebLogic),那么您很可能已经安装了SDK。清单2 显示了可以使用的批处理文件示例 -您需要设置"JAVA_HOME" 变量,使其指向Java SDK 的路径。该批处理文件示例期望在默认的安装路径(C:\xmlbeans)中找到XMLBean library (xbean.jar)。

清单1: ClientOrders.xsd

<?xml version="1.0" encoding="UTF-8"?><xs:schema ? 
 targetNamespace="http://www.justwebsolutions.com/articles" xmlns:?
 xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www.?  justwebsolutions.com/articles"
 elementFormDefault="qualified"?  >
 <!-- define global elements for Client -->
   <xs:element ?  name="CustomerId" type="xs:string"/>
     <xs:element name="CompanyName" ?  type="xs:string"/>
	   <xs:element name="Phone" type="xs:string"/>
	   <xs:element name="Fax" type="xs:string"/>
	   <!-- define global ? elements for Order -->
	   <xs:element name="OrderId" type="xs:? int"/>
	   <xs:element name="OrderDate" type="xs:date"/>
	   <xs:? element name="RequiredDate" type="xs:date"/>	?
	   <xs:element name="ShippedDate" type="xs:date"/>
	   <!-- define Order ? element -->
	     <xs:element name="Order">
		 <xs:complexType>
		 <xs:sequence>
		 <xs:element ref="OrderId"/>	?
		 <xs:element ref="OrderDate"/>	?
		 <xs:element ref="RequiredDate"/>
		 <xs:element ref="ShippedDate"/>	?
		 </xs:sequence>
		 </xs:complexType>
		 </xs:element>	?
		 <!-- define Client element -->
		 <xs:element name="ClientOrder">
		 <xs:complexType>
		 <xs:sequence>
		 <xs:element ref="CustomerId"/>
		 <xs:element ref="CompanyName"/>
		 <xs:element ref="Phone"/>
		 <xs:element ref="Fax"/>
		 <xs:sequence>
		 <xs:element ref="Order"/>
		 </xs:sequence>
		 </xs:sequence>
		 </xs:complexType>
		 </xs:element>
		 <!-- define schema elements -->
		 <xs:element name="ClientOrders">
		 <xs:complexType>
		 <xs:sequence>
		 <xs:element ref="ClientOrder"/>
		 </xs:sequence>
		 </xs:complexType>
		 </xs:element></xs:schema>

清单 2: XMLBean 生成脚本

@rem Schema compiler
@rem
@rem Builds XBean types from xsd files.

@echo off

rem *** SET JAVA_HOME to the location of the Java 1.4 SDK
set JAVA_HOME=C:\JBuilderX\jdk1.4
set PATH=%JAVA_HOME%\bin
set cp=C:\xmlbeans\xkit\lib\xbean.jar

java -classpath %cp% com.bea.xbean.tool.SchemaCompiler %*

:done

  一旦运行了XMLBeans 工具,您将有一个.jar 文件,该文件包含了一些类,而这些类是ClientOrders.xsd XML 模式的对象表示。

  输出应当如下所示:

C:\xmlbeans\output>scomp ClientOrders.xsd
Loading schema file ClientOrders.xsd
Time to build schema type system: 3.655 seconds
Time to generate code: 12.107 seconds
Compiled types to xmltypes.jar

  把xmltypes.jar 文件重命名为ClientOrders.jar ,该Java 代码示例简单地实例化Java 类,并使用mutator方法来设置基于Northwind 数据库的示例值。在实际情况下,您很可能使用Java 技术(如JDBC 或EJB) 来访问数据库并获取实时数据。在构建适当的Java 对象之后,代码调用XMLText 方法获得表示客户和定单数据的XML 文件实例。使用ClientOrders.xsd XML模式可以使该XML 文件实例有效。然后把此XML 字符作为Web Service generateTestData 方法的结果进行传递。

  清单3 显示了使用ClientOrders.jar 来构建XML 文件实例的示例Java 代码。

清单3: ClientOrdersDAO.java

package com.justwebsolutions.articles.dotnetj2ee.datatransfer;

import com.justwebsolutions.articles.*;
import java.util.Calendar;

public class ClientOrdersDAO {

  public ClientOrdersDAO() {
  }

  public static String generateTestData() {

    // generate some data for client-orders
    ClientOrdersDocument xmlDoc = ClientOrdersDocument.Factory.?      newInstance();
    ClientOrdersDocument.ClientOrders clientOrder = ?      xmlDoc.addNewClientOrders();
    ClientOrderDocument.ClientOrder client = ?     clientOrder.addNewClientOrder();

    // add client information
    client.setCustomerId("ALFKI");
    client.setCompanyName("Alfreds Futterkiste");
    client.setFax("030-0076545");
    client.setPhone("030-0074321");
    // add order 1
    OrderDocument.Order order = client.addNewOrder();
    order.setOrderId(10643);
    Calendar cal = Calendar.getInstance();
    cal.set(1997, 8, 25);
    order.setOrderDate(cal);
    cal.set(1997, 8, 26);
    order.setRequiredDate(cal);
    cal.set(1997, 9, 2);
    order.setShippedDate(cal);

    // add order 2
    OrderDocument.Order order2 = client.addNewOrder();
    order2.setOrderId(10692);
    cal.set(1997, 10, 3);
    order2.setOrderDate(cal);
    cal.set(1997, 10, 31);
    order2.setShippedDate(cal);

    // obtain the XML document instance as a string and return
    return xmlDoc.xmlText();

  }

}

  ASP.NET 客户端页面的代码首先实例化了Web Service 代理并调用WebLogic Web Service。

// Call J2EE web service and obtain xml document
weblogic.BusinessDelegate proxy = new weblogic.BusinessDelegate();

// Obtain XML document instance
string xmlDoc = proxy.generateTestData();


  然后ASP.NET 客户端页面定义了DataSet,,把XML 读取到字符串中,使用ClientOrders.xsd 定义DataSet 结构,并使用已传递的XML 字符串装载DataSet。

DataSet dsClientOrder = new DataSet();
dsClientOrder.EnforceConstraints = false;
DataTable dataTable = new DataTable();

string schemaRelativePath = "~/Schemas/ClientOrders.xsd";
string schemaFullPath = HttpContext.Current.Server.MapPath(schemaRelativePath);

StringReader stringReader = new StringReader(xmlDoc);
XmlReader xmlReader = new XmlTextReader(stringReader);
dsClientOrder.ReadXmlSchema(schemaFullPath);
dsClientOrder.ReadXml(xmlReader, XmlReadMode.IgnoreSchema);

  接着ASP.NET 客户端页面将DataSet 绑定到dgClients 和dgOrders datagrids。

// now bind to DataGrids
dgClients.DataSource = dsClientOrder;
dgClients.DataMember = "ClientOrder";
dgClients.DataBind();

dgOrders.DataSource = dsClientOrder;
dgOrders.DataMember = "Order";
dgOrders.DataBind();

图2显示了代码完成之后的页面。

  我们从XML 模式对数据的验证中获益,在WebLogic中使用数据的对象表示,以直接向DataSet 装载数据的方式向ASP.NET 应用程序传递数据。然后我们就可以将诸如DataGrid 或DataList 的GUI对象直接绑定到DataSet 表格中。这就排除了通过Web Service 分析数据的需要。它也提供一种灵活的架构,在此架构中,更改传递到ASP.NET 应用程序的数据时不需要对界面进行更改。传递的数据不是由界面验证的,而是通过XML模式验证的。

原文出处

http://wldj.sys-con.com/read/48934.htm
 作者简介
Blair Taylor 是JustWebSolutions.com的总裁,这是一家专注于分布式系统的架构和开发的加拿大公司。Blair为几家出版社撰写过图书,内容涵盖了客户端-服务器和分布式技术,Blair获得了Java 和.NET 技术两方面的认证。
posted on 2005-11-17 13:10  球童  阅读(306)  评论(0编辑  收藏  举报