【前言】发现我没有压力的时候就会懒,一直想总结一下之前用axis1.3开发时学到的知识,但是这件事情一直被我推到了今天。如果再不记录一下的话,我想不过多久自己都不记得怎么做了,更何况本来axis用的就不深入。目前soap的开发已经告一段落,估计以后也没有机会在做这方面了,我要去学习项目中一个高深的模块,到目前为止还是雾水。。。
其实axis1中我还是有很多没有搞懂的地方,这个总结中应该很多地方没有讲清楚甚至是错误的,希望各位批判着看,有错误还望指出。还是老样子,总结中的图没有贴上来,贴图太繁琐了。
1. 下载axis-bin-1_3.zip,解压后放在tomcat下的webapps目录下
C:/Program Files/Apache Software Foundation/Tomcat 5.5/webapps/
可以访问到axis的界面:
可以点击Validation验证一下axis安装是否正确:
2. 设置环境变量如下。其实并不一定非要按照这个设置,只要在CLASSPATH中找到相关的包就可以。
设置AXIS_HOME:%TOMCAT_HOME%/webapps/axis
设置AXIS_LIB:%AXIS_HOME%/WEB-INF/lib
设置AXISCLASSPATH:%AXIS_LIB%/activation.jar;%AXIS_LIB%/axis.jar;%AXIS_LIB%/axis-ant.jar;%AXIS_LIB%/commons-discovery-0.2.jar;%AXIS_LIB%/commons-httpclient-3.1.jar;%AXIS_LIB%/commons-logging-1.0.4.jar;%AXIS_LIB%/jaxrpc.jar;%AXIS_LIB%/log4j-1.2.8.jar;%AXIS_LIB%/mailapi.jar;%AXIS_LIB%/saaj.jar;%AXIS_LIB%/wsdl4j-1.5.1.jar;%AXIS_LIB%/xercesImpl.jar
设置CLASSPATH:
.;%TOMCAT_HOME%/common/lib/soap.jar;%TOMCAT_HOME%/common/lib/mail.jar;%TOMCAT_HOME%/common/lib/activation.jar;%TOMCAT_HOME%/common/lib/xercesImpl.jar;%TOMCAT_HOME%/common/lib/xml-apis.jar;C:/Sun/SDK/lib;%TOMCAT_HOME%/common/lib/servlet-api.jar;D:/software_work/ICP/ICP_CI_Windows_Master/tools/ant/lib;%AXIS_LIB%/activation-1.1.jar;%AXIS_LIB%/axis-1.3.jar;%AXIS_LIB%/axis-jaxrpc-1.3.jar;%AXIS_LIB%/axis-saaj-1.3.jar;%AXIS_LIB%/axis-wsdl4j-1.3.jar;%AXIS_LIB%/commons-discovery-0.2.jar;%AXIS_LIB%/commons-el.jar;%AXIS_LIB%/commons-logging-1.0.4.jar;%AXIS_LIB%/jasper-compiler.jar;%AXIS_LIB%/jasper-compiler-jdt.jar;%AXIS_LIB%/jasper-runtime.jar;%AXIS_LIB%/jsp-api.jar;%AXIS_LIB%/junit-3.8.1.jar;%AXIS_LIB%/mail-1.4.jar;%AXIS_LIB%/naming-factory.jar;%AXIS_LIB%/naming-factory-dbcp.jar;%AXIS_LIB%/naming-resources.jar;%AXIS_LIB%/opensaml-1.0.1.jar;%AXIS_LIB%/servlet-api.jar;%AXIS_LIB%/spring-1.2.7.jar;%AXIS_LIB%/wimssecurity-client.jar;%AXIS_LIB%/wss4j-1.1.0.jar;%AXIS_LIB%/xercesImpl-2.6.0.jar;%AXIS_LIB%/xml-apis-1.0.b2.jar;%AXIS_LIB%/xmlsec-1.3.0.jar;
1. WSDL2Java常用的参数如下:
-s server-side
-p package <argument>
-c implementationClassName <argument>
想了解更多,使用java org.apache.axis.wsdl.WSDL2Java –h查看帮助。
2. 在wsdl所在的目录,用WSDL2Java根据wsdl生成代码,命令如下:
java -cp "%CLASSPATH%" org.apache.axis.wsdl.WSDL2Java -s -p webservices.test.DeviceNotification -c webservices.test.DeviceNotification.TestServiceSkeleton new_Test.wsdl
如果生成代码成功,则不报任何信息。这样就生成了下面的代码和文件:
[D:/eclipse_workspace/eclipse_fromwebdev/AAAtoOMA_axis1.3/src/webservices/test/DeviceNotification/]
├-[TestServiceSkeleton.java]
├-[deploy.wsdd]
├-[DeviceObject.java]
├-[NewNotifyStatusCode.java]
├-[undeploy.wsdd]
├-[DeviceManagementBindingStub.java]
├-[DeviceManagementService.java]
├-[DeviceManagementServiceLocator.java]
└-[DeviceManagement_PortType.java]
下面是对上面文件的介绍:
l TestServiceSkeleton.java
这个类是服务器业务代码的实现类。类中的方法名称和wsdl中定义的是portType中operation是一致的。其实在porttype中定义的就是各个消息以及它的request/response。在TestServiceSkeleton.java中正是来实现这个消息在服务器端的代码,函数入参是在porttype中定义的input,函数出参就是在porttype中定义的output。
注意:有关这个类中各个消息函数的入参和出参的名称,在axis1.3和axis2.1.4中定义是不同。在aixs2.1.4生成的代码中,这个函数的入参和出参名称就是wsdl中porttype的input/output之后的message之后的内容,如下图:
而在用axis1.3生成的代码中,这个函数的入参和出参名称是input/output中message对应的type,如下图。我想,这个可能也是axis1.3的封装性不如axis2吧
l DeviceObject.java,NewNotifyStatusCode.java
对于在wsdl中定义的类型,axis1(axis2也是)都会生成一个相应的封装类。自定义类型,wsdl中的复杂类型定义都会生成对应的javaBean。
l DeviceManagementBindingStub.java
这个类实现了DeviceManagementService接口,作为服务器在客户端的存根,也就是一个stub。在客户端,对服务器的所有调用,本质上都是对stub的调用。这个类中也有一个portType中operation定义一致的函数DeviceNotification,这个函数中实现向server发送request消息:
//发送消息给server
java.lang.Object _resp = _call.invoke(new java.lang.Object[] { deviceObject });
1)可以在这个函数中设置client端等待消息的超时时长:
// 从配置文件中读取超时时间并设置
CfgData cfgData = CfgData.getInstance();
Integer timeout = new Integer(cfgData.getDeviceServer().getTimout());
_call.setTimeout(timeout);
2)可以在这个函数中增加soap request的soap header:在setRequestHeaders(_call);之前拼接好soap header,然后设置_call.addHeader(head);
3)有的时候,对端不使用soap header中的验证方式,而是采用http验证方式,那么可以在该函数中使用http验证方式:
// 从配置文件中读出http验证的用户名和密码
_call.getMessageContext().setUsername(cfgData.getReturnIPServer().getUserName());
_call.getMessageContext().setPassword(cfgData.getReturnIPServer().getPassword());
l DeviceManagementService.java
该类是一个接口,相当于wsdl中的wsdl:service结点,定义了得到这个服务的信息的函数。
l DeviceManagementServiceLocator
该类实现了DeviceManagementService接口,这个类的作用是直接与服务器端通信,建立与服务器端的连接,实例化stub。然后客户端就可以通过stub与服务器通信了。从字面意思是指定服务所在的locator,包括url和服务名称。
可以直接在这个类中指定服务所在的url如下,也可以从配置文件中读出对端的url:
private java.lang.String DeviceManagement_address = http://202.54.48.26:8280/services/DeviceManagement;
l DeviceManagement_PortType.java
这个也是一个接口,描述服务器端能干什么,对应于wsdl中的wsdl:portType。该接口中定义了DeviceNotification函数,DeviceManagementBindingStub.java实现了这个接口。
1. 修改服务器端的代码,以实现业务逻辑:这个主要是修改TestServiceSkeleton.java。在相应的函数中实现具体的服务器端代码,同时给客户端回response。
2. 修改客户端的代码,给服务器端发送request。
DeviceManagementService service = new DeviceManagementServiceLocator();
DeviceManagement_PortType client;
try {
URL portAddress = new URL(url);
client = service.getDeviceManagement(portAddress);
NewNotifyStatusCode statusCode;
// 发送消息并得到返回值
statusCode = client.DeviceNotification(newDeviceObject);
log.debug("Get DeviceNotification Response(statuscode) is:" + statusCode.getStatusCode());
return statusCode.getStatusCode();
} catch (ServiceException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return -1;
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return -1;
} catch(Exception e){
e.printStackTrace();
return -1;
}
1. 发布工程时,首先要启动tomcat
2. 发布命令为java -cp "%CLASSPATH%" org.apache.axis.client.AdminClient deploy.wsdd
3. 发布成功后,会在C:/Program Files/Apache Software Foundation/Tomcat 5.5/webapps/axis/WEB-INF/目录下自动生成server端的部署文件server-config.wsdd,从这个文件中可以看到相关的部署信息:
<service name="OmadmToAaa" provider="java:RPC">
// 定义了将来部署的服务名称为OmadmToAaa,这样访问这个服务时url为:http://localhost:8080/AAAtoOMA_axis1.3/services/ OmadmToAaa。下面的两组消息registerIPNotification和provisionComplete都是定义在这个服务中的
<operation name="registerIPNotification" qname="ns1:registerIPNotification" returnQName="macIpAddr" returnType="ns1:MacIpAddr" soapAction="http://services.mformation.com/MFServices/registerIPNotification" xmlns:ns1="http://services.mformation.com/MFServices/">
<parameter name="registerIPNotification" type="ns1:RegisterIPNotification"/>
</operation>
// returnQName和returnType定义了registerIPNotification消息出参为MacIpAddr。parameter这个元素是定义registerIPNotification消息的出参为registerIPNotification
<operation name="provisionComplete" qname="ns2:provisionComplete" soapAction="http://services.mformation.com/MFServices/provisionComplete" xmlns:ns2="http://services.mformation.com/MFServices/">
<parameter name="provisionData" type="ns2:ProvisionData"/>
</operation>
// 同样,这段定义了provisionComplete消息的入参和出参
<parameter name="allowedMethods" value="provisionComplete registerIPNotification"/>
// 定义了在这个服务中允许调用的消息方法
<parameter name="typeMappingVersion" value="1.2"/>
<parameter name="wsdlPortType" value="OmadmToAaaPort"/>
<parameter name="className" value="webservices.omadmtoaaa.OmadmToAaaServiceSkeleton"/>
// 指定了服务实现的类
<parameter name="wsdlServicePort" value="OmadmToAaa"/>
<parameter name="schemaQualified" value="http://services.mformation.com/MFServices/"/>
<parameter name="wsdlTargetNamespace" value="http://services.mformation.com/MFServices/"/>
<parameter name="wsdlServiceElement" value="OmadmToAaaService"/>
<typeMapping deserializer="org.apache.axis.encoding.ser.EnumDeserializerFactory" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" qname="ns3:CommandStatusCode" serializer="org.apache.axis.encoding.ser.EnumSerializerFactory" type="java:webservices.omadmtoaaa.CommandStatusCode" xmlns:ns3="http://services.mformation.com/MFServices/"/>
// 定义了按照什么方法解析消息中的CommandStatusCode,其中type为axis专门对该数据类型实现的类
<typeMapping deserializer="org.apache.axis.encoding.ser.BeanDeserializerFactory" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" qname="ns4:MacIpAddr" serializer="org.apache.axis.encoding.ser.BeanSerializerFactory" type="java:webservices.omadmtoaaa.MacIpAddr" xmlns:ns4="http://services.mformation.com/MFServices/"/>
// 定义了按照什么方法解析消息中的MacIpAddr
<typeMapping deserializer="org.apache.axis.encoding.ser.BeanDeserializerFactory" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" qname="ns5:RegisterIPNotification" serializer="org.apache.axis.encoding.ser.BeanSerializerFactory" type="java:webservices.omadmtoaaa.RegisterIPNotification" xmlns:ns5="http://services.mformation.com/MFServices/"/>
// 定义了按照什么方法解析消息中的RegisterIPNotification
<typeMapping deserializer="org.apache.axis.encoding.ser.BeanDeserializerFactory" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" qname="ns6:ProvisionData" serializer="org.apache.axis.encoding.ser.BeanSerializerFactory" type="java:webservices.omadmtoaaa.ProvisionData" xmlns:ns6="http://services.mformation.com/MFServices/"/>
// 定义了按照什么方法解析消息中的ProvisionData
</service>
4. 如果之前在WEB-INF目录下有一个server-config.wsdd,在发布一个另外的服务时,原来的server-config.wsdd并不会被完全覆盖,而是会在原来的基础上,将新发布的内容追加进去,真好。
有时候不使用axis1.3产生的代码框架,但是想借用axis1.3来发布业务代码,可以采用下面偷懒的方法:
1. 首先用wsdl文件,用wsdl2java来生成代码和deploy.wsdd
2. 用deploy.wsdd发布服务,同时生成server-config.wsdd
3. 按照实际的代码,修改server-config.wsdd。
发布工程目录如下图:
1. 把server-config.wsdd放在工程的WEB-INF下,server-config.wsdd可以用delpoy.wsdd发布时自动产生的那个
2. 用axis安装目录下web.xml覆盖WEB-INF目录下的web.xml
如果WEB_INF目录下没有server-config.wsdd会报错。delpoy.wsdd和server-config.wsdd是两回事,单单把delpoy.wsdd放在WEB-INF下,是不能发布该工程,仍然会报下面的错误:
另外,并不用将class专门放到WEB_INF目录下,也不用将axis的lib专门copy到WEB_INF/lib下。
注意:axis1和axis2部署的方式是不用的。
为了适应对端,我们从axis2降为axis1。在前期开发过程中,
1. multiref:
Axis1支持multiref,发出去的soap消息中的数据就用multiref表示(当server-config.wsdd中的sendMultiRefs为true)。但是axis2不支持multiref,如果非要axis2能够支持解析multiref的消息,可以利用MultiRefTestSOAPBindingImpl这个类自己手工解析。
2. axis2目前还不支持rpc/encoded
3. axis1和axis2生成的代码框架上也有很大的不同。
启动tomcat并部署后,发现在tomcat的log目录下出现了一个很奇怪的目录。
-rw-r----- 1 webadm web 0 2010-05-02 18:52 admin.2010-05-02.log
-rw-r----- 1 webadm web 1054 2010-05-02 18:52 catalina.2010-05-02.log
-rw-r----- 1 webadm web 1556 2010-05-02 18:52 catalina.out
drwxr-x--- 2 webadm web 4096 2010-05-02 18:52 C:/Program Files/Apache Software Foundation/Tomcat 5.5/webapps/axis/WEB-INF/attachments
-rw-r----- 1 webadm web 0 2010-05-02 18:52 host-manager.2010-05-02.log
-rw-r----- 1 webadm web 0 2010-05-02 18:52 localhost.2010-05-02.log
-rw-r----- 1 webadm web 0 2010-05-02 18:52 manager.2010-05-02.log
后来看了server-config.wsdd,这个应该是axis1指定的消息附件存放的目录。
<parameter name="attachments.Directory" value="C:/Program Files/Apache Software Foundation/Tomcat 5.5/webapps/axis/WEB-INF/attachments" />
我还没有试过,是否可以将server-config.wsdd的这个参数去掉,来控制是否产生这个附件目录。
1. 最近刚发现的一个介绍WSDL2Java的文档《WSDL2Java操作指南》
http://blog.csdn.net/wjwwgh/archive/2009/07/07/4325559.aspx
2. Axis1.3生成的代码分别是什么作用?
http://zhongkem.javaeye.com/blog/514130
3. apache官方网站讲解wsdd
http://ws.apache.org/axis/java/reference.html#DeploymentWSDDReference