分类: C/C++
2011-04-20 13:29:17
wsdl2h -o 头文件名 WSDL文件名或URL
xsd__string = | std::wstring | wchar_t*
wsdl2h -o ayandy.h \ -n ay -t wsmap.dat \
soapcpp2 头文件
soapcpp2 ayandy.h
soapcpp2 ayandy.h -I D:\gsoap-2.7\gsoap\import
下面将演示使用gSOAP到网上取得天气预报,互联网上有不少网站提供SOAP服务,比如Google提供的搜索API(现在已不再提 供新的License Key了),不少博客提供的API等。这里介绍一个提供天气预报服务的SOAP服务,地址是
getSupportCity 查询本天气WebService支持的城市信息。
getSupportProvince 查询本天气 WebService支持的省份信息。
getWeatherbyCityName 根据城市名称获得天 气情况。
它的WSDL地址是
现在,我们编写一个客户端去调用getWeatherbyCityName来 取得天气情况
wsdl2h -o ayandy.h
soapcpp2 -i -C -x ayandy.h -ID:\gsoap-2.7\gsoap\import
命令选项注释:
把gsoap库里的stdsoap2.cpp文件,以及上一步生成的soapServiceSoapProxy.cpp和soapC.cpp都加入到项 目。
设置加入的这三个文件为不使用预编译头。
由于参数及回传的数据都是中文,所有让gSOAP使用UTF8方式传送以防止乱码。
#include
#include
#include "soapServiceSoapProxy.h"
#include& nbsp;"ServiceSoap.nsmap" //表忘了名空间定义
using namespace std;
// 宽 字符转UTF8
string EncodeUtf8(wstring in)
{
string s(in.length()*3+1,' ');
size_t len = ::WideCharToMultiByte(CP_UTF8, 0,
in.c_str(), in.length(),
&s[0], s.length(),
NULL, NULL);
s.resize(len);
return s;
}
// UTF8 转宽字符
wstring DecodeUtf8(string in)
{
wstring s(in.length(), _T(' '));
size_t len = ::MultiByteToWideChar(CP_UTF8, 0,
in.c_str(), in.length(),
&s[0], s.length());
s.resize(len);
return s;
}
int main(int argc, char* argv[])
{
ServiceSoapProxy gs(SOAP_C_UTFSTRING);
_ns1__getWeatherbyCityName cityname;
_ns1__getWeatherbyCityNameResponse resp;
string strCityName = EncodeUtf8(L"苏州");
cityname.theCityName = &strCityName;
cityname.theDayFlag = ns1__theDayFlagEnum__Tomorrow;
if(gs.getWeatherbyCityName(&cityname, &resp) == SOAP_OK)
{
ns1__ArrayOfString *aos = resp.getWeatherbyCityNameResult;
wcout.imbue( std::locale("chs") ); //指定输出为中文
for(vector
itr=aos->string.begin(), itr_end = aos->string.end();
itr!=itr_end; ++itr)
wcout << DecodeUtf8(*itr) << endl;
}
return 0;
}
上面的代码花了一半在UTF8编码转换上,如果参数里没有中文的话,代码会简化很多:
ServiceSoapProxy gs;
_ns1__getWeatherbyCityName cityname;
_ns1__getWeatherbyCityNameResponse resp;
string strCityName("苏州");
cityname.theCityName = &strCityName;
cityname.theDayFlag = ns1__theDayFlagEnum__Tomorrow;
if(gs.getWeatherbyCityName(&cityname, &resp) == SOAP_OK)
{
ns1__ArrayOfString *aos = resp.getWeatherbyCityNameResult;
for(vector
itr=aos->string.begin(), itr_end = aos->string.end();
itr!=itr_end; ++itr)
cout << *itr << endl;
}
但是这个代码应用到中文字符串时,会发现返回的是一堆乱码,gSOAP有两种方式支持它:
使用宽字符集,如用前文演示的type map文件来转换字符串为std::wstring。
使用UTF8传送字符串,这个例子就是使用的这个方式:首先,定义ServiceSoapProxy gs的传送模式为SOAP_C_UTFSTRING;然后输入时把字符串转换成UTF8,得到输出时把UTF8转换回来。
使用UTF8时还要注意一点,如果使用纯C调用,那么应该这样设置UTF8调用:
soap sp;
soap_init(&sp);
soap_set_mode(&sp, SOAP_C_UTFSTRING);
sp.mode |= SOAP_C_UTFSTRING; //关键
也许是gSOAP的bug吧,soap_set_mode只 设置了sp.imode和sp.omode两个成员,却没有设置sp.mode。跟踪代码可以发现从服务器传回数据后,gSOAP是根据sp.mode来 决定是否使用UTF8转换的。
现在,我们自己动手写一个天气预报服务,当然,是乱报的啦,呵呵。
写一个wsmap.dat文件,里面写上:xsd__string = | std::wstring | std::wstring*
wsdl2h.exe -o ayandy.h -t wsmap.dat -e
命令选项注释:
-o ayandy.h 生成ayandy.h头文件
-t wsmap.dat 根据wsmap.dat规则转换数据类型
-e 枚举成员不要有长长的名空间前缀
soapcpp2 ayandy.h -i -x -S -I D:\Code\libs\gsoap-2.7\gsoap\import
命令选项注释:
-S 仅生成服务器框架代码
把gsoap库里的stdsoap2.cpp文件,以及上一步生成的soapServiceSoapService.cpp和soapC.cpp都加入到 项目。
设置加入的这三个文件为不使用预编译头。
打开soapcpp2生成的soapServiceSoapService.h文件,在ServiceSoapService类定义里 会看到这样几行字:
///
/// Service operations (you should define these):
///
它后面的几个方法是要我们自己实现它的,先看代码吧:
#include "soapServiceSoapService.h"
#include "ServiceSoap.nsmap"
/// Web service operation 'getWeatherbyCityName' (returns error code or SOAP_OK)
int ServiceSoapService::getWeatherbyCityName(
_ns1__getWeatherbyCityName *ns1__getWeatherbyCityName,
_ns1__getWeatherbyCityNameResponse *ns1__getWeatherbyCityNameResponse)
{
if(*(ns1__getWeatherbyCityName->theCityName) != L"苏州") return SOAP_USER_ERROR;
ns1__ArrayOfString * aos = soap_new_ns1__ArrayOfString(this, -1);
aos->string.push_back( std::wstring() ); //第0个空着
if(ns1__getWeatherbyCityName->theDayFlag != Tomorrow)
{
aos->string.push_back( L"我只知道明天天气,其它的不要问我!" );
}
else
{
aos->string.push_back( L"有日食,不过下大雨,哈哈,气死你!" );
aos->string.push_back( L"下雨当然有风啦,多大我也不知道" );
}
ns1__getWeatherbyCityNameResponse->getWeatherbyCityNameResult = aos;
return SOAP_OK;
}
/// Web service operation 'getSupportProvince' (returns error code or SOAP_OK)
int ServiceSoapService::getSupportProvince(
_ns1__getSupportProvince *ns1__getSupportProvince,
_ns1__getSupportProvinceResponse *ns1__getSupportProvinceResponse)
{
return SOAP_OK;
}
/// Web service operation 'getSupportCity' (returns error code or SOAP_OK)
int ServiceSoapService::getSupportCity(
_ns1__getSupportCity *ns1__getSupportCity,
_ns1__getSupportCityResponse *ns1__getSupportCityResponse)
{
return SOAP_OK;
}
int main(int argc, char* argv[])
{
ServiceSoapService sev;
return sev.run(8888);//本机8888端口
}
编译,运行,现在我们的本机8888端口开始提供天气预报的SOAP服务了。
修改之前的客户端,在main()里第一行
ServiceSoapProxy gs(SOAP_C_UTFSTRING);
后面加上:
gs.soap_endpoint="";
运行这客户端后可以就看到我们提供的优质服务了:)
本例中getWeatherbyCityName方 法里的ns1__getWeatherbyCityNameResponse参 数用于返回数据,它的getWeatherbyCityNameResult成 员是由我们来申请内存的,这个内存应该用“soap_new_ 类名”来取得,这些申请函数可以从soapH.h里找到,如本例的soap_new_ns1__ArrayOfString。
第一个参数是soap类型,它是ServiceSoapService的父类型,也是gSOAP中最重要的类型。
第二个指定申请的个数,指定为-1表示只生成一个,否则生成一个指定数目的数组。