• 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的安装部署, 如下图:

    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-80webappsaxis2WEB-INFservices目录中(自动部署), 完成服务端发布

    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>                                      

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

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

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

    ------------------
    要比昨天的自己更强
  • 相关阅读:
    Maven name=archetypeCatalog value=internal
    ResponseBody和文件上传
    Idea控制台中文乱码
    idea tomcat部署项目路径
    git 常用操作
    webpack
    AbstractQueuedSynchronizer-AQS
    线程安全
    cpu多级缓存
    Axure中继器设置单选
  • 原文地址:https://www.cnblogs.com/lzj0616/p/5219610.html
Copyright © 2020-2023  润新知