ITPub博客

首页 > Linux操作系统 > Linux操作系统 > [转载]SOAP--新一轮竞争的三八线?(二)--例子与实验过程

[转载]SOAP--新一轮竞争的三八线?(二)--例子与实验过程

原创 Linux操作系统 作者:dinner1007 时间:2019-02-19 09:51:04 0 删除 编辑

SOAP--新一轮竞争的三八线?(二)--例子与实验过程


在本系列的 上一篇文章中,我们架设了了于"三八线"的环境--Microsoft环境的客户端和Linux与开放技术环境的服务器端,下面我们来看在这个架构下一个具体的例子。

应用例子的服务器端

这里假设了这样一个WEB Service,接受一个整数作为学号输入,返回这个学生的成绩记录(对象)。学生的成绩用一个叫Score的Java类来描述。而实际提供Web Service功能的是另一个叫QueryScore的类,这两个类很简单,完整的代码在 这里下载。

先来介绍QueryScore.java,它是为我们Web Service的提供者(Provider)类,它很简单,看上去也没有什么特别,也并不因为要提供Web Service而多声明什么(这就是Java的魅力之一),如清单1所示:

1  package bearsoaptest;
2 public class QueryScore {
3 public Score getScore(int StudentNo) {
4 Score s = new Score();
5 s.name = "Tiger";
6 s.physics = 5;
7 s.mathematics = 4;
8 System.out.println("got score" + s ); //For Debug at Server Console
9 return s;
10 }
11 }

清单1

QueryScore类只有第3行中定义的一个方法。由于这里只想对计算架构作说明,因此并没有实际到数据库中去取学生的成绩,无论学号是什么,都返回同样值的Score对象,相信在这里加上从数据库中取记录的代码对大家不是什么问题。

这个Web Service将返回自定义的Score类型的对象,因此将用到Java对象的序列化(Serialization),序列化器的功能是由Apache SOAP 2.1包中的 org.apache.soap.encoding.soapenc.BeanSerializer来提供的,序列化器的作用就是把一个Java对象表示成XML。实际上,这个序列化器还提供反向功能(Deserialization),就是把一个XML表示还原成一个Java对象。由于这个Web Service接收的参数是一个基本类型,因此不需要Deserializer,请注意区别XML Parser和序列化器是两回事。Parser仅仅是把XML建立成一个可以检索的内存结构模型――例如DOM。

对于Score.java,由于它需要被序列化后以便在网络上传输,基于Apache SOAP 2.1使用的序列化器的要求,Score.java要严格地写成一个Java Bean,否则无法正确地序列化。写成Bean无非是实现各个属性的setXXX和getXXX,在下面的清单2中列出开始的一部分代码,完整的代码请在 参考资料7处下载。

1    package bearsoaptest;
2 public class Score {
3
4 String name;
5
6 int physics = 0;
7 int mathematics = 0;
8
9 public String toString(
10 {
11 return "Score of " + name;
12 }
13 public void setName(String name) //出于Bean的需要
14 {
15 this.name = name;
16 return;
17 }
18 public String getName() //出于Bean的需要
19 {
20 return this.name;
21 }
22 ......

清单2

其实象清单2中的13行之后的代码,很多集成环境已经是可以自动生成的了,只要你告诉它你在写一个Java Bean。在Score.java中,我们实际上只是把要传送的数据放入到第4-7行的三个属性中。

这两个类在第1行都使用了package,为的是在部署的时候在同一个类目录下名字不冲突。

服务器端的代码就这么多,现在在服务器端只剩下最后一件事,部署(Deploy)这个Web Service。所谓部署,在Apache SOAP中,就是填一张表,告诉SOAP 的rpcrouter如何激活这个服务的class。用我们的客户端机器打开浏览器,在地址栏输入:
http://192.168.0.10:8080/soap

进入Admin和Deploy填写下列内容,在这里没有提到的就空着或者用默认值。

ID: urn:bearsoaptest:score
Scope: Request
Methods: getScore
Provider Type: Java
Provider Class: bearsoaptest.QueryScore
Static: No
Number of Mappings: 1
Encoding Style: SOAP
Namespace URI: urn:bearsoap
Local Part: ScoreRecord
Java Type: bearsoaptest.Score
Java To XMLSerializer: org.apache.soap.encoding.soapenc.BeanSerializer
XML To JavaDeserializer: org.apache.soap.encoding.soapenc.BeanSerializer


ID是在同一个服务器环境下用来区分每个Web Service的,在技术上可以是任意的字符串,不过W3C还是规定了它的命名规范。

Scope是指这个Web Service的生存期,Request表示就是一次调用,读者一定猜到还有Session和Application可选,一点儿都没错,Apache SOAP的状态管理与Apache Tomcat是一致的,与在JSP中调用Bean时的选项含义相同。

Provider Type是指Web Service由什么方法提供,我们这里显然是Java。

Provider Class指向提供Web Service的类。

Static指Provider是否是静态,如果是静态,多个QueryScore类就可以共享实例了。这个参数可能与运行效率和内存耗用有关,但我没有仔细测试过它。

Number of Mappings是指后面的表中有几行有效,在我们这个例子中只有一行,就是接下来几项,Encoding Style、Nanespace URI、Local Part三项是用来定义自定义的类bearsoaptest.Score序列化时在XML中的类型映射,在本文后面的XML清单中,你会看到刚才填写的这些值。最后两项指定序列化器和反序列化器,它们是纯Java的。

关于如何使用这个Deploy工具更详细的信息,请参阅 参考资料1的Part 2, Graham Glass给出了每一步完整的屏幕截图。

ScoreRecord这个Localpart的名字我是故意让它和原始的Score类不同名,以清楚地展现SOAP和语言及平台的无关性,说得更简单一点,一个Java Class(Score)被序列化成一个SOAP XML节点后(ScoreRecord)就和Java无关了,收到这个SOAP节点的一端只需想办法理解ScoreRecord就可以了,你可以把ScoreRecord 这个节点Deserializes成任何一种语言的对象,

当成功地Deploy了这个服务之后,还有一个小问题别忘了,编译这两个java程序,我们在/home/tuppin目录中编译它们,因为/home/tuppin已经被加入到了TOMCAT的CLASSPATH中,Apache SOAP的rpcrouter可以找到它们。
javac -d . Score.java
javac -d . QueryScore.java




回页首


应用例子的客户端

因为已经有了Graham Glass在 参考资料1中的例子,我就不想再编一个传递简单类型的例子了来浪费大家的时间了,既然是SOAP,我们就应该试一下Object而且是不同平台、不同语言的Object才够刺激:)。

在客户端,我建立一个名字叫vbclient.vbp的程序,完整的代码请在 参考资料7一节中下载,下面的清单3是最主要的一段代码的逐行注释:

Private Sub Command1_Click()
'这是文章《SOAP--新一轮竞争的三八线》中的例子程序
'作者:Tuppin
Dim Serializer As New SoapSerializer
'请注意这里的Serializer和Java对象的Serializer不是一回事
Dim Reader As SoapReader
Dim Connector As New HttpConnector '使用http协议
Command1.Enabled = False '防止手哆嗦产生代码重入
'以下指定URL到服务器192.168.0.10 Port=8080
Connector.Property("EndPointURL") = "http://192.168.0.10:8080/soap/servlet/rpcrouter"
Connector.Property("SoapAction") = "" 'Apache SOAP 2.1不需要指定Soap Action
Connector.Connect '连接
Connector.BeginMessage '准备发送SOAP请求
Serializer.Init Connector.InputStream '通过MS SOAP Toolkit内置的序列化器开始发送请求
Serializer.startEnvelope '生成标准的Envelope头
'为Apache SOAP 2.1指定两个Namespace,事实上这是XMLSchema所规定的,
' MS SOAP在这一版不自动支持,我们只好填上下面两行
Serializer.SoapNamespace "xsi", "http://www.w3.org/1999/XMLSchema-instance"
Serializer.SoapNamespace "xsd", "http://www.w3.org/1999/XMLSchema"
' 开始正文
Serializer.startBody "http://schemas.xmlsoap.org/soap/encoding/"
'下面这一行应该面熟吧,我们在服务器端Deploy QueryScore那个Java Class时填写的
'Methods、ID等等,后面一个是Namespace
Serializer.startElement "getScore", "urn:bearsoaptest:score", , "ns1"
'这个服务仅仅要求一个参数:学号,类型是xsd:int Java的int刚好和xsd:int相对应
'我们在这里把学号定为常数100
Serializer.writeXML "100"
Serializer.endElement
Serializer.endBody
Serializer.endEnvelope '生成Envelope尾,到此发送完成
Connector.EndMessage '结束发送,并取会响应结果
Set Reader = New SoapReader '准备处理回应
Dim s As New VBScore '创建VBScore对象,准备装传回的对象
Dim f As New SoapTypeMapperFactory
Dim m As ISoapTypeMapper
Reader.Load Connector.OutputStream
If Not Reader.Fault Is Nothing Then '如果有错就显示错误信息
strRs = Reader.Fault.Text
MsgBox Trim(Replace(strRs, Chr(10), vbCrLf)) '把Unix换行改为MS换行
Else
Set m = f.getMapper(enXSDstring, Nothing)
'read的最后一个参数是MS保留的,现在没用
s.name = m.read(Reader.RPCResult.selectSingleNode("name"),_
"", enRPCEncoded, 0) '取name的值
Set m = f.getMapper(enXSDint, Nothing)
s.physics = m.read(Reader.RPCResult.selectSingleNode("physics"),_
"", enRPCEncoded, 0) '取physics的值
s.mathematics = m.read(Reader.RPCResult.selectSingleNode("mathematics"),_
"", enRPCEncoded, 0) '取mathematics的值
'简单地现实VBScore对象各个属性的值,现在是强类型的了
MsgBox s.name + " " & Str(s.physics) + " " & Str(s.mathematics)
End If
Command1.Enabled = True '恢复按钮允许再次执行
End Sub

清单3

运行这个程序,按Command1按钮,至此,我们看到了我们所期待的结果,服务器端的Java Score 对象中的内容被传递到客户断VB Score对象中。但是有些需要注意的问题是,目前的VB 与C++中的所有数据类型与XML Schema中的数据类型不完全兼容,在开发过程中需要对这些类型作一些些特殊处理,例如,目前在VB6中int仍然是16bit的,而在XML Schema和Java中都是32bit的。不过,在Microsoft将来的C#和VB.net中,基本的或者称原生(Primitive)的类型将与XML Schema和Java的类型完全对应,这是一个好消息,这样我们可以更平滑地在这两个世界中交换数据。

目 前的Microsoft SOAP Toolkit 2无法自动地Serializes和Deserializes一个用户自定义的类,无论是C++的还是VB的、也无论是它自己产生的还是第三方系统的,每 一个需要用SOAP来传递的VB或C++对象必须手工地去实现一个被称为ISoapTypeMapper的接口。而对于其它系统产生的对象,除非利用 WSDL(Web Service Description Language),我们可以使用ISoapTypeMapper,目前只能象我们程序中那样处理(自己去Deserializes)。我希望在下一篇文 章中讨论WSDL在这种架构下的应用。关于这一点确实远远没有Java方便(见 参考资料1中的Part 3),在Java中只需要把通过SOAP RPC传递的类写成一个标准的Bean就可以了,这个限制的很大原因归于C++和VB以及COM的语言特性和体系结构,在将来的.net中,这些限制都将成为历史,这也是.net被Microsoft力推的一个重要技术原因。




回页首


过程回顾

其实SOAP RPC的工作原理并不是很复杂,在我们的这个实验中,当你完成一次SOAP RPC时,整个系统内部经过了这样一系列主要动作:

  1. 客户端用DOM接口把RPC请求按照SOAP规范打包成XML,底层是用Microsoft 的 XML Parser中的DOM接口来实现。
  2. 建立到服务器端的HTTP连接,使用HTTP的post方法发送这个SOAP请求(1中生成的XML表示)到 http://192.168.0.10:8080/soap/servlet/rpcrouter
  3. 一 个通用的Java Servlet--被称为SOAP RPC侦听器的rpcrouter收到这个请求后用XML4J(xcerces.jar)中的DOM接口Parse这个请求,然后使用urn: bearsopetest:score这个ID在自己的deploy的list中查找,检查这个服务是否存在,方法、参数等是什么?
  4. 如果找到,并且参数的个数、类型都正确,就调用这个服务(在我们的例子中就是那个QueryScore.class),调用后取得结果--Score的实例。
  5. 先将Score的实例Serialize成XML,再次用XML4J(xcerces.jar)中的DOM接口打包结果成SOAP回应(也是XML),然后通过http的response返回给客户端。
  6. 客户端收到这个回应后,用MS-XML DOM parse这个回应,然后显示结果。


根据上述过程,相信读者可以很容易地把我们用到的部件在本文第一部分的图1中对号入座。

我们利用一个Microsoft提供的监视工具(Apache SOAP中也有一个类似的工具,在 参考资料1的Part 3中有完整的屏幕截图和用法),截获了请求和应答的XML(不要因此而担心SOAP的安全问题,如果不希望传送明文,可以使用HTTPS)在下面的 清单4清单5中,可供大家回忆前面的程序注释和各种设置。


xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
"http://schemas.xmlsoap.org/soap/encoding/">

100



清单4,请求的XML


xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">

SOAP-ENV:encodingStyle=
"http://schemas.xmlsoap.org/soap/encoding/">

5
Tiger
4




清单5 应答的XML

至此,我们完成了这个能粗略覆盖整个架构的例子实践,在本系列的下一篇文章中,我们将比较深入地探讨这个架构的特点和优劣,以及作者对于SOAP的一些观点。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/374079/viewspace-130727/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2018-08-23

  • 博文量
    1013
  • 访问量
    735133