基于Zend_Soap的webservice及其多语言通信(java)(一)
看了一下ZF手册中的关于Zend_Soap的说明,感觉很晕,不知所云,是不是个人理解有问题,那就不得而知了,总觉得没有动手做过的就算看了再多文档也不顶事,于是做了一个关于复杂对象传输的例子,对于那些简单对字符窜做的东西基本不实用,所以直接做个可以用到项目中的。
对于复杂对象的传输这里决不仅指的是数组,还有自定义对象(stdclass),有人说php数组可以解决复杂数据结构的问题用自定义对象不是多此一举,原则上是这样,但是如果涉及到多语言通信的话,问题就会暴露出来,这个我们先放一下,在说完这个实例后再谈。
Zend_Soap中的自定义对象的关键点在于annotation,annotation在java中用的较多,不知道php中是不是这么叫,总知是一个参数类型的说明,看例子。
<?php class Role{ /** * @return string */ public function getDesc() { return $this->desc; } /** * @return string */ public function getParentid() { return $this->parentid; } /** * @return string */ public function getRoleid() { return $this->roleid; } /** * @return string */ public function getRolename() { return $this->rolename; } /** * @param string $desc */ public function setDesc($desc) { $this->desc = $desc; } /** * @param string $parentid */ public function setParentid($parentid) { $this->parentid = $parentid; } /** * @param string $roleid */ public function setRoleid($roleid) { $this->roleid = $roleid; } /** * @param string $rolename */ public function setRolename($rolename) { $this->rolename = $rolename; } /** * @var string */ public $roleid; /** * @var string */ public $rolename; /** * @var string */ public $parentid; /** * @var string */ public $desc; }
这里定义了一个Role对象,并用标明了各个成员变量的类型,注意这种annotaion是不能省略的.
下面再给一个复合的数据结构的定义。
<?php require_once 'Priority.php'; class RolePriority{ /** * @return Priority[] */ public function getPrioritys() { return $this->prioritys; } /** * @return string */ public function getRoleid() { return $this->roleid; } /** * @return string */ public function getRolename() { return $this->rolename; } /** * @param Priority[] $prioritys */ public function setPrioritys($prioritys) { $this->prioritys = $prioritys; } /** * @param string $roleid */ public function setRoleid($roleid) { $this->roleid = $roleid; } /** * @param string $rolename */ public function setRolename($rolename) { $this->rolename = $rolename; } /** * @var string */ public $rolename; /** * @var string */ public $roleid; /** * @var Priority[] */ public $prioritys; }
这样,根据需求,一个webservice可能要设计很多这样的数据结构,这里就省略了,做法大同小异而已。
在定义完这些对象以后,我们要定义一个webservice的接口文件,也就是要这个webservice去做什么。这里定义一个名叫Gateway的文件,当然根据ZF的命名规则,这个是要加前缀的,具体怎么回事,请参考zf文档,这里不细说。
<?php require_once 'CommonMsg.php'; require_once 'MsgResp.php'; require_once 'User.php'; require_once 'UserPriority.php'; require_once 'Userole.php'; require_once 'RolePriority.php'; require_once 'Role.php'; require_once 'Priority.php'; class Custom_Soap_Gateway{ /** * @param string * @param string * @param string * @return MsgResp */ public function logonUser($username, $password,$key) { $msgResp =new MsgResp(); $user =new User(); if($username&&$password&&$key) { $user->userid ='1'; $user->sex='男'; $user->username='***'; } $msgResp->user =$user; $msgResp->code='0000'; $msgResp->msg='login successfully'; return $msgResp; } /** * @param string * @param string * @return MsgResp */ public function logoutUser($username,$key) { $msgResp =new MsgResp(); $user =new User(); if($username&&$key) { $user->userid ='1'; $user->sex='男'; $user->username='***'; } $msgResp->user =$user; $msgResp->code='0000'; $msgResp->msg='logout successfully'; return $msgResp; } /** * @param string * @param string * @return Userole */ public function getUserRole($username,$key) { $userole =new Userole(); for($i=0;$i<10;$i++) { $role =new Role(); $role->roleid =$i; $role->parentid='-1'; $role->rolename="role_$i"; $role->desc='xixi'; $userole->roles[$i]=$role; } $userole->userid='1'; $userole->username='***'; return $userole; } /** * @param array * @param string * @return MsgResp */ public function modifyUser($userinfo,$key) { $msgResp =new MsgResp(); $user =new User(); if($userinfo&&$key) { $user->userid =$userinfo[0]; $user->sex =$userinfo[1]; $user->username =$userinfo[2]; } $msgResp->user =$user; $msgResp->code='0000'; $msgResp->msg='modify successfully'; return $msgResp; } /** * @param string * @param string * @return UserPriority */ public function getUserPriority($username,$key) { $userPriority =new UserPriority(); if($username&&$key) { for($i=0;$i<10;$i++) { $priority =new Priority(); $priority->prid=$i; $priority->operation="opti_$i"; $userPriority->prioritys[$i]=$priority; } $userPriority->userid='1'; $userPriority->username='***'; } return $userPriority; } }
这里直接就给了个处理文件,返回值写死了,但做法是一样的,定义的几个方法会暴露于交互接口。
在Action中的调用处理,咱们这里就直接写了不做动态的写法。
<?php /** * * @author Administrator * */ class admin_SoapController extends Zend_Controller_Action { private $_WSDL_URI="http://localhost/ZFDEMO/admin/soap/index?wsdl"; public function preDispatch() { } public function indexAction() { if (isset ( $_GET ['wsdl'] )) { //return the WSDL $this->hadleWSDL(); } else { //handle SOAP request $this->handleSOAP (); } } public function clientAction() { error_reporting( E_ALL | E_STRICT ); try { $client = new Zend_Soap_Client('http://localhost/ZFDEMO/admin/soap/index?wsdl'); $rs_logout = $client->logoutUser('***','123456'); $rs_logon =$client->logonUser('***','123456','key'); $rs_userole =$client->getUserRole('***','123456'); $rs_priority =$client->getUserPriority('***','123456'); $userinfo =array( '0'=>'1', '1'=>'***', '2'=>'男' ); $rs_moduser =$client->modifyUser($userinfo,'11111'); Zend_Debug::dump($rs_logout,'logout user info',true); Zend_Debug::dump($rs_moduser,'modify user info',true); Zend_Debug::dump($rs_logon,'logon user info',true); Zend_Debug::dump($rs_userole,'userole info',true); Zend_Debug::dump($rs_priority,'user property info',true); } catch (SoapFault $s) { echo $s->faultstring; die('ERROR: [' . $s->faultcode . '] ' . $s->faultstring); } catch (Exception $e) { echo $e->getMessage(); die('ERROR: ' . $e->getMessage()); } } private function hadleWSDL() { $autodiscover = new Zend_Soap_AutoDiscover ('Zend_Soap_Wsdl_Strategy_ArrayOfTypeComplex'); $autodiscover->setUri('http://localhost/ZFDEMO/admin/soap/index'); $autodiscover->setClass ('Custom_Soap_Gateway'); $autodiscover->handle (); } private function handleSOAP() { try{ $soap = new Zend_Soap_Server( $this->_WSDL_URI ); $soap->setClass('Custom_Soap_Gateway'); $soap->registerFaultException(array('Custom_Soap_SoapException')); $soap->handle(); }catch(Exception $e) { echo $e->getMessage(); } } }
注意 http://localhost/ZFDEMO/admin/soap/index?wsdl 这个url实际上指向的就是indexAction,它的处理方法当然是hadleWSDL(), 其作用是通过我们的接口类自动生成wsdl的文件,并将其指向soap_server进行处理($autodiscover->setUri('http://localhost/ZFDEMO/admin/soap/index');),我们直接在IE上输入此URL得到wsdl的完整内容。

<definitions name="Custom_Soap_Gateway" targetNamespace="http://localhost/ZFDEMO/admin/soap/index">
−
<types>
−
<xsd:schema targetNamespace="http://localhost/ZFDEMO/admin/soap/index">
−
<xsd:complexType name="User">
−
<xsd:all>
<xsd:element name="userid" type="xsd:string"/>
<xsd:element name="username" type="xsd:string"/>
<xsd:element name="sex" type="xsd:string"/>
</xsd:all>
</xsd:complexType>
−
<xsd:complexType name="MsgResp">
−
<xsd:all>
<xsd:element name="user" type="tns:User"/>
<xsd:element name="code" type="xsd:string"/>
<xsd:element name="msg" type="xsd:string"/>
</xsd:all>
</xsd:complexType>
−
<xsd:complexType name="ArrayOfRole">
−
<xsd:complexContent>
−
<xsd:restriction base="soap-enc:Array">
<xsd:attribute ref="soap-enc:arrayType" wsdl:arrayType="tns:Role[]"/>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
−
<xsd:complexType name="Role">
−
<xsd:all>
<xsd:element name="roleid" type="xsd:string"/>
<xsd:element name="rolename" type="xsd:string"/>
<xsd:element name="parentid" type="xsd:string"/>
<xsd:element name="desc" type="xsd:string"/>
</xsd:all>
</xsd:complexType>
−
<xsd:complexType name="Userole">
−
<xsd:all>
<xsd:element name="username" type="xsd:string"/>
<xsd:element name="userid" type="xsd:string"/>
<xsd:element name="roles" type="tns:ArrayOfRole"/>
</xsd:all>
</xsd:complexType>
−
<xsd:complexType name="ArrayOfPriority">
−
<xsd:complexContent>
−
<xsd:restriction base="soap-enc:Array">
<xsd:attribute ref="soap-enc:arrayType" wsdl:arrayType="tns:Priority[]"/>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
−
<xsd:complexType name="Priority">
−
<xsd:all>
<xsd:element name="prid" type="xsd:string"/>
<xsd:element name="type" type="xsd:string"/>
<xsd:element name="url" type="xsd:string"/>
<xsd:element name="module" type="xsd:string"/>
<xsd:element name="operation" type="xsd:string"/>
<xsd:element name="desc" type="xsd:string"/>
</xsd:all>
</xsd:complexType>
−
<xsd:complexType name="UserPriority">
−
<xsd:all>
<xsd:element name="username" type="xsd:string"/>
<xsd:element name="userid" type="xsd:string"/>
<xsd:element name="prioritys" type="tns:ArrayOfPriority"/>
</xsd:all>
</xsd:complexType>
</xsd:schema>
</types>
−
<portType name="Custom_Soap_GatewayPort">
−
<operation name="logonUser">
<documentation>@param string</documentation>
<input message="tns:logonUserIn"/>
<output message="tns:logonUserOut"/>
</operation>
−
<operation name="logoutUser">
<documentation>@param string</documentation>
<input message="tns:logoutUserIn"/>
<output message="tns:logoutUserOut"/>
</operation>
−
<operation name="getUserRole">
<documentation>@param string</documentation>
<input message="tns:getUserRoleIn"/>
<output message="tns:getUserRoleOut"/>
</operation>
−
<operation name="modifyUser">
<documentation>@param array</documentation>
<input message="tns:modifyUserIn"/>
<output message="tns:modifyUserOut"/>
</operation>
−
<operation name="getUserPriority">
<documentation>@param string</documentation>
<input message="tns:getUserPriorityIn"/>
<output message="tns:getUserPriorityOut"/>
</operation>
</portType>
−
<binding name="Custom_Soap_GatewayBinding" type="tns:Custom_Soap_GatewayPort">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
−
<operation name="logonUser">
<soap:operation soapAction="http://localhost/ZFDEMO/admin/soap/index#logonUser"/>
−
<input>
<soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost/ZFDEMO/admin/soap/index"/>
</input>
−
<output>
<soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost/ZFDEMO/admin/soap/index"/>
</output>
</operation>
−
<operation name="logoutUser">
<soap:operation soapAction="http://localhost/ZFDEMO/admin/soap/index#logoutUser"/>
−
<input>
<soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost/ZFDEMO/admin/soap/index"/>
</input>
−
<output>
<soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost/ZFDEMO/admin/soap/index"/>
</output>
</operation>
−
<operation name="getUserRole">
<soap:operation soapAction="http://localhost/ZFDEMO/admin/soap/index#getUserRole"/>
−
<input>
<soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost/ZFDEMO/admin/soap/index"/>
</input>
−
<output>
<soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost/ZFDEMO/admin/soap/index"/>
</output>
</operation>
−
<operation name="modifyUser">
<soap:operation soapAction="http://localhost/ZFDEMO/admin/soap/index#modifyUser"/>
−
<input>
<soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost/ZFDEMO/admin/soap/index"/>
</input>
−
<output>
<soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost/ZFDEMO/admin/soap/index"/>
</output>
</operation>
−
<operation name="getUserPriority">
<soap:operation soapAction="http://localhost/ZFDEMO/admin/soap/index#getUserPriority"/>
−
<input>
<soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost/ZFDEMO/admin/soap/index"/>
</input>
−
<output>
<soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost/ZFDEMO/admin/soap/index"/>
</output>
</operation>
</binding>
−
<service name="Custom_Soap_GatewayService">
−
<port name="Custom_Soap_GatewayPort" binding="tns:Custom_Soap_GatewayBinding">
<soap:address location="http://localhost/ZFDEMO/admin/soap/index"/>
</port>
</service>
−
<message name="logonUserIn">
<part name="username" type="xsd:string"/>
<part name="password" type="xsd:string"/>
<part name="key" type="xsd:string"/>
</message>
−
<message name="logonUserOut">
<part name="return" type="tns:MsgResp"/>
</message>
−
<message name="logoutUserIn">
<part name="username" type="xsd:string"/>
<part name="key" type="xsd:string"/>
</message>
−
<message name="logoutUserOut">
<part name="return" type="tns:MsgResp"/>
</message>
−
<message name="getUserRoleIn">
<part name="username" type="xsd:string"/>
<part name="key" type="xsd:string"/>
</message>
−
<message name="getUserRoleOut">
<part name="return" type="tns:Userole"/>
</message>
−
<message name="modifyUserIn">
<part name="userinfo" type="soap-enc:Array"/>
<part name="key" type="xsd:string"/>
</message>
−
<message name="modifyUserOut">
<part name="return" type="tns:MsgResp"/>
</message>
−
<message name="getUserPriorityIn">
<part name="username" type="xsd:string"/>
<part name="key" type="xsd:string"/>
</message>
−
<message name="getUserPriorityOut">
<part name="return" type="tns:UserPriority"/>
</message>
</definitions>
得到结果如下:
logout user info object(stdClass)#44 (3) { ["user"] => object(stdClass)#45 (3) { ["userid"] => string(1) "1" ["username"] => string(9) "***" ["sex"] => string(3) "男" } ["code"] => string(4) "0000" ["msg"] => string(19) "logout successfully" } modify user info object(stdClass)#70 (3) { ["user"] => object(stdClass)#71 (3) { ["userid"] => string(1) "1" ["username"] => string(3) "男" ["sex"] => string(9) "***" } ["code"] => string(4) "0000" ["msg"] => string(19) "modify successfully" } logon user info object(stdClass)#46 (3) { ["user"] => object(stdClass)#47 (3) { ["userid"] => string(1) "1" ["username"] => string(9) "***" ["sex"] => string(3) "男" } ["code"] => string(4) "0000" ["msg"] => string(18) "login successfully" } userole info object(stdClass)#48 (3) { ["username"] => string(9) "***" ["userid"] => string(1) "1" ["roles"] => array(10) { [0] => object(stdClass)#49 (4) { ["roleid"] => string(1) "0" ["rolename"] => string(6) "role_0" ["parentid"] => string(2) "-1" ["desc"] => string(4) "xixi" } [1] => object(stdClass)#50 (4) { ["roleid"] => string(1) "1" ["rolename"] => string(6) "role_1" ["parentid"] => string(2) "-1" ["desc"] => string(4) "xixi" } [2] => object(stdClass)#51 (4) { ["roleid"] => string(1) "2" ["rolename"] => string(6) "role_2" ["parentid"] => string(2) "-1" ["desc"] => string(4) "xixi" } [3] => object(stdClass)#52 (4) { ["roleid"] => string(1) "3" ["rolename"] => string(6) "role_3" ["parentid"] => string(2) "-1" ["desc"] => string(4) "xixi" } [4] => object(stdClass)#53 (4) { ["roleid"] => string(1) "4" ["rolename"] => string(6) "role_4" ["parentid"] => string(2) "-1" ["desc"] => string(4) "xixi" } [5] => object(stdClass)#54 (4) { ["roleid"] => string(1) "5" ["rolename"] => string(6) "role_5" ["parentid"] => string(2) "-1" ["desc"] => string(4) "xixi" } [6] => object(stdClass)#55 (4) { ["roleid"] => string(1) "6" ["rolename"] => string(6) "role_6" ["parentid"] => string(2) "-1" ["desc"] => string(4) "xixi" } [7] => object(stdClass)#56 (4) { ["roleid"] => string(1) "7" ["rolename"] => string(6) "role_7" ["parentid"] => string(2) "-1" ["desc"] => string(4) "xixi" } [8] => object(stdClass)#57 (4) { ["roleid"] => string(1) "8" ["rolename"] => string(6) "role_8" ["parentid"] => string(2) "-1" ["desc"] => string(4) "xixi" } [9] => object(stdClass)#58 (4) { ["roleid"] => string(1) "9" ["rolename"] => string(6) "role_9" ["parentid"] => string(2) "-1" ["desc"] => string(4) "xixi" } } } user property info object(stdClass)#59 (3) { ["username"] => string(9) "***" ["userid"] => string(1) "1" ["prioritys"] => array(10) { [0] => object(stdClass)#60 (6) { ["prid"] => string(1) "0" ["type"] => NULL ["url"] => NULL ["module"] => NULL ["operation"] => string(6) "opti_0" ["desc"] => NULL } [1] => object(stdClass)#61 (6) { ["prid"] => string(1) "1" ["type"] => NULL ["url"] => NULL ["module"] => NULL ["operation"] => string(6) "opti_1" ["desc"] => NULL } [2] => object(stdClass)#62 (6) { ["prid"] => string(1) "2" ["type"] => NULL ["url"] => NULL ["module"] => NULL ["operation"] => string(6) "opti_2" ["desc"] => NULL } [3] => object(stdClass)#63 (6) { ["prid"] => string(1) "3" ["type"] => NULL ["url"] => NULL ["module"] => NULL ["operation"] => string(6) "opti_3" ["desc"] => NULL } [4] => object(stdClass)#64 (6) { ["prid"] => string(1) "4" ["type"] => NULL ["url"] => NULL ["module"] => NULL ["operation"] => string(6) "opti_4" ["desc"] => NULL } [5] => object(stdClass)#65 (6) { ["prid"] => string(1) "5" ["type"] => NULL ["url"] => NULL ["module"] => NULL ["operation"] => string(6) "opti_5" ["desc"] => NULL } [6] => object(stdClass)#66 (6) { ["prid"] => string(1) "6" ["type"] => NULL ["url"] => NULL ["module"] => NULL ["operation"] => string(6) "opti_6" ["desc"] => NULL } [7] => object(stdClass)#67 (6) { ["prid"] => string(1) "7" ["type"] => NULL ["url"] => NULL ["module"] => NULL ["operation"] => string(6) "opti_7" ["desc"] => NULL } [8] => object(stdClass)#68 (6) { ["prid"] => string(1) "8" ["type"] => NULL ["url"] => NULL ["module"] => NULL ["operation"] => string(6) "opti_8" ["desc"] => NULL } [9] => object(stdClass)#69 (6) { ["prid"] => string(1) "9" ["type"] => NULL ["url"] => NULL ["module"] => NULL ["operation"] => string(6) "opti_9" ["desc"] => NULL } } }