webservice -- cxf客户端调用axis2服务端

背景:

有个项目, 需要由第三方提供用户信息, 实现用户同步操作, 对方给提供webservice接口(axis2实现)并也使用axis2作主客户端调用我方提供的webservice接口

起初, 由于项目使用了spring, 且spring可与cxf较好的集成, 所以也就选用了cxf,

可问题随之出现, 接口可以调用到, 接口的具体方法也可以调用到,

但是,

1. cxf作为客户端, 获取服务端返回值时均为null.

2. cxf作为服务端, 获取axis2客户端传来的参数时, 也均为null.

针对上述问题, 做了大量调试模拟, 如有不妥之处, 敬请指正.

 

一. axis2服务器搭建

简单起见, axis2r搭建采用较为简单的一种方式, 即将服务类和services.xml打成.aar包发布.

1. 下载部署axis2

http://axis.apache.org/axis2/java/core/

这里选择下载的1.7.0版本, axis2-1.7.0-war.zip

2. 将zip文件中的axis2.war包解压到tomcat的webapps目录中, 启动tomcat,

完成axis2的安装部署, 如下图:

webservice -- cxf客户端调用axis2服务端_第1张图片

3. 访问 http://localhost/axis2 显示如下页面, 表示axis2部署成功

webservice -- cxf客户端调用axis2服务端_第2张图片

4. 访问 http://localhost/axis2/services/listServices , 可查看此axis2所发布的webservice服务, 如下图:

其中, Version为axis2默认发布的服务, getVersion是此服务的方法

 

二. 编写发布webserivce接口

1. 新建java项目myAxis2

2. 创建服务类HelloShooter.java

 1 package com.shooter.webservice;
 2 
 3 public class HelloShooter {
 4 
 5     public void getShooterId(String shooterId) {
 6         System.out.println("狙击手编号: " + shooterId);
 7     }
 8     
 9     public String shoot(int num) {
10         return "本次出击共狙击 " + num + " 名敌军";
11     }
12     
13     public String undershoot() {
14         return "脱靶, 很遗憾!";
15     }
16     
17 }

3. 新建META-INF目录, 并创建services.xml文件

webservice -- cxf客户端调用axis2服务端_第3张图片

services.xml源码如下:

 1 <serviceGroup>
 2     <!-- 第一个webservice服务 -->
 3     <service name="HelloShooter" targetNamespace="http://sharp-shooter">
 4         <!-- 命名空间 -->
 5         <schema schemaNamespace="http://sharp-shooter" />
 6         <!-- 发布的服务类全路径 -->
 7         <parameter name="ServiceClass">com.shooter.webservice.HelloShooter
 8         </parameter>
 9         <!-- 对每个方法配置处理器 -->
10         <operation name="getShooterId">
11             <messageReceiver class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver" />
12         </operation>
13         <operation name="shoot">
14             <messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" />
15         </operation>
16         <operation name="undershoot">
17             <messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" />
18         </operation>
19     </service>
20 </serviceGroup>

另一种services.xml编写方式, 配置全局处理器, 但此种方法我没有成功过, 如哪位测试成功了, 交流一下

 1 <serviceGroup>
 2     <!-- 第一个webservice服务 -->
 3     <service name="HelloShooter" targetNamespace="http://sharp-shooter.com">
 4         <!-- 命名空间 -->
 5         <schema schemaNamespace="http://sharp-shooter.com" />
 6         <!-- 发布的服务类全路径 -->
 7         <parameter name="ServiceClass">com.shooter.webservice.HelloShooter</parameter>
 8         <messageReceivers>
 9             <!--有返回值的处理器-->
10             <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out" 
11                                 class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" />
12             <!--无返回值的处理器-->
13             <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-only" 
14                                 class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver" />
15         </messageReceivers>
16     </service>
17 </serviceGroup>

其中,

1) service元素的name属性为服务名称, 如果没有设置此属性, 那么服务名称为发布包名, 如发布包为shooter.aar, 则服务名为shooter

2) schema配置的为命名空间, 并在service元素中配置同样的命名空间

3) parameter name="ServicesClass"配置的为服务类的全路径

4) 处理器, 第一种方式为全局处理器, 第二各方式为为某个方法配置所需要的处理器

4. 创建.aar包

1) 使用myeclipse的导出功能, 导出编写的服务类和services.xml文件为jar包, 如图:

可去除不必要的文件.

2) 修改包扩展名为.aar

3) 将.aar包拷贝到...\apache-tomcat-6.0.35-80\webapps\axis2\WEB-INF\services目录中(自动部署), 完成服务端发布

4) 访问 http://localhost/axis2/services/listServices , 服务页面显示HelloShooter服务, 则发布成功

webservice -- cxf客户端调用axis2服务端_第4张图片

 

三. CXF客户端

1. 新建项目, 引入所需CXF的maven依赖(此处有坑, 后文解释)

 1 <dependency>                                       
 2     <groupId>org.apache.cxf</groupId>              
 3     <artifactId>cxf-rt-frontend-jaxws</artifactId> 
 4     <version>2.2.9</version>                       
 5 </dependency>                                      
 6 <dependency>                                       
 7     <groupId>org.apache.cxf</groupId>              
 8     <artifactId>cxf-rt-core</artifactId>           
 9     <version>2.2.9</version>                       
10 </dependency>                                      
11 <dependency>                                       
12     <groupId>org.apache.cxf</groupId>              
13     <artifactId>cxf-rt-transports-http</artifactId>
14     <version>2.2.9</version>                       
15 </dependency>                                      

2. 获取HelloShooter的接口信息

访问 http://localhost/axis2/services/HelloShooter?wsdl, 获取如下信息:

  1 <wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
  2     xmlns:ns1="http://org.apache.axis2/xsd" xmlns:ns="http://sharp-shooter"
  3     xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  4     xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
  5     xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
  6     targetNamespace="http://sharp-shooter">
  7     <wsdl:documentation>HelloShooter</wsdl:documentation>
  8     <wsdl:types>
  9         <xs:schema attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://sharp-shooter">
 10             <xs:element name="undershoot">
 11                 <xs:complexType>
 12                     <xs:sequence />
 13                 </xs:complexType>
 14             </xs:element>
 15             <xs:element name="undershootResponse">
 16                 <xs:complexType>
 17                     <xs:sequence>
 18                         <xs:element minOccurs="0" name="return" nillable="true" type="xs:string" />
 19                     </xs:sequence>
 20                 </xs:complexType>
 21             </xs:element>
 22             <xs:element name="shoot">
 23                 <xs:complexType>
 24                     <xs:sequence>
 25                         <xs:element name="num" type="xs:int" />
 26                     </xs:sequence>
 27                 </xs:complexType>
 28             </xs:element>
 29             <xs:element name="shootResponse">
 30                 <xs:complexType>
 31                     <xs:sequence>
 32                         <xs:element minOccurs="0" name="return" nillable="true" type="xs:string" />
 33                     </xs:sequence>
 34                 </xs:complexType>
 35             </xs:element>
 36             <xs:element name="getShooterId">
 37                 <xs:complexType>
 38                     <xs:sequence>
 39                         <xs:element minOccurs="0" name="shooterId" nillable="true" type="xs:string" />
 40                     </xs:sequence>
 41                 </xs:complexType>
 42             </xs:element>
 43         </xs:schema>
 44     </wsdl:types>
 45     <wsdl:message name="undershootRequest">
 46         <wsdl:part name="parameters" element="ns:undershoot" />
 47     </wsdl:message>
 48     <wsdl:message name="undershootResponse">
 49         <wsdl:part name="parameters" element="ns:undershootResponse" />
 50     </wsdl:message>
 51     <wsdl:message name="shootRequest">
 52         <wsdl:part name="parameters" element="ns:shoot" />
 53     </wsdl:message>
 54     <wsdl:message name="shootResponse">
 55         <wsdl:part name="parameters" element="ns:shootResponse" />
 56     </wsdl:message>
 57     <wsdl:message name="getShooterIdRequest">
 58         <wsdl:part name="parameters" element="ns:getShooterId" />
 59     </wsdl:message>
 60     <wsdl:message name="getShooterIdResponse" />
 61     <wsdl:portType name="HelloShooterPortType">
 62         <wsdl:operation name="undershoot">
 63             <wsdl:input message="ns:undershootRequest" wsaw:Action="urn:undershoot" />
 64             <wsdl:output message="ns:undershootResponse" wsaw:Action="urn:undershootResponse" />
 65         </wsdl:operation>
 66         <wsdl:operation name="shoot">
 67             <wsdl:input message="ns:shootRequest" wsaw:Action="urn:shoot" />
 68             <wsdl:output message="ns:shootResponse" wsaw:Action="urn:shootResponse" />
 69         </wsdl:operation>
 70         <wsdl:operation name="getShooterId">
 71             <wsdl:input message="ns:getShooterIdRequest" wsaw:Action="urn:getShooterId" />
 72             <wsdl:output message="ns:getShooterIdResponse" wsaw:Action="urn:getShooterIdResponse" />
 73         </wsdl:operation>
 74     </wsdl:portType>
 75     <wsdl:binding name="HelloShooterSoap11Binding" type="ns:HelloShooterPortType">
 76         <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />
 77         <wsdl:operation name="undershoot">
 78             <soap:operation soapAction="urn:undershoot" style="document" />
 79             <wsdl:input>
 80                 <soap:body use="literal" />
 81             </wsdl:input>
 82             <wsdl:output>
 83                 <soap:body use="literal" />
 84             </wsdl:output>
 85         </wsdl:operation>
 86         <wsdl:operation name="shoot">
 87             <soap:operation soapAction="urn:shoot" style="document" />
 88             <wsdl:input>
 89                 <soap:body use="literal" />
 90             </wsdl:input>
 91             <wsdl:output>
 92                 <soap:body use="literal" />
 93             </wsdl:output>
 94         </wsdl:operation>
 95         <wsdl:operation name="getShooterId">
 96             <soap:operation soapAction="urn:getShooterId" style="document" />
 97             <wsdl:input>
 98                 <soap:body use="literal" />
 99             </wsdl:input>
100             <wsdl:output>
101                 <soap:body use="literal" />
102             </wsdl:output>
103         </wsdl:operation>
104     </wsdl:binding>
105     <wsdl:binding name="HelloShooterSoap12Binding" type="ns:HelloShooterPortType">
106         <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />
107         <wsdl:operation name="undershoot">
108             <soap12:operation soapAction="urn:undershoot" style="document" />
109             <wsdl:input>
110                 <soap12:body use="literal" />
111             </wsdl:input>
112             <wsdl:output>
113                 <soap12:body use="literal" />
114             </wsdl:output>
115         </wsdl:operation>
116         <wsdl:operation name="shoot">
117             <soap12:operation soapAction="urn:shoot" style="document" />
118             <wsdl:input>
119                 <soap12:body use="literal" />
120             </wsdl:input>
121             <wsdl:output>
122                 <soap12:body use="literal" />
123             </wsdl:output>
124         </wsdl:operation>
125         <wsdl:operation name="getShooterId">
126             <soap12:operation soapAction="urn:getShooterId" style="document" />
127             <wsdl:input>
128                 <soap12:body use="literal" />
129             </wsdl:input>
130             <wsdl:output>
131                 <soap12:body use="literal" />
132             </wsdl:output>
133         </wsdl:operation>
134     </wsdl:binding>
135     <wsdl:binding name="HelloShooterHttpBinding" type="ns:HelloShooterPortType">
136         <http:binding verb="POST" />
137         <wsdl:operation name="undershoot">
138             <http:operation location="undershoot" />
139             <wsdl:input>
140                 <mime:content type="application/xml" part="parameters" />
141             </wsdl:input>
142             <wsdl:output>
143                 <mime:content type="application/xml" part="parameters" />
144             </wsdl:output>
145         </wsdl:operation>
146         <wsdl:operation name="shoot">
147             <http:operation location="shoot" />
148             <wsdl:input>
149                 <mime:content type="application/xml" part="parameters" />
150             </wsdl:input>
151             <wsdl:output>
152                 <mime:content type="application/xml" part="parameters" />
153             </wsdl:output>
154         </wsdl:operation>
155         <wsdl:operation name="getShooterId">
156             <http:operation location="getShooterId" />
157             <wsdl:input>
158                 <mime:content type="application/xml" part="parameters" />
159             </wsdl:input>
160             <wsdl:output>
161                 <mime:content type="application/xml" part="parameters" />
162             </wsdl:output>
163         </wsdl:operation>
164     </wsdl:binding>
165     <wsdl:service name="HelloShooter">
166         <wsdl:port name="HelloShooterHttpSoap11Endpoint" binding="ns:HelloShooterSoap11Binding">
167             <soap:address location="http://localhost/axis2/services/HelloShooter.HelloShooterHttpSoap11Endpoint/" />
168         </wsdl:port>
169         <wsdl:port name="HelloShooterHttpSoap12Endpoint" binding="ns:HelloShooterSoap12Binding">
170             <soap12:address location="http://localhost/axis2/services/HelloShooter.HelloShooterHttpSoap12Endpoint/" />
171         </wsdl:port>
172         <wsdl:port name="HelloShooterHttpEndpoint" binding="ns:HelloShooterHttpBinding">
173             <http:address location="http://localhost/axis2/services/HelloShooter.HelloShooterHttpEndpoint/" />
174         </wsdl:port>
175     </wsdl:service>
176 </wsdl:definitions>
View Code

3. 根据接口信息, 创建客户端接口

 1 package com.shooter.cxf.client;
 2 
 3 import javax.jws.WebMethod;
 4 import javax.jws.WebParam;
 5 import javax.jws.WebResult;
 6 import javax.jws.WebService;
 7 
 8 @WebService(name="HelloShooter", targetNamespace="http://sharp-shooter")
 9 public interface IHelloShooter {
10 
11     @WebMethod(operationName="getShooterId")
12     public void getShooterId(@WebParam(name="shooterId", targetNamespace="http://sharp-shooter")String shooterId);
13     
14     @WebMethod(operationName="shoot")
15     public @WebResult(targetNamespace="http://sharp-shooter") String shoot(@WebParam(name="num", targetNamespace="http://sharp-shooter")int num);
16     
17     @WebMethod(operationName="undershoot")
18     public @WebResult(targetNamespace="http://sharp-shooter") String undershoot();
19     
20 }

注意重点: 此接口主要在4处添加了注解, 分别是: 类, 方法, 方法参数, 方法返回值, 

前面描述的项目中出现的问题, 也正在这里某一处或几处没有添加注解引起的(说实话, 感觉有点怪怪的, 哪位大神有更好的办法, 求赐教)

4. 创建接口调用测试类

 1 package com.shooter.cxf.client;
 2 
 3 import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
 4 
 5 public class CXFClient {
 6 
 7     public static void main(String[] args) {
 8         // 保存返回值
 9         String result = "";
10         
11         String url = "http://localhost/axis2/services/HelloShooter";
12         JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
13         factory.setServiceClass(IHelloShooter.class);
14         factory.setAddress(url);
15         // 创建接口代理对象
16         IHelloShooter helloServices = (IHelloShooter) factory.create();
17 
18         // 调用接口方法
19         helloServices.getShooterId("1123");
20         
21         System.out.println("-----------------------------");
22         result = helloServices.shoot(6);
23         System.out.println(result);
24         
25         System.out.println("-----------------------------");
26         result = helloServices.undershoot();
27         System.out.println(result);
28     }
29 }

执行main方法:

1) getShooterId()方法, 无返回值, 服务端打印相关信息

2) shoot()和undershoot()方法, 有返回值, 在客户端打印相关信息

运行不粗来? 客户端报异常? getShooterId()方法? 那就对了...

填坑:

调试的时候, 试验N多次, 客户端总报如下异常信息:

 1 Exception in thread "main" org.apache.cxf.binding.soap.SoapFault: Error reading XMLStreamReader.
 2  at org.apache.cxf.binding.soap.interceptor.ReadHeadersInterceptor.handleMessage(ReadHeadersInterceptor.java:238)
 3  at org.apache.cxf.binding.soap.interceptor.ReadHeadersInterceptor.handleMessage(ReadHeadersInterceptor.java:60)
 4  at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
 5  at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:801)
 6  at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1679)
 7  at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1517)
 8  at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1425)
 9  at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
10  at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:650)
11  at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
12  at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
13  at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:531)
14  at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:462)
15  at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:365)
16  at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:318)
17  at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:338)
18  at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:324)
19  at com.jialin.ejb.MyClient.main(MyClient.java:40)
20 Caused by: com.ctc.wstx.exc.WstxEOFException: Unexpected EOF in prolog
21  at [row,col {unknown-source}]: [1,0]
22  at com.ctc.wstx.sr.StreamScanner.throwUnexpectedEOF(StreamScanner.java:677)
23  at com.ctc.wstx.sr.BasicStreamReader.handleEOF(BasicStreamReader.java:2116)
24  at com.ctc.wstx.sr.BasicStreamReader.nextFromProlog(BasicStreamReader.java:2022)
25  at com.ctc.wstx.sr.BasicStreamReader.next(BasicStreamReader.java:1114)
26  at com.ctc.wstx.sr.BasicStreamReader.nextTag(BasicStreamReader.java:1137)
27  at org.apache.cxf.binding.soap.interceptor.ReadHeadersInterceptor.handleMessage(ReadHeadersInterceptor.java:139)
28  ... 17 more
View Code

提炼一下, 就俩信息: Error reading XMLStreamReader.和[row,col {unknown-source}]: [1,0]

客户端出问题(当然也不能这么说, 当时的第一感觉)

各种试, 最后换了CXF的版本, 问题解决了

 1 <dependency>                                       
 2     <groupId>org.apache.cxf</groupId>              
 3     <artifactId>cxf-rt-frontend-jaxws</artifactId> 
 4     <version>2.7.16</version>                      
 5 </dependency>                                      
 6 <dependency>                                       
 7     <groupId>org.apache.cxf</groupId>              
 8     <artifactId>cxf-rt-core</artifactId>           
 9     <version>2.7.16</version>                      
10 </dependency>                                      
11 <dependency>                                       
12     <groupId>org.apache.cxf</groupId>              
13     <artifactId>cxf-rt-transports-http</artifactId>
14     <version>2.7.16</version>                      
15 </dependency>                                      

网上好像有帖子说服务端的问题, 个人觉得也不好这样说, 

暂且说服务端与客户端版本不匹配吧, 

如果有更好的解释, 不吝赐教

你可能感兴趣的:(webservice -- cxf客户端调用axis2服务端)