• 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);    

        }

    }

  • 相关阅读:
    基于微信红包插件的原理实现android任何APP自动发送评论(已开源)
    人家为撩妹就鼓捣个网页,我做了个约炮APP(已开源)
    android加固签名工具(源码下载)
    如何优雅的写一篇安利文-以Sugar ORM为例
    写给独立开发兄弟共勉-寂寞是19首诗和2首悲歌
    我开源了一个ios应用,你们拿去随便玩
    android用欢迎界面加载运行环境
    用c#操作Mongodb(附demo)
    sql:除非另外还指定了 TOP 或 FOR XML,否则,ORDER BY 子句在视图、内联函数、派生表、子查询
    怎样阻止Linux服务器执行rm -rf /*命令
  • 原文地址:https://www.cnblogs.com/decarl/p/2506101.html
Copyright © 2020-2023  润新知