用axis1.3开发soap

【前言】发现我没有压力的时候就会懒,一直想总结一下之前用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;

根据wsdl生成代码

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中定义的是portTypeoperation是一致的。其实在porttype中定义的就是各个消息以及它的request/response。在TestServiceSkeleton.java中正是来实现这个消息在服务器端的代码,函数入参是在porttype中定义的input,函数出参就是在porttype中定义的output

注意:有关这个类中各个消息函数的入参和出参的名称,在axis1.3axis2.1.4中定义是不同。在aixs2.1.4生成的代码中,这个函数的入参和出参名称就是wsdlporttypeinput/output之后的message之后的内容,如下图:

而在用axis1.3生成的代码中,这个函数的入参和出参名称是input/outputmessage对应的type,如下图。我想,这个可能也是axis1.3的封装性不如axis2

l         DeviceObject.javaNewNotifyStatusCode.java

对于在wsdl中定义的类型,axis1axis2也是)都会生成一个相应的封装类。自定义类型,wsdl中的复杂类型定义都会生成对应的javaBean

l         DeviceManagementBindingStub.java

这个类实现了DeviceManagementService接口,作为服务器在客户端的存根,也就是一个stub。在客户端,对服务器的所有调用,本质上都是对stub的调用。这个类中也有一个portTypeoperation定义一致的函数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 requestsoap 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。下面的两组消息registerIPNotificationprovisionComplete都是定义在这个服务中的

  <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>

// returnQNamereturnType定义了registerIPNotification消息出参为MacIpAddrparameter这个元素是定义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,其中typeaxis专门对该数据类型实现的类

  <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发布工程的方法

有时候不使用axis1.3产生的代码框架,但是想借用axis1.3来发布业务代码,可以采用下面偷懒的方法:

1. 首先用wsdl文件,用wsdl2java来生成代码和deploy.wsdd

2. deploy.wsdd发布服务,同时生成server-config.wsdd

3. 按照实际的代码,修改server-config.wsdd

eclipse中启动tomcat,发布axis1.3工程的方法

发布工程目录如下图:

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.wsddserver-config.wsdd是两回事,单单把delpoy.wsdd放在WEB-INF下,是不能发布该工程,仍然会报下面的错误:

另外,并不用将class专门放到WEB_INF目录下,也不用将axislib专门copyWEB_INF/lib下。

注意:axis1axis2部署的方式是不用的。

axis1axis2的区别

为了适应对端,我们从axis2降为axis1。在前期开发过程中,

1. multiref

Axis1支持multiref,发出去的soap消息中的数据就用multiref表示(当server-config.wsdd中的sendMultiRefstrue)。但是axis2不支持multiref,如果非要axis2能够支持解析multiref的消息,可以利用MultiRefTestSOAPBindingImpl这个类自己手工解析。

2. axis2目前还不支持rpc/encoded

3. axis1axis2生成的代码框架上也有很大的不同。

日志中有个奇怪的目录

启动tomcat并部署后,发现在tomcatlog目录下出现了一个很奇怪的目录。

-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

 

你可能感兴趣的:(java,tomcat,服务器,Integer,SOAP,2010)