作者:翁 彦
时间:2003-7-24
欢迎大家同我联系,[email protected]
欢迎转载,转载请保留申明信息。
上次我谈了TOMCAT上如何快速开发Web service应用,并且举了个例子。但是传递的参数都是常见的数据类型,如果要传递复杂的数据类型,比如对象类型,那么应该如何来做呢。本篇,就是讨论这个问题。
我的方案是用一个string来实现,web service服务器端和客户端的复杂数据类型的交换。当然,这个string是一个xml格式字符串,它实现了复杂数据类型的存储。
那么,这个过程大致是这样的:
1 客户端发出SOAP的调用请求
2 服务端接受,从数据库中取出数据,并按要求加工成一个XML字符串
3 客户端接受xml字符串,并且解析出其中的信息。
反之,亦然。说道这里,应该说,这样的实现更本不难。那么,我们要解决的问题,是一套快速的开发方案,java开发中,使用对象来存储复杂的数据类型,vb中也有类的概念,那么当不同开发工具编写的程序进行数据交互通信的话,应该采用什么技术可以保证软件的开发速度和质量呢?这就是笔者本文的目的。
笔者认为,采用xml的专业设计工具来设计数据结构,利用第三方的开发工具,自动生成对应开发平台的源代码。这是较为快速和可靠的开发方法。
JAVA和VB都有相应的自动生成工具。JAVA是SUN Web Service Developer pack, VB有Microsoft SOAP ToolKit。简单说明如下:
1 利用XML SPY(XML设计工具)设计一个schema文件。
2 SUN Web Service Developer pack中jaxb可以根据schema自动生成java代码,编译成class文件。可以实现java程序把对象信息直接parse成xml字符串,和把xml字符串装载进来,初始化对象信息。
3 XML SPY把schema转换成xdr文件(xml data抽象文件),SOAP Toolkit中的Soap Message Object Generator自动生成VB类代码。功能同上。
下面,就让我们开始实践。
第一步,XML SCHEMA的设计
启动xml spy(如没有安装,下载并安装),新建一个schema文件,所有的设计都是可视化的。
保存,并得到一个EmployeeRoot.xsd文件。
第二步,自动生成java源程序。
先下载SUN Web Service Developer pack 1.1,安装并且按照文档配置环境。
在command窗口中,运行 %JAXB_HOME%\bin\xjc.bat EmployeeRoot.xsd -p com.sam.util.emp。命令成功后,会自动生成java源文件。
第三步,编译并且生成class代码。
在command窗口中,运行 %JAVA_HOME%\bin\javac com\sam\util\emp\*.java com\sam\util\emp\impl\*.java。
可以再运行jar命令打包。也可以运行javadoc为你的类生成技术文档。
第四部,建立一个Web Service,用于测试。
本例中,笔者使用的平台是TOMCAT+AXIS,大家可以看http://www.csdn.net/Develop/read_article.asp?id=19782 了解具体的配置。注意,请先把jaxb和jaxp的类库复制到$TOMCAT_HOME/axis/web-inf/libs下面。主要有:jaxb-api.jar, jaxb-libs.jar, jaxb-ri.jar, jaxb-xjc.jar, jaxp-api.jar。并把第三步得到的类库包也复制过来。
在axis目录下,创建一个EmpService.jws文件,代码如下:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.*;
import java.io.StringReader;
import java.io.StringWriter;
import com.sam.util.emp.*;
public class EmpService {
public String GetEmployees()
{
StringWriter sOut=new StringWriter();
try {
// create a JAXBContext capable of handling classes generated into
JAXBContext jc=
JAXBContext.newInstance("com.sam.util.emp" );
Unmarshaller u= jc.createUnmarshaller();
StringBuffer xmlStr=new StringBuffer
("<Employees><Employee><FirstName></FirstName>
<MiddleName></MiddleName><LastName></LastName><SSN>
</SSN></Employee><Version></Version></Employees>");
Employees emps=(Employees)u.unmarshal(
new StreamSource(new StringReader(
xmlStr.toString())));;
emps.getEmployee().clear();
Employee emp=new com.sam.util.emp.impl.EmployeeImpl();
emp.setFirstName("John");
emp.setMiddleName("");
emp.setLastName("Bob");
emp.setSSN("555-111");
emps.getEmployee().add(emp);
emp=new com.sam.util.emp.impl.EmployeeImpl();
emp.setFirstName("Tom");
emp.setMiddleName("");
emp.setLastName("Bill");
emp.setSSN("567-281");
emps.getEmployee().add(emp);
Marshaller m = jc.createMarshaller();
m.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT,
Boolean.TRUE );
StreamResult result = new StreamResult(sOut);
m.marshal(emps,result);
//System.out.println(sOut.toString());
} catch( JAXBException je ) {
je.printStackTrace();
return "";
}
return sOut.toString();
}
}
运行http://localhost:8080/axis/EmpService.jws?wsdl, 可以看到该Service文件对应的wsdl接口。第五步,利用xml spy中的convert dtd/schema,将employeeroot.xsd 转换成xml data文件(Employeeroot.xdr)。
转换出来的文件内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!-- edited with XML Spy v4.4 U (http://www.xmlspy.com) by weng yan (e-mao-e) -->
<!--XML-Data generated by XML Spy v4.4 U (http://www.xmlspy.com)-->
<Schema name="Untitled-schema" xmlns="urn:schemas-microsoft-com:xml-data" xmlns:dt="urn:schemas-microsoft-com:datatypes">
<ElementType name="Employee" model="closed" content="eltOnly" order="seq">
<group minOccurs="1" maxOccurs="1" order="seq">
<element type="FirstName" minOccurs="1" maxOccurs="1"/>
<element type="MiddleName" minOccurs="1" maxOccurs="1"/>
<element type="LastName" minOccurs="1" maxOccurs="1"/>
<element type="SSN" minOccurs="1" maxOccurs="1"/>
</group>
</ElementType>
<ElementType name="Employees" model="closed" content="eltOnly" order="seq">
<AttributeType name="xmlns" dt:type="string"/>
<attribute type="xmlns"/>
<group minOccurs="1" maxOccurs="1" order="seq">
<element type="Employee" minOccurs="1" maxOccurs="*"/>
<element type="Version" minOccurs="1" maxOccurs="1"/>
</group>
</ElementType>
<ElementType name="FirstName" model="closed" content="textOnly" dt:type="string"/>
<ElementType name="LastName" model="closed" content="textOnly" dt:type="string"/>
<ElementType name="MiddleName" model="closed" content="textOnly" dt:type="string"/>
<ElementType name="SSN" model="closed" content="textOnly" dt:type="string"/>
<ElementType name="Version" model="closed" content="textOnly" dt:type="string"/>
</Schema>
第六步,启动Visual Basic工程,如果安装过Soap ToolKit3的话,可以看到在Visual Basic中有一个add-in程序,叫Microsoft SOAP Messaging Object Generator,利用这个工具可以自动得到对应的vb类代码。利用这个工具,生成VB类代码,并且编译成一个ActiveX DLL。关于具体的内容,以后,我会在SOAP TOOLKIT工具使用介绍中专门解释。
第七步,编写客户端测试程序。在屏幕上放置一个文本框text1和list框list1。放置一个按钮cmdRead。
编写代码如下:
Private Sub cmdRead_Click()
On Error Resume Next
Dim SoapClient As Object
Dim sResult As String
Set SoapClient = CreateObject("MSSOAP.SoapClient30")
Call SoapClient.MSSoapInit2(Text1.Text, "", "", "EmpService", "")
If Err.Number <> 0 Then
MsgBox SoapClient.FaultString, vbExclamation
Exit Sub
End If
' Now the client can call an operation listed in the portType element
' specified when calling mssoapinit().
sResult = SoapClient.GetEmployees()
If Err.Number <> 0 Then
MsgBox SoapClient.FaultString, vbExclamation
Exit Sub
End If
Dim oSoap As MSSMO.ISoapMessagePart
Dim oDom As MSXML2.DOMDocument30
Dim oEmps As EmployeesRoot.Employees
Dim oEmp As EmployeesRoot.Employee
'now we parse the xml data into our class
Set oDom = New MSXML2.DOMDocument30
If oDom.loadXML(sResult) Then
Set oEmps = New EmployeesRoot.Employees
Set oSoap = oEmps
For Each oXMLNode In oDom.childNodes
If oXMLNode.nodeType = NODE_ELEMENT Then
If _
oXMLNode.baseName = oSoap.ElementName And _
oXMLNode.namespaceURI = oSoap.namespaceURI _
Then
Set oSoap.Element = oXMLNode
Exit For
End If
End If
Next
List1.Clear
For Each oEmp In oEmps.Employee
List1.AddItem oEmp.SSN & vbTab & oEmp.FirstName & "," & oEmp.MiddleName & "," & oEmp.FirstName
Next
End If
End Sub
运行,测试结果如下:
总结,通过这个例子,笔者认为,它为我们开发带来了一种新的概念和思路。利用xml进行数据结构的设计,而代码是基于设计的模式自动得到,采用这种开发方法使得,设计人员可以把精力集中在数据模型和业务逻辑上,而且,代码的维护成本也大大降低。
本文地址:http://com.8s8s.com/it/it17554.htm