开发 WebService 服务首先需要根据接口的要求编写相关的 wsdl 文件。编写 wsdl 文件需要先对 XML 语法、XML Schema 语法以及 SOAP 语法有一些简单了解。

假设需要提供一个 Student 服务,该服务仅提供一个操作:add($student),通过 add 方法添加学生信息。即需要定义一个 Student 类,该类仅包括一个方法 add,该方法的参数是一个一维数组,数组键名包括:name(string)/sex(int)/age(int)。现在开始定义对应的 wsdl 文件。

wsdl 文件基本结构

wsdl 文件的结构大致如下:

 <definitions>
<types>
definition of types........
</types> <message>
definition of a message....
</message> <portType>
<operation>
definition of a operation.......
</operation>
</portType> <binding>
definition of a binding....
</binding> <service>
definition of a service....
</service>
</definitions>

主要有五个元素构成:types、message、portType、binding、service。根元素是 definitions。

第一步:声明 wsdl 文件
wsdl 文件本质仍是一个 XML 文件,所以第一行进行 XML 文件声明:
<?xml version="1.0" encoding="UTF-8"?>
第二步:定义 definitions 根元素
定义 definitions 元素时,需要定义之后将要使用的命名空间及其他属性。
<wsdl:definitions
name="StudentService"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://example.com/student/index.php"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://example.com/student/index.php"
>
...
</wsdl:definitions>

xmlns:soap、xmlns:wsdl、xmlns:xsd 这三个命名空间是默认的命名空间,其他默认的命名空间还有:

命名空间
wsdl http://schemas.xmlsoap.org/wsdl/
soap
http http://schemas.xmlsoap.org/wsdl/http/
mime http://schemas.xmlsoap.org/wsdl/mime/
soapenc http://schemas.xmlsoap.org/soap/encoding/
soapenv http://schemas.xmlsoap.org/soap/envelope/
xsi http://www.w3.org/2000/10/XMLSchema-instance
xsd http://www.w3.org/2000/10/XMLSchema
  1. targetNamesapce:指定该服务所属的命名空间,作用相当于 Java 中的 package。防止与其他 wsdl 文件冲突。一般指定为服务地址即可。
  2. xmlns:soap:定义 soap 命名空间,指定该服务遵守的 soap 版本。
  3. xmlns:wsdl:定义 wsdl 命名空间。该服务遵守的 wsdl 规范。注意:如果不定义该命名空间,则需要定义一个默认命名空间,即xmlns="http://schemas.xmlsoap.org/wsdl/"。定义该命名空间后,所有的 wsdl 元素都需要加载 wsdl 前缀。
  4. xmlns:xsd:定义 xsd 命名空间。XML Schema 实例遵守的规范。
  5. xmlns:tns:自定义命名空间。tns 即 targetNamespace,该文件中定义的新元素属于该命名空间。一般定义为服务地址即可。
第三步:定义 types 元素
当服务需要的数据类型超出 XML 内置的数据类型范围时,需要在 types 元素内通过 XML Schema 定义新的数据类型。
根据 Student 服务 add 方法的需求,需要定义 addRequest 数据类型表示请求参数的结构,定义 addResponse 数据类型表示响应消息的结构。
add 方法接受一个一维数组作为参数,键名为 name、sex、age。返回一个一位数组,键名 msg。
所以 types 元素的结构为:
<wsdl:types>
<!--xsd:schema元素的targetNamespace属性必需,且值与definitions元素的xmlns:tns相同-->
  <xsd:schema  
    targetNamespace="http://example.com/student/index.php">
    <!--定义addRequest数据类型,属于tns命名空间-->
    <xsd:element name="addRequest">
      <xsd:complexType>
        <xsd:sequence>
          <xsd:element name="name" type="xsd:string" minOccurs="0" />
          <xsd:element name="sex" type="xsd:string" minOccurs="0" />
          <xsd:element name="age" type="xsd:string" minOccurs="0" />
        </xsd:sequence>
      </xsd:complexType>
    </xsd:element>
    <!--定义addResponse数据类型,属于tns命名空间-->
    <xsd:element name="addResponse">
      <xsd:complexType>
        <xsd:sequence>
          <xsd:element name="msg" type="xsd:string" minOccurs="1" />
        </xsd:sequence>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
</wsdl:types>

<xsd:schema>元素中必须指定 targetNamespace 属性,值与definitions元素的xmlns:tns属性值相同。表示定义的新元素的隶属命名空间。

第四步:定义 message 元素
每一个 WebService 服务都有都需要定义两个 message 元素:input 和 output。input 用于描述 WebService 服务接收的参数,output 描述 WebService 服务响应消息。
每一个 message 元素由 0 或多个 part 元素构成。一个 part 元素表示一个请求或响应参数。
part 元素有两种写法:
  1. <part name="fristParam" type="xsd:string" />:描述基本类型的参数。
  2. <part name="secondParam" element="tns:addRequest" />:描述复杂类型的参数。
根据服务示例定义 message 元素:
<!--input message:addRequest message,隶属命名空间tns,数据类型是XML Schema中定义的addRequest-->
<wsdl:message name="addRequest">
  <wsdl:part element="tns:addRequest" name="request" />
</wsdl:message>
<!--output message:addResponse message,隶属命名空间tns,数据类型是XML Schema中定义的addResponse-->
<wsdl:message name="addResponse">
  <wsdl:part element="tns:addResponse" name="response" />
</wsdl:message>
第五步:定义 portType 元素
portType 元素描述了一个完整的 WebService 服务操作。通过 portType 元素定义不同的 port,用于 binding 元素的绑定操作。这些类型的 port 属于 tns 命名空间。
  • 一个 portType 元素有一个或多个 operation 元素构成。
  • 一个 operation 元素表示一个 WebService 服务,通过 operation 元素的 name 属性定义对应的 WebService 服务操作。
  • 一个 operation 元素通常包括一个 input 元素 和一个 output 元素。
根据服务示例定义 portType 元素:
<!--name属性定义portType-->
<wsdl:portType name="StudentService">
  <!--该operation元素对应add服务-->
  <wsdl:operation name="add">
    <!--input的消息类型是tns:addRequest-->
    <wsdl:input name="addInput" message="tns:addRequest" />
    <!--output的消息类型是tns:addResponse-->
    <wsdl:output name="addOutput" message="tns:addResponse" />
  </wsdl:operation>
</wsdl:portType>
第六步:定义 binding 元素
binding 元素描述了 WebService 服务如何绑定到消息协议,包括指定数据传输方式(HTTP GET/HTTP POST/SOAP),指定传输协议,指定服务地址等。
binding 元素有两个属性:name 和 type。name 属性定义 binding 元素名称,type 属性定义该 binding 指向哪一个类型的 port,即之前定义 portType 元素。type 值即 portType 元素的 name 值。
WSDL1.1 中引入了 soap 的扩展元素:soap:binding/soap:operation/soap:body。binding 元素主要由这三个元素构成。
  1. soap:binding:包括 style 属性和 transport 属性。style 属性定义了 soap 消息格式的整体样式,值为 rpc 或 document。这两个值仅表示两种不同的将 WSDL binding 转换为 SOAP message 的方式,选择任一种即可。transport 属性指定传输协议,值为http://schemas.xmlsoap.org/soap/http,表示通过soap HTTP 方式传输;值为http://schemas.xmlsoap.org/soap/smtp,表示通过 SOAP SMTP方式传输。
  2. soap:operation:将指定的 WebService 服务绑定到指定的 SOAP 实现。属性 soapAction 指定 soapAction HTTP header 内容以标识对应的服务。
  3. soap:body:包括 use 属性,值为 encoded 和 literal。指定 input 和 output 的 message 细节。
soap:binding 元素的 style 属性和 soap:body 元素的 use 属性组合有四种方式:RPC/encoded、RPC/literal、Document/encoded、Document/literal。其中 RPC/encoded 虽然合法的 WSDL,但和 Document/encoded 一样并不是 WS-I 的标准规范。所以一般指定 soap:body 元素的 use 属性值为 literal。如果使用 encoded,需要为 soap:body 元素的 encodedStyle 属性指定编码方式,一般为:”http://schemas.xmlsoap.org/soap/encoding/“。

注意:这四种组合的具体差别参考:https://www.ibm.com/developerworks/library/ws-whichwsdl/

根据服务示例定义 binding 元素:

<wsdl:binding name="StudentServiceBinding" type="tns:StudentService">
  <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
  <wsdl:operation name="add">
    <soap:operation soapAction="http://example.com/student/index.php#add" />
    <wsdl:input name="addInput">
      <soap:body use="literal" />
    </wsdl:input>
    <wsdl:output name="addOutput">
      <soap:body use="literal" />
    </wsdl:output>
  </wsdl:operation>
</wsdl:binding>
第七步:定义 service 元素
service 元素定义 WebService 支持的 port。每一个支持的协议都有一个对应的 port 元素。service 元素就是一系列 port 元素的集合。
service 元素内的 port 元素的 binding 属性关联 binding 元素的 name 属性。
service 元素内的 port 元素内的 soap:address 元素的 location 属性是 WebService 服务的地址。
根据服务示例定义 service 元素:
<wsdl:service name="StudentService">
  <wsdl:port name="StudentServicePort" binding="tns:StudentServiceBinding">
    <soap:address location="http://example.com/student/index.php?wsdl" />
  </wsdl:port>
</wsdl:service>

编写结束后将文件保存为 student.wsdl。

开发服务端

addRequest message 中仅有一个 part 元素,表示 add 方法只有一个参数。定义 Student 类:
Student.php:
class Student
{
  public function add($student)
  {
    return [ 'msg'=>json_encode($studentList, JSON_UNESCAPED_UNICODE)];
  }
}

定义 index.php:

require './Student.php';
if(isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'POST')
{
  try
  {
    $wsdl = './student.wsdl';
    $soap = new SoapServer($wsdl);
    $soap->setClass('Student');
    $soap->handle();
  }catch (SoapFault $fault){
    echo $fault->getMessage();
  }
}elseif(isset($_SERVER['REQUEST_METHOD']) && strtolower($_SERVER['QUERY_STRING']) == 'wsdl' && $_SERVER['REQUEST_METHOD'] == 'GET')
{
  header('Content-type: text/xml; charset=utf-8');
  $wsdl = file_get_contents('./student.wsdl');
  echo $wsdl;
}else
{
  echo 'No wsdl xml file';
}

客户端调用

client.php:
try
{
$soap = new SoapClient('http://127.0.0.1:8091/exercise/soap/index.php?wsdl', ['trace'=>true, 'cache_wsdl'=>WSDL_CACHE_NONE]);
  $studentInfo = ['name' => 'a', 'sex'=>'0', 'age'=>'20'];
  $backlog = $soap->add($studentInfo);
  var_dump($backlog);
}catch(Exception $e)
{
  var_dump($e->getMessage());
}

不同类型传参时的 message 元素定义

示例一:请求参数和响应数据都是基本类型
public function($int1, $str1)
{
  return json_encode(func_get_args());
}
请求参数有两个,一个是 int,一个是 string。响应消息是一个 string。
message 元素定义:

<wsdl:message name="addRequest">
  <wsdl:part name="int1" type="xsd:int" />
  <wsdl:part name="str1" type="xsd:string" />
</wsdl:message>
<wsdl:message name="addResponse">
  <wsdl:part name="return" type="xsd:string" />
</wsdl:message>
此时不需要再定义 types 元素。因为请求和响应的数据都是基本类型,不需要定义额外的数据类型。
客户端调用:

$soap = new SoapClient('http://192.168.12.118:8091/exercise/soap/index.php?wsdl', ['trace'=>true, 'cache_wsdl'=>WSDL_CACHE_NONE]);
$backlog = $soap->add(20, 'age');
var_dump($backlog);

示例二:请求参数是长度不定的一维数组

public function($idList)
{
  return json_encode($idList);
}
因为数组已经不是 XML 内置的基本数据类型了,因此需要在 types 元素内通过 XML Schema 定义一个数组的数据类型。
types 元素定义:

<wsdl:types>
  <xsd:schema
  targetNamespace="http://example.com/student/index.php">
    <!--定义addRequest数据类型,属于tns命名空间-->
    <xsd:element name="addRequest">
      <xsd:complexType>
        <xsd:sequence>
          <!--maxOccurs="unbounded"属性表示该元素出现的最大次数不定,通过该属性定义一个长度不定的数组-->
          <xsd:element name="id" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
        </xsd:sequence>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
</wsdl:types>

message 元素定义:

<wsdl:message name="addRequest">
  <wsdl:part name="idList" element="tns:addRequest" />
</wsdl:message>
<wsdl:message name="addResponse">
  <wsdl:part name="return" type="xsd:string" />
</wsdl:message>

客户端调用:

$soap = new SoapClient('http://192.168.12.118:8091/exercise/soap/index.php?wsdl', ['trace'=>true, 'cache_wsdl'=>WSDL_CACHE_NONE]);
$backlog = $soap->add([1,2,3]);
此时服务端接收的数据结构是:["id":["1","2","3"]],一个二维数组,二维数组包含一个键名为“id”的元素,该元素就是客户端传过来的一维数组。
也可以以对象类型调用:
$std = new stdClass();
$std->id = [1, 2, 3];
$backlog = $soap->add($std);

此时服务端接收到的数据格式与之前的相同。

注意:当客户端的请求参数是只有一个元素的一维数组时,服务端接收的数据不再是一个二维数组,也是一个一维数组。

客户端调用:

$backlog = $soap->add([1]);

服务端接口数据为:["id":"1"]。

示例三:传入多维数组
现在设定 add 方法接受一个参数,该参数是一个多为数组,结构如下:

[
  "num": "传入的学生信息数量",
  "studentList": [
    ["name":1, "age":20, "sex": 0],
    ["name":2, "age":20, "sex": 0],
    ...
  ]
]

服务端方法:

public function($studentInfo)
{
  return json_encode($studentInfo);
}

types 元素和 message 元素的定义:

<wsdl:types>
  <xsd:schema
  targetNamespace="http://example.com/student/index.php">
    <xsd:element name="addRequest">
      <xsd:complexType>
        <xsd:sequence>
          <xsd:element name="num" type="xsd:int" />
          <xsd:element name="studentList" type="tns:studentList" />
        </xsd:sequence>
      </xsd:complexType>
    </xsd:element>
    <!--定义studentList数据结构,长度不定的数组-->
    <xsd:complexType name="studentList">
      <xsd:sequence>
        <xsd:element name="student" type="tns:student" minOccurs="0" maxOccurs="unbounded" />
      </xsd:sequence>
    </xsd:complexType>
    <!--定义student数据结构-->
    <xsd:complexType name="student">
      <xsd:sequence>
        <xsd:element name="name" type="xsd:string" minOccurs="0" />
        <xsd:element name="age" type="xsd:string" minOccurs="0" />
        <xsd:element name="sex" type="xsd:string" minOccurs="0" />
      </xsd:sequence>
    </xsd:complexType>
  </xsd:schema>
</wsdl:types> <wsdl:message name="addRequest">
  <wsdl:part name="studentInfo" element="tns:addRequest" />
</wsdl:message>
<wsdl:message name="addResponse">
  <wsdl:part name="return" type="xsd:string" />
</wsdl:message>

定 add 方法接受一个参数,该参数是一个多为数组,结构如下:

客户端调用:

$soap = new SoapClient('http://192.168.12.118:8091/exercise/soap/index.php?wsdl', ['trace'=>true, 'cache_wsdl'=>WSDL_CACHE_NONE]);
$studentInfo = ['name' => 'a', 'sex'=>'0', 'age'=>'20'];
$list = [
  'num' => 2,
  'studentList' => [$studentInfo, $studentInfo],
];
$backlog = $soap->add($list);

注意:传入请求参数时,务必保持参数的传入顺序和 input message 中的 part 元素顺序一致。

WebService 服务开发的更多相关文章

  1. ASP.NET MVC 中应用Windows服务以及Webservice服务开发分布式定时器

    ASP.NET MVC 中应用Windows服务以及Webservice服务开发分布式定时器一:闲谈一下:1.现在任务跟踪管理系统已经开发快要结束了,抽一点时间来写一下,想一想自己就有成就感啊!!  ...

  2. 基于CXF框架下的SOAP Webservice服务端接口开发

    最近对webservice 进行入门学习,网上也是找了很多的学习资料.总得感觉就是这了解点,那了解点.感觉不够系统,不够容易入门.差不多断断续续看了一个星期了,今天小有成果,把客户端,服务端都搞定了. ...

  3. Spring Boot 开发 WebService 服务

    WebService 虽然现在大部分互联网企业不太提倡使用,但在以第三方接口为主导的市场,对方来什么接口你还得用什么接口,不可能把接口重写了.例如大部分传统的大型企业都在用 WebService,并且 ...

  4. C#开发WEBService服务 C++开发客户端调用WEBService服务

    编写WEBService服务端应用程序并部署 http://blog.csdn.net/u011835515/article/details/47615425 编写调用WEBService的C++客户 ...

  5. Java创建WebService服务及客户端实现(转)

    简介 WebService是一种服务的提供方式,通过WebService,不同应用间相互间调用变的很方便,网络上有很多常用的WebService服务,如:http://developer.51cto. ...

  6. CXF发布webService服务以及客户端调用

    这篇随笔内容是CXF发布webService服务以及客户端调用的方法 CXF是什么? 开发工作之前需要下载CXF和安装 下载地址:http://cxf.apache.org 安装过程: <1&g ...

  7. Node.js 使用 soap 模块请求 WebService 服务接口

    项目开发中需要请求webservice服务,前端主要使用node.js 作为运行环境,因此可以使用soap进行请求. 使用SOAP请求webservice服务的流程如下: 1.进入项目目录,安装 so ...

  8. Vmware Vsphere WebService SDK开发(第一讲)-基本知识学习

    刚开始这方面开发的时候,不知道如何下手,能够查到的资料特别少,而且看到很多网友和我一样也在找这方面的资料.接下来的一段时间我就结合自己所参与的项目,完成关于Vmware Vsphere WebServ ...

  9. 二十、【.Net开源】EFW框架核心类库之WebService服务

    回<[开源]EFW框架系列文章索引> EFW框架源代码下载V1.1:http://pan.baidu.com/s/1qWJjo3U EFW框架实例源代码下载:http://pan.baid ...

随机推荐

  1. 并不对劲的Loj6031:「雅礼集训 2017 Day1」字符串

    题目传送门:-> 看到题目的第一反应当然是暴力:对于串s建后缀自动机,每次询问中,求w对应的子串在s的SAM中的right集合.O(qmk)听上去显然过不了. 数据范围有个∑w<=1e5, ...

  2. CF 809 D Hitchhiking in the Baltic States —— 思路+DP(LIS)+splay优化

    题目:http://codeforces.com/contest/809/problem/D 看题解,抄标程...发现自己连 splay 都快不会写了... 首先,题目就是要得到一个 LIS: 但与一 ...

  3. javascript复制内容到剪切板/网页上的复制按钮的实现

    javascript复制内容到剪切板/网页上的复制按钮的实现:DEMO如下 <!doctype html> <html> <head> <meta chars ...

  4. poj1419 求最大独立集

    题目链接:http://poj.org/problem?id=1419 题意:求最大独立集 思路: 这里有一个定理: 最大独立集=补图的最大团最大团=补图的最大独立集 所以这里我们只要求给出的图的最大 ...

  5. ios http2客户端访问nginx失败bug

    我们将项目迁入腾讯云后,外网访问流量转发如下外网--->大禹BGP(BGPAntiDDoS)高防---->lbc(LoadBalance cluster)---->lb-----&g ...

  6. bzoj 3555: [Ctsc2014]企鹅QQ【hash+瞎搞】

    首先注意 先hash一下,双hash,然后枚举删去位置,把hash值排个序,把些相等的加起来统计一下对数即可 #include<iostream> #include<cstdio&g ...

  7. bzoj 1042: [HAOI2008]硬币购物【dp】

    设f[i]为凑i元的方案数,这个随便dp一下就行了 然后处理限制,我们考虑用容斥,也就是4个超限-3个超限+2个超限-1个超限,这里用状压枚举一下,然后i硬币超限就当做选了d[i]+1个,在s里减去, ...

  8. bzoj 1601: [Usaco2008 Oct]灌水【最小生成树】

    挺有意思的思路 如果不能自己打井,那么就是MST裸题了,考虑转换一下,自己打井就相当于连接一口虚拟的井(地下水?),所有井i到这口井的距离是w[i],这样把所有边排个序跑MST即可 #include& ...

  9. P4412 [SHOI2004]最小生成树

    传送门 不难发现,对于每一条树边肯定要减小它的权值,对于每一条非树边要增加它的权值 对于每一条非树边\(j\),他肯定与某些树边构成了一个环,那么它的边权必须大于等于这个环上的所有边 设其中一条边为\ ...

  10. java多线程下模拟抢票

    我们设置三个对象分别同时抢20张票,利用多线程实现. public class Web123506 implements Runnable{ private int ticteksNums=20;// ...