六、服务的访问
GET方式的服务访问
一般的SOAP消息都是采用POST方式实现传递,但也可以通过GET方式来访问。比如以下给出的一个服务——“HelloWorld”,其源码如下:
文件HelloWorld.jws
public class HelloWorld
{
public String helloWorld()
{
System.out.println( "Hello World!" );//在服务器端打印输出
return "Hello World!";//返回相应字符串
}
}
这个服务给出一个名为“helloWorld”的无入口参数的操作,返回一个内容为“Hello World!的字符串”,同时在服务器端打印“Hello World!”,将该文件放到“……\webapps\axis”目录下,即可通过GET方法直接访问该服务,访问的地址为http://localhost:8080/axis/HelloWorld.jws?method=helloWorld,可以看到返回的SOAP信封消息,同时服务器端给出了相应的显示信息“Hello World!”这表明HelloWorld服务被成功访问了,生成的SOAP信封消息为:
<?xml version="1.0" encoding="UTF-8" ?>
- <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <soapenv:Body>
- <helloWorldResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<helloWorldReturn xsi:type="xsd:string">Hello World!</helloWorldReturn>
</helloWorldResponse>
</soapenv:Body>
</soapenv:Envelope>
七、客户端服务访问编程
Axis提供了一套API来实现SOAP,从http://localhost:8080/axis/docs/apiDocs/index.html可以看到Axis的API文档。
其中,org.apache.axis.client.Call和org.apache.axis.client.Service是两个比较常用的类,一般的客户端程序欲访问一个Web Service时,都要生成一个客户端的Service对象和Call对象,在访问服务之前,首先要对Call对象设置相应的参数,包括服务的位置、操作名、入口参数、返回值类型等,最后调用Call对象的invoke方法访问服务。
以下给出了一个客户端访问Web服务的例程——AXISTest.java:
文件AXISTest.java
package axisexercise;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.encoding.XMLType;
import javax.xml.rpc.ParameterMode;
public class AXISTest
{
public static void main( String[] args ) throws Exception
{
创建service和call对象,这些对象是标准的JAX-RPC对象,这些对象用于存储服务调用的数据(metadata)。
Service service = new Service();
Call call = ( Call ) service.createCall();
//////////访问即时发布的Distance服务
//设置访问点
call.setTargetEndpointAddress( "http://localhost:8080/axis/Distance.jws" );
//设置操作名
call.setOperationName( "convertMile2Kilometre" );
//设置入口参数
call.addParameter( "op1", XMLType.XSD_DOUBLE, ParameterMode.IN );
//设置返回参数类型
call.setReturnType( XMLType.XSD_DOUBLE );
Double d1 = new Double( 190 );
//调用服务,在invoke方法中传入的是包含调用参数的数组
System.out.println( d1 + " 英里相当于 " +
call.invoke( new Object[] {d1} ) + " 公里!" );
//////////访问定制发布的Capacity服务
call = ( Call ) service.createCall();
//设置访问点
call.setTargetEndpointAddress( "http://localhost:8080/axis/services/Capacity" );
//设置操作名
call.setOperationName( "convertGallon2Litre" );
//设置入口参数
call.addParameter( "op1", XMLType.XSD_DOUBLE, ParameterMode.IN );
call.setReturnType( XMLType.XSD_DOUBLE );
d1 = new Double( 10.00 );
//调用服务
System.out.println( d1 + " 加仑相当于 " +
call.invoke( new Object[] {d1} ) + " 升!" );
} //main()
}/* AXISTest */
编译运行后运行可以看到以下的结果:
190.0英里相当于305.71公里!
10.0加仑相当于45.46升!
注意程序在访问即时发布的Distance服务和定制发布的Capacity服务时的不同,前者的服务访问点地址为http://localhost:8080/axis/HelloWorld.jws,而后者的则为http://localhost:8080/axis/services/Capacity。
八、服务类型:RPC, Document, Wrapped, and Message
在Axis中,有四种服务类型:
1. RPC服务:
PRC服务是AXIS中的默认服务,当你通过<service ... provider="java:RPC"> or <service ... style="RPC">标签进行部署的时候,使用的就是RPC服务。RPC服务遵循SOAP RPC和其编码规范。AXIS可以将XML反序列化成java对象,并将其传给服务的方法。并且可以将服务的方法返回的JAVA对象序列化成XML。
2.Document / Wrapped services
Document services and wrapped services are similar in that neither uses the SOAP encoding for data; it's just plain old XML schema. In both cases, however, Axis still "binds" Java representations to the XML (see the databinding section for more), so you end up dealing with Java objects, not directly with XML constructs.
Document和Wrapped服务都不使用SOAP编码数据,这一点是他们相似的地方。他们仅仅使用旧的XML模式。然而,在这两种服务中,AXIS将捆绑Java的表示到XML文档中,所以你最终处理的是java对象而不直接处理XML。
下面是包含定单的一个简单的SOAP消息,你可以看到Document 和 Wrapped 服务的区别所在:
<soap:Envelope xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<soap:Body>
<myNS:PurchaseOrder xmlns:myNS="http://commerce.com/PO">
<item>SK001</item>
<quantity>1</quantity>
<description>Sushi Knife</description>
</myNS:PurchaseOrder>
</soap:Body>
</soap:Envelope>
相应的XML模式如下:
<schema targetNamespace="http://commerce.com/PO">
<complexType name="POType">
<sequence>
<element name="item" type="xsd:string"/>
<element name="quantity" type="xsd:int"/>
<element name="description" type="xsd:string"/>
</sequence>
</complexType>
<element name="PurchaseOrder" type="POType"/>
</deployment>
对于Document类型服务,他将映射成下面的方法:
public void method(PurchaseOrder po)
八、soap envolop(soap信封)
1. soap信封
在客户端发出服务请求以及服务端返回请求结果的时候,在网络中传输的是SOAP信封。首先客户端程序将请求参数及请求的方法序列到XML的文件中(SOAP信封),并将SOAP信封传送到服务器端。服务器端接受到SOAP信封后,将解析这个SOAP信封并反序列化调用参数及方法并将该方法的调用结果封装成SOAP信封(序列到XML的文件中)返回给客户端,客户端同样将SOAP信封中封装的返回结果反序列化为想要得到的结果。
我们来看下面这段客户端程序的SOAP信封:
(1) 客户端程序:
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import javax.xml.namespace.QName;
public class TestClient
{
public static void main(String [] args)
{
try
{
String endpoint = "http://nagoya.apache.org:5049/axis/services/echo";
Service service = new Service();
Call call = (Call) service.createCall();
call.setTargetEndpointAddress( new java.net.URL(endpoint) );
call.setOperationName(new QName("http://soapinterop.org/", "echoString"));
String ret = (String) call.invoke( new Object[] { "Hello!" } );
System.out.println("Sent 'Hello!', got '" + ret + "'");
}
catch (Exception e)
{
System.err.println(e.toString());
}
}
}
(2) SOAP信封:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<ns1:echoString xmlns:ns1="http://soapinterop.org/">
<arg0 xsi:type="xsd:string">Hello!</arg0>
</ns1:echoString>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
2. 参数命名:
在上面的代码中,AXIS自动将在Soap消息中的函数调用参数命名为arg0,arg1等等,如果你想按照自己定义的参数名调用方法的话,很简单,在你调用invoke函数之前只要调用addParameter()函数即可。如下所示:
call.addParameter("testParam",
org.apache.axis.Constants.XSD_STRING,
javax.xml.rpc.ParameterMode.IN);
call.setReturnType(org.apache.axis.Constants.XSD_STRING);
将testParam定义为调用函数的第一个参数(这里也只有一个参数),这里也可以同时定义该参数的类型以及该参数是输入、输出还是输入输出类型。在这里它是一个输入类型,现在当你运行程序,你将得到下面的消息:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<ns1:echoString xmlns:ns1="http://soapinterop.org/">
<testParam xsi:type="xsd:string">Hello!</testParam>
</ns1:echoString>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
3. 返回类型
在上面的代码中我们知道echoString函数将返回一个String对象,而且我们也希望通过客户端的调用能够返回预期的String对象。下面是一个典型的通过调用echoString函数后获得的Soap信封(消息)。
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<ns1:echoStringResponse xmlns:ns1="http://soapinterop.org/">
<result xsi:type="xsd:string">Hello!</result>
</ns1:echoStringResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
我们可以看到这里已经声明了返回类型(<result xsi:type="xsd:string">)是一个String对象。这样Axis就可以将返回结果反序列化成我们想要的String对象了。
很多工具都会将这种确定的类型信息放到XML文件中,以生成消息的“自我描述部分”,另一方面,还有一些工具是象下面这样返回响应的:(Many toolkits put this kind of explicit typing information in the XML to make the message "self-describing". On the other hand, some toolkits return responses that look like this:)
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<ns1:echoStringResponse xmlns:ns1="http://soapinterop.org/">
<result>Hello, I'm a string!</result>
</ns1:echoStringResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
在这里并没有返回类型,那么我们怎么知道应该将返回结果反序列化成什么类型的结果呢?答案是metadata,在这种情况下,我们需要一个描述来指明我们期望的返回类型,下面这行代码说明了在客户端应该如何去做:
call.setReturnType( org.apache.axis.Constants.XSD_STRING );
这个方法将会告诉Axis客户端,如果返回的结果没有指明类型的话,那么Axis将会把返回类型指明为xsi:type属性所预定义的SOAP类型,在这里XSD_STRING属性所指明的是String类型。
所以也有这样一个相似的方法,允许你指定所期望返回的Java的类。
call.setReturnClass(String.class);
http://blog.csdn.net/tenwang1977/archive/2004/09/06/95991.aspx