<?xml version="1.0" encoding="UTF-8"?>   
<definitions   
 xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"  
 xmlns:tns="http://www.jsoso.com/wstest"  
 xmlns:xsd="http://www.w3.org/2001/XMLSchema"  
 xmlns="http://schemas.xmlsoap.org/wsdl/"  
 targetNamespace="http://www.jsoso.com/wstest"  
 name="Example">   
  
<types>   
  <xsd:schema>   
  <xsd:import  
   namespace="http://www.jsoso.com/wstest"  
   schemaLocation="http://localhost:8080/hello?xsd=1"></xsd:import>   
  </xsd:schema>   
</types>   
  
<message name="toSayHello">   
  <part name="userName" type="xsd:string"></part>   
</message>   
<message name="toSayHelloResponse">   
  <part name="returnWord" type="xsd:string"></part>   
</message>   
  
<message name="sayHello">   
  <part name="person" type="tns:person"></part>   
  <part name="arg1" type="xsd:string"></part>   
</message>   
<message name="sayHelloResponse">   
  <part name="personList" type="tns:personArray"></part>   
</message>   
<message name="HelloException">   
  <part name="fault" element="tns:HelloException"></part>   
</message>   
  
<portType name="Example">   
  <operation name="toSayHello" parameterOrder="userName">   
    <input message="tns:toSayHello"></input>   
    <output message="tns:toSayHelloResponse"></output>   
  </operation>   
  <operation name="sayHello" parameterOrder="person arg1">   
    <input message="tns:sayHello"></input>   
    <output message="tns:sayHelloResponse"></output>   
    <fault message="tns:HelloException" name="HelloException"></fault>   
  </operation>   
</portType>   
  
<binding name="ExamplePortBinding" type="tns:Example">   
  <soap:binding   
    transport="http://schemas.xmlsoap.org/soap/http"    
    style="rpc"></soap:binding>   
  <operation name="toSayHello">   
    <soap:operation soapAction="sayHello"></soap:operation>   
    <input>   
      <soap:body use="literal"  
        namespace="http://www.jsoso.com/wstest"></soap:body>   
    </input>   
    <output>   
      <soap:body use="literal"  
         namespace="http://www.jsoso.com/wstest"></soap:body>   
    </output>   
  </operation>   
  <operation name="sayHello">   
    <soap:operation soapAction="sayHello"></soap:operation>   
    <input>   
      <soap:body use="literal"  
        namespace="http://www.jsoso.com/wstest"></soap:body>   
    </input>   
    <output>   
      <soap:body use="literal"  
        namespace="http://www.jsoso.com/wstest"></soap:body>   
    </output>   
    <fault name="HelloException">   
      <soap:fault name="HelloException" use="literal"></soap:fault>   
    </fault>   
    </operation>   
</binding>   
  
<service name="Example">   
  <port name="ExamplePort" binding="tns:ExamplePortBinding">   
    <soap:address location="http://localhost:8080/hello"></soap:address>   
  </port>   
</service>   
</definitions>
由于上面的事例XML较长,我们将其逐段分解讲解 WSDL文档的根元素:<definitions>
<definitions   
 xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"  
 xmlns:tns="http://www.jsoso.com/wstest"  
 xmlns:xsd="http://www.w3.org/2001/XMLSchema"  
 xmlns="http://schemas.xmlsoap.org/wsdl/"  
 targetNamespace="http://www.jsoso.com/wstest"  
 name="Example">   
……   
……   
</definitions> 
<definitions>定义了文档中用到的各个xml元素的namespace缩写,也界定了本文档自己的targetNamespace="http://www.jsoso.com/wstest",这意味着其它的XML要引用当前XML中的元素时,要声明这个namespace。注意xmlns:tns="http://www.jsoso.com/wstest"这个声明,它标示了使用tns这个前缀指向自身的命名空间。 
引用
WSDL文档数据类型定义元素:<types>
<types>   
  <xsd:schema>   
  <xsd:import  
   namespace="http://www.jsoso.com/wstest"  
   schemaLocation="http://localhost:8080/hello?xsd=1"></xsd:import>   
  </xsd:schema>   
</types> 
<types>标签定义了当前的WSDL文档用到的数据类型。要说明的是,为了最大程度的平台中立性,WSDL 使用 XML Schema 语法来定义数据类型。这些数据类型用来定义web service方法的参数和返回指。对于通用的原生数据类型如:integer , boolean , char , float等,在W3C的标准文档http://www.w3.org/2001/XMLSchema中已经做了定义。这里我们要引入的schema定义schemaLocation="http://localhost:8080/hello?xsd=1"是我们自定义的Java对象类型。 WSDL文档消息体定义元素:< message > 
<message name="toSayHello">   
  <part name="userName" type="xsd:string"></part>   
</message>   
<message name="toSayHelloResponse">   
  <part name="returnWord" type="xsd:string"></part>   
</message>   
  
<message name="sayHello">   
  <part name="person" type="tns:person"></part>   
  <part name="arg1" type="xsd:string"></part>   
</message>   
<message name="sayHelloResponse">   
  <part name="personList" type="tns:personArray"></part>   
</message>   
<message name="HelloException">   
  <part name="fault" element="tns:HelloException"></part>   
</message>
<message>元素定义了web service函数的参数。<message>元素中的每个<part>子元素都和某个参数相符。输入参数在<message>元素中定义,与输出参数相隔离,输出参数有自己的<message>元素。兼作输入、输出的参数在输入输出的<message>元素中有它们相应的<part>元素。输出<message>元素以"Response"结尾,对Java而言方法得返回值就对应一个输出的<message>。每个<part>元素都有名字和类型属性,就像函数的参数有参数名和参数类型。 在上面的文档中有两个输入参数、两个输出参数和一个错误参数(对应Java中的Exception)。  输入参数<message>的name属性分别命名为toSayHello,sayHello。 
toSayHello对应输入参数userName,参数类型为xsd:string,在Java语言中就是String; 
sayHello对应两个输入参数person和arg1,类型为tns:person和xsd:string。这里tns:person类型就是引用了< types >标签中的类型定义。  输出参数<message>的name属性分别命名为toSayHelloResponse和sayHelloResponse。 
这个名称和输入参数的<message>标签name属性对应,在其后面加上Response尾缀。 
toSayHelloResponse对应的返回值是returnWord,参数类型为xsd:string; 
sayHelloResponse对应的返回值是personList,参数类型为tns:personArray(自定义类型);  错误参数<message>的name属性为HelloException。 
它的<part>子标签element而不是type来定义类型。 以上的message标签的name属性通常使用web service函数方法名作为参照,错误参数标签则使用异常类名为参照。标签中的参数名称,即part子元素的name属性是可自定义的(下一章节详细说明)。message标签的参数类型将引用types标签的定义。 WSDL文档函数体定义元素:< portType > 
<portType name="Example">   
  <operation name="toSayHello" parameterOrder="userName">   
    <input message="tns:toSayHello"></input>   
    <output message="tns:toSayHelloResponse"></output>   
  </operation>   
  <operation name="sayHello" parameterOrder="person arg1">   
    <input message="tns:sayHello"></input>   
    <output message="tns:sayHelloResponse"></output>   
    <fault message="tns:HelloException" name="HelloException"></fault>   
  </operation>   
</portType> 
<portType> 元素是最重要的 WSDL 元素。它可描述一个 web service、可被执行的操作,以及相关的消息。portType的name属性对应Java中的一个服务类的类名。<portType> 元素使用其子元素< operation>描述一个web service的服务方法。 在<operation>元素中,name属性表示服务方法名,parameterOrder属性表示方法的参数顺序,使用空格符分割多个参数,如:“parameterOrder="person arg1”。<operation>元素的子标签<input>表示输入参数说明,它引用<message>标签中的输入参数。<output>表示输出参数说明,它引用<message>标签中的输出参数。<fault>标签在Java方法中的特别用来表示异常(其它语言有对应的错误处理机制),它引用<message>标签中的错误参数。 WSDL绑定实现定义元素:< binding > 
<binding name="ExamplePortBinding" type="tns:Example">   
  <soap:binding   
    transport="http://schemas.xmlsoap.org/soap/http"    
    style="rpc"></soap:binding>   
  <operation name="toSayHello">   
    <soap:operation soapAction="sayHello"></soap:operation>   
    <input>   
      <soap:body use="literal"  
        namespace="http://www.jsoso.com/wstest"></soap:body>   
    </input>   
    <output>   
      <soap:body use="literal"  
         namespace="http://www.jsoso.com/wstest"></soap:body>   
    </output>   
  </operation>   
  <operation name="sayHello">   
    <soap:operation soapAction="sayHello"></soap:operation>   
    <input>   
      <soap:body use="literal"  
        namespace="http://www.jsoso.com/wstest"></soap:body>   
    </input>   
    <output>   
      <soap:body use="literal"  
        namespace="http://www.jsoso.com/wstest"></soap:body>   
    </output>   
    <fault name="HelloException">   
      <soap:fault name="HelloException" use="literal"></soap:fault>   
    </fault>   
    </operation>   
</binding>
<binding>标签是完整描述协议、序列化和编码的地方,<types>,<message>和<portType>标签处理抽象的数据内容,而<binding>标签是处理数据传输的物理实现。 
<binding>标签把前三部分的抽象定义具体化。 

解决方案 »

  1.   

    首先<binding>标签使用<soap:binding>的transport和style属性定义了Web Service的通讯协议HTTP和SOAP的请求风格RPC。其次<operation>子标签将portType中定义的operation同SOAP的请求绑定,定义了操作名称soapAction,输出输入参数和异常的编码方式及命名空间。 WSDL服务地址绑定元素:< service > 
    <service name="Example">   
      <port name="ExamplePort" binding="tns:ExamplePortBinding">   
        <soap:address location="http://localhost:8080/hello"></soap:address>   
      </port>   
    </service> 
    service是一套<port>元素。在一一对应形式下,每个<port>元素都和一个location关联。如果同一个<binding>有多个<port>元素与之关联,可以使用额外的URL地址作为替换。 一个WSDL文档中可以有多个<service>元素,而且多个<service>元素十分有用,其中之一就是可以根据目标URL来组织端口。在一个WSDL文档中,<service>的name属性用来区分不同的service。在同一个service中,不同端口,使用端口的"name"属性区分。 这一章节,我们简单的描述了WSDL对SOAP协议的支持,以及在Web Service中的作用。在接下来的章节中,我们将学习如何使用Java6.0的Annotation标签来定义和生成对应的WSDL。 JavaSE6.0下的Web Service 
    从JavaSE6.0开始,Java引入了对Web Service的原生支持。我们只需要简单的使用Java的Annotation标签即可将标准的Java方法发布成Web Service。(PS:Java Annotation资料请参考 JDK5.0 Annotation学习笔记(一) ) 但不是所有的Java类都可以发布成Web Service。Java类若要成为一个实现了Web Service的bean,它需要遵循下边这些原则:  这个类必须是public类 
     这些类不能是final的或者abstract 
     这个类必须有一个公共的默认构造函数 
     这个类绝对不能有finalize()方法 下面我们将通过一个具体的Java Web Service代码例子,配合上述的WSDL文件,讲述如何编写JavaSE6.0的原生Web Service应用。 完整的Java Web Service类代码 
    package org.jsoso.jws.server;   
      
    import java.util.ArrayList;   
    import javax.jws.WebMethod;   
    import javax.jws.WebParam;   
    import javax.jws.WebResult;   
    import javax.jws.WebService;   
    import javax.jws.WebParam.Mode;   
    import javax.jws.soap.SOAPBinding;   
    /   
     * 提供WebService服务的类   
     */   
    @WebService(name="Example", targetNamespace="http://www.jsoso.com/wstest", serviceName="Example")   
    @SOAPBinding(style=SOAPBinding.Style.RPC)   
    public class Example {   
        private ArrayList<Person> persons = new ArrayList<Person>();;   
        /**  
         *   
         * 返回一个字符串  
         * @param userName  
         * @return  
         */  
        @WebMethod(operationName="toSayHello",action="sayHello",exclude=false)   
        @WebResult(name="returnWord")//自定义该方法返回值在WSDL中相关的描述   
        public String sayHello(@WebParam(name="userName")String userName) {   
            return "Hello:" + userName;   
        }   
      
        /**  
         * web services 方法的返回值与参数的类型不能为接口  
         * @param person  
         * @return  
         * @throws HelloException  
         */  
        @WebMethod(operationName="sayHello", action="sayHello")   
        @WebResult(partName="personList")   
        public Person[] sayHello(@WebParam(partName="person", mode=Mode.IN)Person person,    
                String userName) throws HelloException {   
            if (person == null || person.getName() == null) {   
                throw new HelloException("说hello出错,对像为空。。");   
            }   
            System.out.println(person.getName() + " 对 " + userName + " 说:Hello,我今年" + person.getAge() + "岁");   
            persons.add(person);   
            return persons.toArray(new Person[0]);   
        }   

    Annotation 1@WebService(name="Example", targetNamespace="http://www.jsoso.com/wstest", serviceName="Example") 
    @WebService标签主要将类暴露为WebService,其中targetNamespace属性定义了自己的命名空间,serviceName则定义了< definitions >标签和<service>标签的name属性。 Annotation 2:@SOAPBinding(style=SOAPBinding.Style.RPC) 
    @SOAPBinding标签定义了WSDL文档中SOAP的消息协议,其中style属性对应SOAP的文档类型,可选的有RPC和DOCUMENT Annotation 3:@WebMethod(operationName="toSayHello",action="sayHello",exclude=false) 
    @WebMethod定义Web Service运作的方法, 
    属性action 对应操作的活动 ,如<soap:operation soapAction="sayHello" /> 
    属性operationName匹配的wsdl:operation 的名称,如<operation name="toSayHello" parameterOrder="userName"> 
    属性exclude 用于阻止将某一继承方法公开为web服务,默认为false Annotation 4:@WebResult(name="returnWord") 
    @ WebResult定义方法返回值得名称,如<part name="returnWord" type="xsd:string" /> Annotation 5:@WebParam(partName="person", mode=Mode.IN 
    @WebParam定义方法的参数名称,如<part name="person" type="tns:person" />,其中mode属性表示参数的流向,可选值有IN / OUT / INOUT 这里要着重说明的是,上述Web Service类的sayHello方法中,带有HelloException这个异常声明,造成该服务类不能直接发布成Web Service。需要使用wsgen工具为其生存异常Bean。关于wsgen工具的使用,请参考wsgen与wsimport命令说明 发布一个的Java Web Service 
    在完成了上述的Web Service Annotation注释后,我们使用wsgen工具为其进行服务资源文件的构造(这里主要是生成一个名为org.jsoso.jws.server.jaxws.HelloExceptionBean的异常bean类),最后使用以下的类发布Web 服务:
    package org.jsoso.jws.server;   
      
    import java.util.LinkedList;   
    import java.util.List;   
    import javax.xml.ws.Binding;   
    import javax.xml.ws.Endpoint;   
    import javax.xml.ws.handler.Handler;   
      
    /**  
     * @author zsy 启动web services服务  
     */  
    public class StartServer {   
      
        /**  
         * @param args  
         */  
        public static void main(String[] args) {   
            /*  
             * 生成Example 服务实例  
             */  
            Example serverBean = new Example();   
            /*  
             * 发布Web Service到http://localhost:8080/hello地址  
             */  
            Endpoint endpoint =    
               Endpoint.publish("http://localhost:8080/hello", serverBean);   
            Binding binding = endpoint.getBinding();   
            /*  
             * 设置一个SOAP协议处理栈  
             * 这里就简单得打印SOAP的消息文本  
             */  
            List<Handler> handlerChain = new LinkedList<Handler>();   
            handlerChain.add(new TraceHandler());   
            binding.setHandlerChain(handlerChain);   
            System.out.println("服务已启动 http://localhost:8080/hello");   
        }   

    在控制台运行这个类,就可以使用URL :http://localhost:8080/hello?wsdl 浏览到上文所描述的WSDL的全文了。这说明您的第一个Web Service应用发布成功! 构建Web Service客户端 
    使用JavaSE6.0构建Web Service的客户端是一件相当简单的事。这里我们要使用到JDK中的另一个命令行工具wsimport。在控制台下输入以下命令: 引用
    wsimport -d ./bin -s ./src -p org.jsoso.jws.client.ref http://localhost:8080/hello?wsdl即可在包org.jsoso.jws.client.ref中生成客户端的存根及框架文件。其中我们要使用的类只有两个:服务类Example_Service和本地接口Example。编写如下客户端,即可调用Web Service服务: 
    package org.jsoso.jws.client;   
      
    import org.jsoso.jws.client.ref.*;   
      
    public class RunClient {   
      
        /**  
         * @param args  
         */  
        public static void main(String[] args) {   
            //初始化服务框架类   
            Example_Service service = new Example_Service();   
            //或者本地服务借口的实例   
            Example server = (Example) service.getExamplePort();   
            try {   
                //调用web service的toSayHello方法   
                System.out.println("输入toSayHello的返回值——" + server.toSayHello("阿土"));            
                 Person person = new Person();   
                 person.setName("阿土");   
                 person.setAge(25);   
                 //调用web service的sayHello方法   
                 server.sayHello(person, "机器人");   
                    
                 person = new Person();   
                 person.setName("aten");   
                 person.setAge(30);   
                 //调用web service的sayHello方法   
                 PersonArray list = server.sayHello(person, "机器人");   
                //输出返回值   
                 System.out.println("\n以下输入sayHello的返回值——");   
                for (Person p : list.getItem()) {   
                    System.out.println(p.getName() + ":" + p.getAge());   
                }              
            } catch (HelloException_Exception e) {   
                e.printStackTrace();   
            }   
        }   
    }
    届此,本次Web Service的学习暂告一个段落。Java Web Service是一个相当庞大的知识体系,其中涉及的相关技术较多,这里无法一一道来,我们将会在今后的开发和使用中,同大家做进一步深入的探讨和学习。 附录:wsgen与wsimport命令说明 wsgen 
    wsgen是在JDK的bin目录下的一个exe文件(Windows版),该命令的主要功能是用来生成合适的JAX-WS。它读取Web Service的终端类文件,同时生成所有用于发布Web Service所依赖的源代码文件和经过编译过的二进制类文件。这里要特别说明的是,通常在Web Service Bean中用到的异常类会另外生成一个描述Bean,如果Web Service Bean中的方法有申明抛出异常,这一步是必需的,否则服务器无法绑定该对像。此外,wsgen还能辅助生成WSDL和相关的xsd文件。wsgen从资源文件生成一个完整的操作列表并验证web service是否合法,可以完整发布。 
    命令参数说明:  -cp 定义classpath 
     -r 生成 bean的wsdl文件的存放目录 
     -s 生成发布Web Service的源代码文件的存放目录(如果方法有抛出异常,则会生成该异常的描述类源文件) 
     -d 生成发布Web Service的编译过的二进制类文件的存放目录(该异常的描述类的class文件) 
      

  2.   

    命令范例:wsgen -cp ./bin -r ./wsdl -s ./src -d ./bin -wsdl org.jsoso.jws.server.Example wsimport 
    wsimport也是在JDK的bin目录下的一个exe文件(Windows版),主要功能是根据服务端发布的wsdl文件生成客户端存根及框架,负责与Web Service 服务器通信,并在将其封装成实例,客户端可以直接使用,就像使用本地实例一样。对Java而言,wsimport帮助程序员生存调用web service所需要的客户端类文件.java和.class。要提醒指出的是,wsimport可以用于非Java的服务器端,如:服务器端也许是C#编写的web service,通过wsimport则生成Java的客户端实现。 
    命令参数说明:  -d 生成客户端执行类的class文件的存放目录 
     -s 生成客户端执行类的源文件的存放目录 
     -p 定义生成类的包名 命令范例:wsimport -d ./bin -s ./src -p org.jsoso.jws.client.ref http://localhost:8080/hello?wsdl 
      

  3.   

    这么好的文章居然没人支持,可见在CSDN上面了解web service的人少之又少.