Axis 1.1 for Java进行Web Services开发
用Axis 1.1 for Java进行Web Services开发 下面的所有几乎来自Axis1.1的文档。但不完全来自文档,本人做了部分修改,这些修改完全出自国内读者的需要。 什么是SOAP? SOAP是一个基于XML的用于应用程序之间通信数据编码的传输协议。最初由微软和Userland Software提出,随着不断地完善和改进,SOAP很快被业界广泛应用,目前完全发布版本是1.1。在其发展过程中,W3C XML标准工作小组积极促成SOAP成为一个真正的开放标准。在写作此文档之时,SOAP1.2草案已经发布,1.2对1.1中相对混乱的部分做了改进。 SOAP被广泛作为新一代跨平台、跨语言分布计算Web Services的重要部分。 这里太肤浅的说明,请参阅我的整理《一步一步学习SOAP》。 什么是Axis? Axis本质上就是一个SOAP引擎,提供创建服务器端、客户端和网关SOAP操作的基本框架。Axis目前版本是为Java编写的,不过为C++的版本正在开发中。 但Axis并不完全是一个SOAP引擎,它还包括: 是一个独立的SOAP服务器。 是一个嵌入Servlet引擎(例如Tomcat)的服务器。 支持WSDL。 提供转化WSDL为Java类的工具。 提供例子程序。 提供TCP/IP数据包监视工具。 Axis是第三代Apache SOAP,从2000年起,SOAP v2开发小组开始讨论如何让Axis更加灵活、可配置,以及能够处理SOAP和来自W3C的各种XML标准。通过不断地讨论和代码编写,Axis目前取得了如下成果: 速度提高。 Axis通过基于事件的SAX对XML文档进行处理,从而在速度和效率上比Apache SOAP有所提高。 灵活性提高。 稳定性提高。 提供面向组件的部署。 提供一个简洁的传输抽象框架。其核心引擎完全于传输方式独立。从而使基于何种协议传输的选择更加灵活。 支持WSDL。包括到处WSDL和客户代理生成等。 在目前发行1.1版本中有什么东西? SOAP1.1/1.2引擎。 灵活的配置和部署系统。 支持及时自动生成SOAP服务(JWS)。 支持所有的基本数据类型,为自定义串行操作提供类型映射系统。 JavaBean的自动串行操作,包括将自定义属性类型映射到XML的属性和元素。 RPC和基于消息的SOAP服务提供者。 从部署好的服务自动生成WSDL。 WSDL2Java工具可以从WSDL描述文件中产生相应的客户和服务器端SOAP操作框架。 初步提供安全扩展,能够与Servlet2.2安全集成。 通过HTTP Cookie和与传输无关的SOAP头信息提供会话跟踪。 初步支持带附件的SOAP消息。 在EJB方面提供把EJB作为Web服务的访问途经。 基于Servlet的HTTP传输。 基于JMS的传输。 独立的服务器(但需要HTTP 服务器和Servlet容器支持)。 提供客户端、服务器端相关应用程序的样例。 Axis的运行需要如下组件包 axis.jar jaxrpc.jar saaj.jar commons-logging.jar commons-discovery.jar wsdl4j.jar 符合JAXP-1.1的XML处理器。 一步一步开始用Axis进行Web Services操作 下面给出一段简单的调用Web Services方法的客户端代码(由于原文档中直接用导入包的方式初学者不易了解那个类在那个包中,所以下面我做了一些简单的修改,希望能给学习者清晰的思路): public class TestClient { public static void main(String[] args) { try{ String endpoint="http://localhost:8080/axis/SayHello.jws?wsdl";// 调用的web服务的url地址,这里是一个http请求,希望得到的结果是wsdl文档。 org.apache.axis.client.Service service=new org.apache.axis.client.Service();//建立请求服务框架实例。 /* * org.apache.axis.client.Service实现JAX-RPC's javax.xml.rpc.Services接口 * 该接口充当产生下面提到的org.apache.axis.client.Call实例 * 的角色。 */ org.apache.axis.client.Call call=(org.apache.axis.client.Call)service.createCall();//从框架中生成一个维护调用的实例。 /* * org.apache.axis.client.Call实现了JAX-RPC's javax.xml.rpc.Call接口。 */ call.setTargetEndpointAddress(new java.net.URL(endpoint)); call.setOperationName(new javax.xml.namespace.QName("http://www.edu-edu.com.cn/luopc/ws","echoString"));//设置需要调用的函数名称 String result=(String)call.invoke(new Object[]{"hello!"}); System.out.println(result); }catch(Exception e){ System.err.println(e.toString()); } } } 上面的代码可能和原文档中不同,并且在名称空间、函数多态上会给用户造成糊涂。不过别急,我在翻译手册的同时会加入很多解释的代码,如果哪位纯粹看不懂可以通过邮件获取帮助:[email protected] ,邮件主题必须是我提供的文档名称。 通过上面的调用代码,最终生成向服务器请求SOAP信息包,具体XML内容如下: <?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://www.edu-edu.com.cn/luopc/ws"> <arg0 xsi:type="xsd:string">Hello!</arg0> </ns1:echoString> </SOAP-ENV:Body></SOAP-ENV:Envelope> 这里我不再多少,细心的朋友请从代码中找相应的对应信息来进行自己的逻辑理解。至于SOAP协议在我以后的翻译文档中会加入进去。 从上面的代码中我们在调用的时候输入了参数new Object[]{“hello!”}。然后从生成的SOAP请求包中可以看到自动序列化成<arg0 xsi:type="xsd:string">Hello!</arg0>。你可以看到参数名称为arg0,类型为xsd:string。其实在Axis客户端我们可以直接通过具体的方法来设置每一个参数名称、类型以及返回值类型。如下代码: call.addParameter("testParam", org.apache.axis.Constants.XSD_STRING, javax.xml.rpc.ParameterMode.IN);call.setReturnType(org.apache.axis.Constants.XSD_STRING); 加入上面的代码之后生成如下的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://www.edu-edu.com.cn/luopc/ws"> <testParam xsi:type="xsd:string">Hello!</testParam> </ns1:echoString> </SOAP-ENV:Body></SOAP-ENV:Envelope> 可以作简单的对比。 也许你会疑惑设置参数名称和不设置参数名称有什么区别的疑问。这里作简单的解释: 1. 为什么要call.setReturnType(org.apache.axis.Constants.XSD_STRING)? 上面你可以调用或者可以不调用,但当返回结果中没有标明数据类型时Axis就不知道如何进行数据类型转换。当然如果返回类型你很清楚并且返回应答SOAP的结果中表明了相应的数据类型你便可以不进行上面的函数调用。 2. 为什么要设置参数名称和类型? 好了,下在你知道了如何调用Web Services了,下面告诉你如何写作和发布Web Services。 通过Axis发布Web Services 这里写作一个简单的类,然后一步一步进行发布。希望用户能够从中理出一些思路来。我在其他的关于Web Services的文章中会专门针对Web Services的通用发布方法。虽然Web Services牵涉到很多复杂的知识,但请大家不要感觉到这些操作简单,也许你已经有很多疑问,没关系,记下你的疑问,不断的投试。 public class SayHello { public String echoString(String hello){ return hello; }} 哈哈,这个类是不是太简单了。 一步一步来。 Axis提供两种将Java类发布成Web Services的途径,即即时快速自动发布和通过配置文件进行发布。我们首先从最容易部署的入手。 JWS----即时部署 简单说就是将自己写的Java类源文件按一定的规则Copy到特定的目录下便可自行被Axis部署。具体步骤如下: 将上面写的SayHello.java复制到axis目录下。 改名为SayHello.jws。 注意:在你写的类中不能有具体包的信息,因为这正是Axis即时部署不支持的。 运行我们前面写的客户端进行测试,运行结果是hello!。 目前你是否有如下的问题? 如果类中用多态的函数将如何处理? 其实很简单,我们知道在每次发出调用请求之前代理程序在后台会直接请求你给的URL,这里是http://localhost:8080/axis/SayHello.jws?wsdl,其实这一请求返回来的是WSDL描述文件,通过具体的描述文件的内容和你输入的参数的类型比较,最终确定发送什么请求。细节上的解释需要用户阅读SOAP的具体内容。我也会提供相应的权威文当翻译的。 Axis的客户端默认就是通过HTTP协议传输吗? 如何将自己定义的类型进行映射? 通过WSDD自定义部署 上面的自动部署相当简单,但当你需要 映射自己的类型时 不需要暴露源代码时 需要自己的路径和包管理时 对用户操作Web Services的事件进行相应时 就需要通过WSDD来自定义部署。 前面新特性中提到过,Axis是一个很灵活的可配置系统,但在配置之前你得懂得Axis Web Services描述文档(WSDD)的格式和意义。这里有一个简单的例子(deploy.wsdd): <deployment xmlns="http://xml.apache.org/axis/wsdd/" 很简短的描述就会自定义对特定类以Web Services的形式发布。上面的每一个service项都会意味着开通一个相应的可被WSDL文件引用的服务。其内部描述信息将会描述从请求-处理请求-应答需要的所有核心信息。这里provider=”java:RPC”对应着相应的服务类为org.apache.axis.providers.java.RPCProvider。其实你可以通过多种方式提供相应的服务。在关于Axis的架构文章中将会详细解释这些内容。 上面的各个参数我不再解释,我想大家一看就明白。 下面让我们在上面的简单配置上开始一步一步的进行各种高级配置: 服务存活范围 Axis提供Session、Request和Application三种可选范围配置。具体配置标记为: <service name="MyService"...> 一旦你完成上面的文件。可以写一个脚本批处理文件来完成部署。批处理文件如下: java -classpath F:\resource\tools\axis-1_1\lib\axis.jar;F:\resource\tools\axis-1_1\lib\commons-discovery.jar;F:\resource\tools\axis-1_1\lib\jaxrpc.jar;F:\resource\tools\axis-1_1\lib\commons-logging.jar;F:\resource\tools\axis-1_1\lib\log4j-1.2.8.jar;F:\resource\tools\axis-1_1\lib\wsdl4j.jar;F:\resource\tools\axis-1_1\lib\j2ee.jar org.apache.axis.client.AdminClient sayHelloD.wsdd。 上面的一些jar文件都是Axis运行需要的组件,所以必须添加到环境中。上面的目录是我的机器里的目录,你可以按自己的目录进行。 如果部署成功,会输出<Admin>Done processing</Admin>信息。 但本人这里再强调几个: 你首先要将你编译好的类放到axis/web-inf/classes/下面。 可以通过http://localhost:8080/axis/services/SayHello2来调用。 你可以从我的配置文件中发现了包的概念。 可以用相应的xml文件进行卸载已部署的服务。 卸载方法如下: 编写如下XML文档 <undeployment xmlns="http://xml.apache.org/axis/wsdd/"> 把上面的批处理文件中的sayHelloD.wsdd换成该文件便可。 继续关注高级部署 如果你想知道自己的某个Web Services被调用多少次,你应该怎么做呢? Axis提供了相应的跟踪机制。 首先你应该编写一个满足一定接口的事件处理类。 在配置文件中添加事件处理器信息。 我们先看看配置文件中的信息: <deployment xmlns="http://xml.apache.org/axis/wsdd/" 上面的绿色部分起到核心的配置信息提供。 下面提供一个事件处理类,同样来自原文档,但为了更清晰我同样将所有的类前面加上了包名称。 package luopc.ws; /** * @author luopc */ public class EventHandler extends org.apache.axis.handlers.BasicHandler{ public void invoke(org.apache.axis.MessageContext mtxt){ String param=(String)getOption("parameter1"); System.out.println(param); } public static void main(String[] args) { } } 就这样,我们对请求跟踪了。嘻嘻。 可以远程进行管理(不推荐) 前面就提到服务类型的问题,在Axis有四种类型的服务,分别为RPC、Document、Wrapped和Message。 |
本人按照网上例子制作一个Sample,遇到一个问题,当用JAVA编写的客户端调用返回值类型是int的函数时能正确得到返回值,但是调用返回值类型是String的函数时,不能正确得到返回值。以下为服务器端程序源代码: /** * 此处插入类型描述。 * 创建日期:(2005-10-27 10:32:48) * @author:Administrator */ import java.util.*; public class ZxjTest { protected String name="gaga"; protected int age=20; protected int sex=22; protected List items=new ArrayList(); /** * ZxjTest 构造子注解。 */ public ZxjTest() { super(); } public String getName() { return name; } public int getAge() { return age; } public int getSex() { return sex; } public List getItems() { return items; } } 客户端调用的源代码: String endpoint = "http://myserver:7001/ZxjTest.jws"; Service service = new Service(); Call call = (Call) service.createCall(); call.setTargetEndpointAddress(new java.net.URL(endpoint)); call.setOperationName("getName"); String ret = (String) call.invoke(new Object[] {}); 出错的就是最后一句。如果这一句改成调用返回值是Int的函数,就不会出错。请问,这是Axis的配置的问题吗?如果是,该如何改? 应该不大可能是Axis的配置的问题,你调用的是 public String getName() { return name; } 因此返回的是String,这个是没有错误的! 你的程序我在自己机器上运行的很好!不管调用哪个方法,都一样输出。你可以把String ret = (String) call.invoke(new Object[] {});改成Object ret = (Object)call.invoke(new Object[] {});这样的话你就不用去类型转换了! 或者如果你要类型转换的话,也可以这样做: 1,如果调用返回类型是string的方法 那么最后一句应该为 String ret = (String) call.invoke(new Object[] {}); 2,如果调用返回类型是int的方法,那么最后一句应该为 Integer ret = (Integer)call.invoke(new Object[] {}); 还有要注意的是在利用客户端进行测试的时候,确保服务器已经启动,否则会出错。如果你是采用http://myserver:7001/ZxjTest.jws的话,你的web-inf下确保没有 server-config.wsdd,否则也会出错。 还有一个很简单的错误,可能仅仅只是WebLogic配置的问题。最好重建一个应用并重新配置。 |