【旧文】web service与axis(3)
五、利用axis开发客户端web服务
如果要使用对方提供的web服务,首先必须要有该web服务WSDL的URL,类似http://localhost:8090/webserviceTest/services/wstest?wsdl ,并对WSDL有着一定的了解。
axis支持三种web服务客户端的开发方式,分别是:
Ø 动态调用接口(Dynamic Invocation Interface)
Ø 动态代理服务(Dynamic Proxy)
Ø 静态票根(static stub)
下面分别给予介绍。
1. 动态调用接口
首先看示例代码:
package com.ufgov.webservice.client; import java.net.URL; import javax.xml.namespace.QName; import org.apache.axis.client.Call; import org.apache.axis.client.Service; public class WsTestClient { private String UrlString = "http://localhost:8090/webserviceTest/services/wstest?wsdl"; private String nameSpaceUri = "http://localhost:8090/webserviceTest/services/wstest"; public String getNameDII(){ try{ Service service = new Service(); Call call = (Call) service.createCall(); call.setOperationName(new QName(nameSpaceUri,"getName")); call.setTargetEndpointAddress(new URL(UrlString)); String name = (String) call.invoke(new Object[]{}); return name; } catch(Exception e){ e.printStackTrace(); } return null; } public static void main(String[] args){ String name = ""; WsTestClient wsTestClient = new WsTestClient(); name = wsTestClient.getNameDII(); System.out.println("getName():" + name); } }
几点说明:
a. 在编写web服务客户端代码时,我们需要获得WSDL的URL,如http://localhost:8090/webserviceTest/services/wstest?wsdl ;需要获得web服务的URL,如http://localhost:8090/webserviceTest/services/wstest;需要获得web服务的名称,如WsTestService;需要获得web服务的端口,如wstest。
WSDL的URL一般由合作伙伴提供;web服务的URL一般是把WSDL的URL去掉后面的参数(即:“?wsdl”字样);web服务的名称对应WSDL文档里service元素的name属性;web服务的端口对应prot元素的name属性。
b. call.setOperationName()方法接受一个QName类型的参数,实例化一个QName对象需要提供web服务的URL和要调用的web服务方法。
c. call.invoke()方法接受一个Object数组参数,数组各个成员是传递给要调用的web服务方法的参数列表。
d. 如果要调用的web服务方法返回一个自定义对象,那么在客户端也需要注册自定义对象的序列化/反序列化器,代码如下:
Service service = new Service(); Call call = (Call) service.createCall(); QName qn = new QName("urn:BeanService","WsBean"); call.registerTypeMapping(WsBean.class,qn,new BeanSerializerFactory(WsBean.class,qn),new BeanDeserializerFactory(WsBean.class,qn)); call.setOperationName(new QName(nameSpaceUri,"getWsBean")); call.setTargetEndpointAddress(new URL(UrlString)); WsBean bean = (WsBean) call.invoke(new Object[]{"myname",new Integer(20)});
2. 动态代理服务
首先需要编写代理接口,这个接口必须继承java.rmi.Remote接口,接口提供的方法是web服务提供的所有方法的声明,并且每个接口都要抛出java.rmi.RemoteException异常,如:
package com.ufgov.webservice.client; public interface WsTest extends java.rmi.Remote { public java.lang.String getName() throws java.rmi.RemoteException; public com.ufgov.webservice.client.WsBean getWsBean(java.lang.String name, int age) throws java.rmi.RemoteException; }
编写客户端代码,使用动态代理服务访问web服务,示例代码如下:
package com.ufgov.webservice.client; import java.net.URL; import javax.xml.namespace.QName; import javax.xml.rpc.ServiceFactory; import javax.xml.rpc.Service; public class WsTestClient { private String UrlString = "http://localhost:8090/webserviceTest/services/wstest?wsdl"; private String nameSpaceUri = "http://localhost:8090/webserviceTest/services/wstest"; private String serviceName = "WsTestService"; private String portName = "wstest"; public String getNameDynamicProxy(){ try{ URL serverUrl = new URL(UrlString); ServiceFactory serviceFactory = ServiceFactory.newInstance(); javax.xml.rpc.Service service = serviceFactory.createService(serverUrl,new QName(nameSpaceUri,serviceName)); WsTest wsTest = (WsTest)service.getPort(new QName(nameSpaceUri,portName),WsTest.class); String name = wsTest.getName(); return name; } catch(Exception e){ e.printStackTrace(); } return null; } public static void main(String[] args){ String name = ""; WsTestClient wsTestClient = new WsTestClient(); name = wsTestClient.getNameDynamicProxy (); System.out.println("getName():" + name); }
说明:
代理接口可以自己手工编写,这需要对WSDL比较熟悉,能够从中抽象出web服务所提供的所有方法及其参数列表、返回值类型等。还有一种选择是利用axis提供的工具生成代理接口,具体方法参见静态票根部分。
如何用动态代理的方法调用返回自定义对象的web服务方法,暂无相关资料。
3. 静态票根
要使用静态票根方法访问web服务,首先必须借助axis生成客户端代码。打开命令行窗口,转到AXIS目录下的WEB-INF子目录。确保Tomcat服务已经处于启动状态,键入命令 :
Java org.apache.axis.wsdl.WSDL2Java http://localhost:8090/webserviceTest/services/wstest?wsdl
该命令执行的结果是在当前所在目录下产生一个子目录,localhost\webserviceTest\services\wstest,该目录下有4个java源文件,分别是:
Ø WsTest.java:定义了web服务代理接口,提供了web服务提供的所有方法的声明参见动态代理服务部分。
Ø WsTestService.java:定义了用于获取Web服务接口的方法。
Ø WsTestServiceLocator.java:接口WsTestService的具体实现。
Ø WstestSoapBindingStub.java:Web服务客户端票根,通过该类与服务器交互。
命令执行后,在当前所在目录还产生一个子目录,BeanService,该目录下有自定义对象的源文件:
ü WsBean.java:web服务提供者自定义的类。
将自动生成的java源文件拷贝到项目合适的地方,并编译。
编写代码访问服务,如下:
package com.ufgov.webservice.client; public class WsTestClient { public String getNameStaticStub(){ try{ WsTestService service = new WsTestServiceLocator(); WsTest wsTest = service.getwstest(); String name = wsTest.getName(); return name; } catch(Exception e){ e.printStackTrace(); } return null; } public static void main(String[] args){ String name = ""; WsTestClient wsTestClient = new WsTestClient(); name = wsTestClient.getNameStaticStub(); System.out.println("getName():" + name); } }
说明:
a. 执行WSDL2Java命令自动生成的子目录结构不是固定的,跟WSDL的URL有关系;
b. 自动生成的java源文件的名称不是固定的,跟web服务的名称有关系。
c. 在示例中我将自动生成的代码放在了跟客户端代码WsTestClient.java同样的包中,所以不必引入自动生成的类,否则,需要引入自动生成的类。
d. 使用静态票根调用返回自定义对象的web服务方法时,代码与调用返回XML Schema内置简单类型的方法无任何不同。
六、其他
axis还支持所谓的自动部署,自动部署相当简单,但是限制也较多,网上有许多资料可以参考。个人感觉在真正的项目开发中,恐怕很少有人使用自动部署,更多的是选择通过WSDD自定义部署,也就是我们在第四部分介绍的。
(未完待续……)