一次WebService调试- Shoopman

    项目背景:中移动某省的一个管理系统A,而本公司另一产品线则负责此移动公司的门户P,现在需要进行用户数据的同步及实现单点登陆。门户P有一套简单的关于用户数据同步的WebService接口规范,定义了方法名、返回值及参数。

    系统A技术框架:JDK1.4 + Struts1.2.x + Spring + XFire。

    我对XFire不太熟悉,幸好系统A原先就已经使用了XFire向其他系统提供了WebService,我只需要依葫芦画瓢就行。还是简单的说一下XFire及与Spring集成的配置吧。

    1. web.xml的配置,配置xfire的servlet及URI映射

<servlet>
<servlet-name>xfire</servlet-name>
<servlet-class>org.codehaus.xfire.spring.XFireSpringServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>xfire</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>

    2. services.xml的配置,位于WEB-INF/META-INF/xfire下,指定WebService的名称、路径及类接口及实现类

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xfire.codehaus.org/config/1.0">
     <service>  
        <name>NopService</name>  
        <namespace>/services/NopService</namespace>  
        <serviceClass>com.xxx.project.service.NopService</serviceClass>  
        <implementationClass>com.xxx.project.service.NopServiceImpl</implementationClass>  
      </service>
</beans>

服务接口类如下:

package com.xxx.project.service

public interface NopService {
    /**
     * 获得用户信息
     * @param flag
     * @return
     */
    public List getAccount(String flag);

}

getAccount返回的List包含的是对象是RemoteUser,一个纯粹的JavaBean,如下:

package com.xxx.project.service

public class RemoteUser {
    private String uid; 
    private String name; 
    private String pwd; 
    private String sex; 
    private String mobile; 
    private String telephone; 
    private String mail; 
    private String post; 
    private String fax;

    /** 省略掉的getter与setter */

}

    3. spring beans 的配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC
    "-//SPRING//DTD BEAN//EN"
    "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <import resource="classpath:org/codehaus/xfire/spring/xfire.xml" />
    <bean
        class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="urlMap">
            <map>               
                <entry key="/nopService">
                    <ref bean="xfire.nopService"/>
                </entry>               
            </map>
        </property>
    </bean>
    <!– common xfire exporter,set the parent to this bean –>
    <bean id="commonXFireExporter"
        class="org.codehaus.xfire.spring.remoting.XFireExporter"
        lazy-init="false" abstract="true">
        <property name="serviceFactory" ref="xfire.serviceFactory" />
        <property name="xfire" ref="xfire" />
    </bean>
    <!– Declare a parent bean with all properties common to both services –>
    <bean id="xfire.nopService" parent="commonXFireExporter">
        <property name="name" value="nopService"/>
        <property name="namespace" value="http://www.xxx.com/services/nopService"/>
        <property name="serviceBean" ref="nopService" />
        <property name="serviceInterface"
            value="com.xxx.project.service.NopService" />
    </bean>
</beans>

    4.aegis的配置,由于接口上的返回类型是集合类,需要配置一个NopService.aegis.xml的文件来告诉xfire包含在集合中的是什么类型,注意到文件名是接口名+.aegis.xml,位置跟接口的一样。

<?xml version="1.0" encoding="UTF-8"?>
<mappings>
    <mapping>
        <method name="getAccount">
            <return-type
                componentType="com.xxx.project.service.RemoteUser"
                minOccurs="1" maxOccurs="1" />
        </method>
    </mapping>
</mappings>

 

部署到Tomcat中,通过浏览器访问,得到了类似如下的WSDL:

<?xml version="1.0
" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://www.xxx.com/services/nopService"
   xmlns:tns="http://www.xxx.com/services/nopService" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:soap12="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://project.xxx.com"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenc11="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:soapenc12="http://www.w3.org/2003/05/soap-encoding" xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
    <wsdl:types>
        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            attributeFormDefault="qualified" elementFormDefault="qualified"
            targetNamespace="http://www.xxx.com/services/nopService">
            <xsd:element name="getAccount">
                <xsd:complexType>
                    <xsd:sequence>
                        <xsd:element maxOccurs="1" minOccurs="1" name="in0"
                            nillable="true" type="xsd:string" />
                    </xsd:sequence>
                </xsd:complexType>
            </xsd:element>
            <xsd:element name="getAccountResponse">
                <xsd:complexType>
                    <xsd:sequence>
                        <xsd:element maxOccurs="1" minOccurs="1" name="out"
                            nillable="true" type="ns1:ArrayOfRemoteUser" />
                    </xsd:sequence>
                </xsd:complexType>
            </xsd:element>
        </xsd:schema>
        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            attributeFormDefault="qualified" elementFormDefault="qualified"
            targetNamespace="http://project.xxx.com">
            <xsd:complexType name="ArrayOfRemoteUser">
                <xsd:sequence>
                    <xsd:element maxOccurs="unbounded" minOccurs="0"
                        name="RemoteUser" nillable="true" type="ns1:RemoteUser" />
                </xsd:sequence>
            </xsd:complexType>
            <xsd:complexType name="RemoteUser">
                <xsd:sequence>
                    <xsd:element minOccurs="0" name="fax" nillable="true"
                        type="xsd:string" />
                    <xsd:element minOccurs="0" name="mail" nillable="true"
                        type="xsd:string" />
                    <xsd:element minOccurs="0" name="mobile" nillable="true"
                        type="xsd:string" />
                    <xsd:element minOccurs="0" name="name" nillable="true"
                        type="xsd:string" />
                    <xsd:element minOccurs="0" name="post" nillable="true"
                        type="xsd:string" />
                    <xsd:element minOccurs="0" name="pwd" nillable="true"
                       
type="xsd:string" />
                    <xsd:element minOccurs="0" name="sex" nillable="true"
                        type="xsd:string" />
                    <xsd:element minOccurs="0" name="telephone" nillable="true"
                        type="xsd:string" />
                    <xsd:element minOccurs="0" name="uid" nillable="true"
                        type="xsd:string" />
                </xsd:sequence>
            </xsd:complexType>
        </xsd:schema>
    </wsdl:types>

    <!– 省略了部分 –>
    </wsdl:definitions>

wsdl文件都出来,算是成功一半了,接着就是生成客户端来测试了。像Axis和cfx一样,XFire也带有代码生成工具,也有ant任务,如下:

<project name="xfire-client" default="wsgen" basedir=".">
    <path id="classpath">
        <fileset dir="lib">
            <include name="**/*.jar" />
        </fileset>
    </path>
    <target name="wsgen">
        <taskdef name="wsgen" classname="org.codehaus.xfire.gen.WsGenTask" classpathref="classpath" />
        <wsgen outputDirectory="appClientModule" wsdl="http://localhost:8080/services/nopService?wsdl" package="com.xxx.project.client" overwrite="true" />
    </target>
</project>

 

客户代码生成后,再写一个测试类来调用WebService:

public class NopServiceTest {

    public static void main(String[] args) {
        nopServiceClient client = new nopServiceClient();
        nopServicePortType service = client.getnopServiceHttpPort("
        ArrayOfRemoteUser rets = service.getAccount("");
        List<RemoteUser> list = rets.getRemoteUser();
        System.out.println(list.size());
    }

}

    OK!测试成功。赶紧打包部署到测试服务器上,让门户P的开发人员来测试。对方很快来了反应:wsdl不符合他们的规范,在将wsdl导入门户P时报错—-无法识别类型“ns1:ArrayOfRemoteUser”。我能得到的错误信息就这么多,以及一份符合所谓规范的wsdl样例,貌似是由Axis生成的:

<?xml version="1.0" encoding="UTF-8" ?>
<wsdl:definitions targetNamespace="
    xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="
    xmlns:intf="http://security.interfaces.eoms.yyy.com" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <!–
        WSDL created by Apache Axis version: 1.3 Built on Oct 05, 2005
        (05:23:37 EDT)
    –>
    <wsdl:types>
        <schema elementFormDefault="qualified"
            targetNamespace="http://security.interfaces.eoms.yyy.com" xmlns="http://www.w3.org/2001/XMLSchema">
            <element name="getAccount">
                <complexType>
                    <sequence>
                        <element name="flag" type="xsd:string" />
                    </sequence>
                </complexType>
            </element>
            <element name="getAccountResponse">
                <complexType>
                    <sequence>
                        <element maxOccurs="unbounded" name="getAccountReturn"
                            type="impl:RemoteUser" />
                    </sequence>
                </complexType>
            </element>
            <complexType name="RemoteUser">
                <seque
nce>
                    <element name="fax" nillable="true" type="xsd:string" />
                    <element name="mail" nillable="true" type="xsd:string" />
                    <element name="mobile" nillable="true" type="xsd:string" />
                    <element name="name" nillable="true" type="xsd:string" />
                    <element name="post" nillable="true" type="xsd:string" />
                    <element name="pwd" nillable="true" type="xsd:string" />
                    <element name="sex" nillable="true" type="xsd:string" />
                    <element name="telephone" nillable="true" type="xsd:string" />
                    <element name="uid" nillable="true" type="xsd:string" />
                </sequence>
            </complexType>
        </schema>
    </wsdl:types>

    由于非技术原因,此问题得由我来处理。通过对比两个wsdl文件、长时间及多次的测试,最终锁定了门户P无法识别”ns1:ArrayOfRemoteUser”的原因:系统A的wsdl有两个<xsd:schema>节点。又经过多次尝试,才终于把xfire生成的wsdl的schema节点合并为一个,方法是,把前面第3步的spring beans配置中的标红处修改如下,跟接口类颠倒的包名保持一致:

<bean id="xfire.nopService" parent="commonXFireExporter">
        <property name="name" value="nopService"/>
        <property name="namespace" value="http://service.project.xxx.com"/>
        <property name="serviceBean" ref="nopService" />
        <property name="serviceInterface"
            value="com.xxx.project.service.NopService" /> 
</bean>

后来在网上找到可能的原因:,门户P的cxf包可能较旧,不支持多个xmlns。

郑重声明:资讯 【一次WebService调试- Shoopman】由 发布,版权归原作者及其所在单位,其原创性以及文中陈述文字和内容未经(企业库qiyeku.com)证实,请读者仅作参考,并请自行核实相关内容。若本文有侵犯到您的版权, 请你提供相关证明及申请并与我们联系(qiyeku # qq.com)或【在线投诉】,我们审核后将会尽快处理。
—— 相关资讯 ——