webservice -- cxf客戶端調用axis2服務端

背景:java

有個項目, 須要由第三方提供用戶信息, 實現用戶同步操做, 對方給提供webservice接口(axis2實現)並也使用axis2做主客戶端調用我方提供的webservice接口web

起初, 因爲項目使用了spring, 且spring可與cxf較好的集成, 因此也就選用了cxf,spring

可問題隨之出現, 接口能夠調用到, 接口的具體方法也能夠調用到,apache

可是,tomcat

1. cxf做爲客戶端, 獲取服務端返回值時均爲null.服務器

2. cxf做爲服務端, 獲取axis2客戶端傳來的參數時, 也均爲null.app

針對上述問題, 作了大量調試模擬, 若有不妥之處, 敬請指正.frontend

 

一. axis2服務器搭建eclipse

簡單起見, axis2r搭建採用較爲簡單的一種方式, 即將服務類和services.xml打成.aar包發佈.webapp

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的安裝部署, 以下圖:

3. 訪問 http://localhost/axis2 顯示以下頁面, 表示axis2部署成功

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

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服務, 則發佈成功

 

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

網上好像有帖子說服務端的問題, 我的以爲也很差這樣說, 

暫且說服務端與客戶端版本不匹配吧, 

若是有更好的解釋, 不吝賜教

相關文章
相關標籤/搜索