Web Service 开发系列文章之三(一个较小的契约优先的Web Service例子,用JavaApplication发布)

Web Service 学习第三期

1、编写纯WSDL的web服务

1.1、新建目录及WSDL文件

 

 

1.2、编写WSDL

1.2.1、编写type

<wsdl:types>

<xsd:schema targetNamespace="http://www.example.org/mywsdl/">

<!-- 自己定义了两个方法,两对儿元素 -->

    <xsd:element name="add" type="tns:add"/>

    <xsd:element name="addResponse" type="tns:addResponse"/>

    <xsd:element name="divide" type="tns:divide"/>

    <xsd:element name="divideResponse" type="tns:divideResponse"/>

      

<!-- 下面要为元素定义具体的类型 -->

<xsd:complexType name="add">

    <xsd:sequence>

        <xsd:element name="a" type="xsd:int"/>

        <xsd:element name="b" type="xsd:int"/>

    </xsd:sequence>

</xsd:complexType>

<xsd:complexType name="addResponse">

    <xsd:sequence>

        <xsd:element name="addResult" type="xsd:int"/>

    </xsd:sequence>

</xsd:complexType>

 

<xsd:complexType name="divide">

    <xsd:sequence>

        <xsd:element name="num1" type="xsd:int"/>

        <xsd:element name="num2" type="xsd:int"/>

    </xsd:sequence>

</xsd:complexType>

 

<xsd:complexType name="divideResponse">

    <xsd:sequence>

        <xsd:element name="divideResult" type="xsd:int"/>

    </xsd:sequence>

</xsd:complexType>

 

</xsd:schema>

</wsdl:types>

 

 

 

1.2.2、编写message

 

<wsdl:message name="add">

    <wsdl:part name="add" element="tns:add"/>

</wsdl:message>

<wsdl:message name="addResponse">

    <wsdl:part name="addResponse" element="tns:addResponse"></wsdl:part>

</wsdl:message>

 

<wsdl:message name="divide">

    <wsdl:part name="divide" element="tns:divide"/>

</wsdl:message>

<wsdl:message name="divideResponse">

    <wsdl:part name="divideResponse" element="tns:divideResponse"></wsdl:part>

</wsdl:message>

 

1.2.3、编写portTypes

 

<!-- 指定接口和方法portType是对象的接口,所以下面的nameIMyService-->

<wsdl:portType name="IMyService">

<wsdl:operation name="add">

    <wsdl:input message="tns:add"/>

    <wsdl:output message="tns:addResponse"/>

</wsdl:operation>

 

<wsdl:operation name="divide">

    <wsdl:input message="tns:divide"/>

    <wsdl:output message="tns:divideResponse"/>

</wsdl:operation>

</wsdl:portType>

 

 

1.2.4、编写binding

 

<wsdl:binding name="myServiceSOAP" type="tns:IMyService"> <!-- type是与上面wsdl:portType name="IMyService"name相关联-->

<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>

<wsdl:operation name="add">

<!-- <soap:operation soapAction="http://www.example.org/mywsdl/NewOperation"/>-->

<wsdl:input>

<soap:body use="literal"/>

</wsdl:input>

<wsdl:output>

<soap:body use="literal"/>

</wsdl:output>

</wsdl:operation>

 

<wsdl:operation name="divide">

<!-- <soap:operation soapAction="http://www.example.org/mywsdl/NewOperation"/>-->

<wsdl:input>

<soap:body use="literal"/>

</wsdl:input>

<wsdl:output>

<soap:body use="literal"/>

</wsdl:output>

</wsdl:operation>

 

</wsdl:binding>

 

 

1.2.5、编写service

 

<!-- 下面的wsdl:service name="MyServiceImplService"name

与文档开头的命名空间xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="MyServiceImplService"中的 name对应-->

<wsdl:service name="MyServiceImplService">

<!-- wsdl:port binding="tns:myServiceSOAP"中的binging与上面wsdl:binding name="myServiceSOAP"中的name一致 -->

<wsdl:port binding="tns:myServiceSOAP" name="MyServiceImplPort">

<!-- 下面的地址是发布到网上的地址 -->

<soap:address location="http://localhost:8989/ms"/>

</wsdl:port>

</wsdl:service>

 

 

1.3、通过编写好的WSDL生成服务接口

1.3.1、生成接口

进入WSDL的目录,用wsimport根据WSDL文件生成一个客户端

wsimport -d D:\wsimport\06 -keep mywsdl.wsdl

 

 

 

 

 

 

将生成的代码拷贝到项目中

 

 

除了IMyservice.java其余文件可以删除

 

 

 

之后编写这个文件的实现类

 

其实这个接口也可以不要,直接把实现类发布成Web Service,但是通过接口发布可以通过加Annotation来控制WSDL中变量的名称

 

 

1.4、编写刚刚生成的服务接口的实现类

 

package org.example.mywsdl;

import javax.jws.WebService;

 

@WebService(endpointInterface="org.example.mywsdl.IMyService",

         targetNamespace = "http://www.example.org/mywsdl/",

         wsdlLocation = "META-INF/wsdl/mywsdl.wsdl")//指定WSDL的位置

public class MyServiceImpl implements IMyService {

 

    @Override

    public int add(int a, int b) {

        System.out.println(a + b);

        return a + b;

    }

 

    @Override

    public int divide(int num1, int num2) {

        System.out.println(num1 / num2);

        return num1 / num2;

    }

}

 

在实现类上指定自定义的WSDL的位置,之后产生类(自己理解应该是产生调用接口的.class)的时候就会根据WSDL文件产生,而不会根据实现类中的方法产生,实现类中的方法是具体执行的实现

 

具体指定WSDL的做法:wsdlLocation = "META-INF/wsdl/mywsdl.wsdl"(上面程序中的)

 

 

 

1.5、启动服务

 

1.5.1、创建一个MyServer

 

 

package org.example.mywsdl;

 

import javax.xml.ws.Endpoint;

 

public class MyServer {

    public static void main(String[] args) {

        Endpoint.publish("http://localhost:8989/ms", new MyServiceImpl());

    }

}

注意上面程序中的服务地址是自定义的WSDL中

<wsdl:service name="MyServiceImplService">

<!-- wsdl:port binding="tns:myServiceSOAP"中的binging与上面wsdl:binding name="myServiceSOAP"中的name一致 -->

<wsdl:port binding="tns:myServiceSOAP" name="MyServiceImplPort">

<!-- 下面的地址是发布到网上的地址 -->

<soap:address location="http://localhost:8989/ms"/>

</wsdl:port>

</wsdl:service>

 

 

现在只要修改WSDL,http://localhost:8989/ms?wsdl 地址下的内容就会相应的改变

 

1.6、生成客户端,执行WSDL

wsimport -d D:\wsimport\061 -keep http://localhost:8989/ms?wsdl

 

生成了客户端代码

 

 

新建客户端项目

 

 

 

 

编写Test.java测试类

 

package org.example.mywsdl;

 

public class Test {

    public static void main(String[] args) {

        MyServiceImplService mis = new MyServiceImplService();

        IMyService ms = mis.getMyServiceImplPort();

        System.out.println(ms.add(9, 3));    

    }

}

 

1.7、大总结

1.7.1、对于服务端的一些PS

 

 

项目结构

 

 

手动开发的:META-INF-wsdl-mywsdl.wsdl

 

通过编写好的wsdl生成的接口:IMyService.java(1.3.1节),

生成的这个接口中有丰富的Annotation,这些Annotation是完全符合我们自己定义的wsdl的,这些Annotation能够很好地格式化来往的SOAP消息标签名。

 

编写的实现类:MyServiceImpl.java,为了说明它与IMyService.java的关系,在此将MyServiceImpl.java代码列在下面,注意加了背景颜色的部分有了endpointInterface=…那句话就将实现类与根据我们自己定义的WSDL生成的接口联系在了一起,也就等于在实现类加上了那些Annotation如果不加endpointInterface那句话,自己手动在实现类的函数上加上诸如@WebResult@WebParam等Annotation效果也是一样的;不过wsimport可以帮我们自动通过我们定义的WSDL生成这个"带有Annotation的契约的集合---IMyService接口"

 

package org.example.mywsdl;

import javax.jws.WebService;

 

@WebService(endpointInterface="org.example.mywsdl.IMyService",

         targetNamespace = "http://www.example.org/mywsdl/",

         wsdlLocation = "META-INF/wsdl/mywsdl.wsdl")

public class MyServiceImpl implements IMyService {

    @Override

    public int add(int a, int b) {

        System.out.println(a + b);

        return a + b;

    }

    @Override

    public int divide(int num1, int num2) {

        System.out.println(num1 / num2);

        return num1 / num2;

    }

}

1.7.2、关于wsimport

 

对于服务端的接口是用本地的自己定义的WSDL文件生成的

wsimport -d D:\wsimport\06 -keep mywsdl.wsdl

 

对于客户端,是通过对外发布的WSDL(URL)生成的

wsimport -d D:\wsimport\061 -keep http://localhost:8989/ms?wsdl

 

 

1.8、增加头信息

1.8.1、添加一个类型(下面第二部分)

 

<xsd:element name="divideResponse" type="tns:divideResponse"/>

      

    <!-- 定义头信息类型,给下面的message使用 -->

    <xsd:element name="licenseInfo" type="xsd:string"/>

 

1.8.2、添加一个message(下面第二部分)

 

<wsdl:message name="divide">

    <wsdl:part name="divide" element="tns:divide"/>

</wsdl:message>

<wsdl:message name="divideResponse">

    <wsdl:part name="divideResponse" element="tns:divideResponse"></wsdl:part>

</wsdl:message>

 

 

<!-- 定义头信息的message -->

<wsdl:message name="licenseInfo">

    <wsdl:part name="licenseInfo" element="tns:licenseInfo"></wsdl:part>

</wsdl:message>

 

 

1.8.3、将头信息加在add里

 

<wsdl:operation name="add">

<!-- <soap:operation soapAction="http://www.example.org/mywsdl/NewOperation"/>-->

<wsdl:input>

<soap:body use="literal"/>

 

<!-- 加头信息 -->

<soap:header use="literal" part="licenseInfo" message="tns:licenseInfo"></soap:header>

 

</wsdl:input>

<wsdl:output>

<soap:body use="literal"/>

</wsdl:output>

</wsdl:operation>

 

1.8.4、重新导出客户端

 

1.8.5、在服务端生成的接口IMyService中给add方法添加参数用来接收头信息

 

public int add(

@WebParam(name = "a", targetNamespace = "")

int a,

@WebParam(name = "b", targetNamespace = "")

int b,

@WebParam(name = "licenseInfo", header = true)

String licenseInfo);

 

之后相应地在实现类MyServiceImpl里也增加同样的参数

 

@Override

    public int add(int a, int b, String licenseInfo) {

        System.out.println(licenseInfo);

        System.out.println(a + b);

        return a + b;

    }

 

之后重新发布,从浏览器中看WSDL完全没有变化。

 

依赖的不是我们的代码

 

 

1.8.6、在Test中用SOAP加头信息

 

package org.example.mywsdl;

 

import java.net.URL;

 

import javax.xml.namespace.QName;

import javax.xml.soap.MessageFactory;

import javax.xml.soap.SOAPBody;

import javax.xml.soap.SOAPBodyElement;

import javax.xml.soap.SOAPEnvelope;

import javax.xml.soap.SOAPHeader;

import javax.xml.soap.SOAPMessage;

import javax.xml.ws.Dispatch;

import javax.xml.ws.Service;

 

public class Test {

    public static void main(String[] args) throws Exception{

        

        String ns = "http://www.example.org/mywsdl/";

        

        QName name = new QName(ns, "MyServiceImplService");

        URL url = new URL("http://localhost:8989/ms?wsdl");

        

//        MyServiceImplService mis = new MyServiceImplService();

//        IMyService ms = mis.getMyServiceImplPort();

//        System.out.println(ms.add(9, 3));

        

        Service service = Service.create(url, name);

        

        //<wsdl:port binding="tns:myServiceSOAP" name="MyServiceImplPort">

        

        QName pname = new QName(ns, "MyServiceImplPort");

        

        //创建dispatch

        Dispatch<SOAPMessage> dis = service.createDispatch(pname, SOAPMessage.class, Service.Mode.MESSAGE);

          

        

        //组建SOAP

        SOAPMessage msg = MessageFactory.newInstance().createMessage();

        SOAPEnvelope enev = msg.getSOAPPart().getEnvelope();

        SOAPHeader header = enev.getHeader();

        SOAPBody body = enev.getBody();

        if(header == null) {

            enev.addHeader();

        }

        QName hName = new QName(ns, "licenseInfo", "ns");

        header.addHeaderElement(hName).setValue("asdf1234");

        

        QName hName2 = new QName(ns, "licenseInfo22222", "nswwwww1111111");

        header.addHeaderElement(hName2).setValue("222222");

        

        //header.addHeaderElement(hName).setValue("222222");

        

        System.out.println("head 组装信息");

        msg.writeTo(System.out);

        

        QName bname = new QName(ns, "add", "ns");

        SOAPBodyElement ele = body.addBodyElement(bname);

        ele.addChildElement("a").setValue("12");

        ele.addChildElement("b").setValue("33");

        

        System.out.println("body组装信息");

          

        

        msg.writeTo(System.out);

        System.out.println("\n invoking...");

        

        SOAPMessage rep = dis.invoke(msg);

        

        System.out.println("回复信息");

        rep.writeTo(System.out);    

    }

}

 

 

posted on 2012-05-17 13:52  decarl  阅读(2254)  评论(0编辑  收藏  举报