《VC++实战》之gSOAP方式访问WebService服务器

1 gSOAP是个什么鬼?

百度打开搜索gsoap,映入眼帘的第一栏便是gSOAP官网,进入不必详细阅读,观其大略。

《VC++实战》之gSOAP方式访问WebService服务器

大意是说gSOAP是一种编译工具,并且提供了一个SOAP/XML关于C/C++语言的实现,从而让C/C++语言研发web服务或客户端程式的工作变得轻松了很多,其他不必赘述。其实质是,使用C++的朋友,在实际开发过程中如果遇到需要通过WSDL访问对方WebService服务器或者客户端的情况下,可以采用gSOAP这种编译工具,将WebService的WSDL接口API编译为C/C++直接可以加入到工程调用的源码,方便直接生成WebService客户端/服务端。当然C++访问WebService服务端/客户端的方式可不止这一种,在windows下还可以使用Windows Web Services API和非托管com组件方式。

2 gSOAP访问WebService

2.1 下载gSOAP

同样是在gSOAP官网,左侧Download,下载最新版本。https://sourceforge.net/projects/gsoap2/files/

《VC++实战》之gSOAP方式访问WebService服务器

当前最新版本为gsoap_2.8.80

2.2 安装gSOAP

将其解压到指定目录,我这里解压路径为 F:\gsoap_2.8.80。将 F:\gsoap_2.8.80\gsoap-2.8\gsoap\bin\win32 加入系统环境变量。

3 使用wsdl2h生成头文件

wsdl2h作用是编译wsdl路径或文件生成c/c++头文件。

wsdl2h -help查看帮助可得如下使用方法:

《VC++实战》之gSOAP方式访问WebService服务器

命令最后可以是WebService接口地址(例如:http://webservice.webxml.com.cn/WebServices/WeatherWS.asmx?WSDL)也可以是导出的.wsdl文件。

  • -o 文件名,指定输出头文件
  • -n 名空间前缀 代替默认的ns
  • -c 产生纯C代码,否则是C++代码
  • -s 不要使用STL代码
  • -t 文件名,指定type map文件,默认为typemap.dat
  • -e 禁止为enum成员加上名空间前缀

wsdl2h -o CustService.h CustService.wsdl

《VC++实战》之gSOAP方式访问WebService服务器

4 使用soapcpp2生成服务器/客户端c/c++源文件

soapcpp2.exe的作用是根据头文件自动生成调用远程 SOAP服务的客户端代码(称为存根:Stub)和提供SOAP服务的框架代码外它也能从头文件生成WSDL文件(如果使用STL,需要从压缩包里找到stlvector.h放到soapcpp2.exe目录下,否则运行失败)。

soapcpp2 -help查看帮助可得如下使用方法:

《VC++实战》之gSOAP方式访问WebService服务器

  • -C 仅生成客户端代码
  • -S 仅生成服务器端代码
  • -L 不要产生soapClientLib.c和soapServerLib.c文件
  • -c 产生纯C代码,否则是C++代码(与头文件有关)
  • -I 指定import路径(见上文)
  • -x 不要产生XML示例文件
  • -i 生成C++包装,客户端为xxxxProxy.h(.cpp),服务器端为xxxxService.h(.cpp)

soapcpp2 -i -C -x CustService.h 执行后报错如下。

《VC++实战》之gSOAP方式访问WebService服务器

需要将gSOAP安装目录下gsoap\import\soap12.h拷贝到工程目录。再次执行成功。

《VC++实战》之gSOAP方式访问WebService服务器

生成如下文件

《VC++实战》之gSOAP方式访问WebService服务器

5 将生成的源码添加到工程

将生成文件中的文件***.nsmap、soapC.cpp、***SoapProxy.cpp、***SoapProxy.h、soapH.h、soapStub.h以及gSOAP安装目录下gsoap\ stdsoap2.cpp和stdsoap2.h拷贝并添加到项目工程。

《VC++实战》之gSOAP方式访问WebService服务器

6 调用示例

SoapClient.h

//////////////////////////////////// SoapClient.h
#ifndef _SOAP_CLIENT_H_
#define _SOAP_CLIENT_H_

#include <afx.h>
#include "classdef.h"

#include "soapCustServiceSoapProxy.h"

class CSoapClient
{
public:
	CSoapClient();
	virtual ~CSoapClient(void);

	void SetServerURL(const CString &endpointRoot, const CString &actionRoot);
	void StopServer();

	//查询客户等级(此接口为了兼容老的接口程序,新的参考2)
	bool IsVipCustomer(IsVipCustomerRequest &request,string &backStr);
	
	//查询客户等级(此接口为了兼容新老叫号机存在)
	bool IsVipCustomerNew(IsVipCustomerNewRequest &request,string &backStr);
	
	//刷卡完成后得到排队号以后需要触发的接口(此接口用于向大堂经理推送消息用到)
	bool CustomerAcceptedToMng(CustomerAcceptedToMngRequest &request,string &backStr);
	
	//刷卡完成后得到排队号以后需要触发的接口(此接口用于向大堂经理推送消息用到,支持上传客户排队时候排队机拍摄的客户头像数据)此接口代替了接口3
	bool CustomerAcceptedToMngImg(CustomerAcceptedToMngImgRequest &request,string &backStr);
	
	//通知客户已经被柜面叫到号(此接口是在柜员按下叫号器是触发,用于返回给柜员相应的客户信息)
	bool VipCustomerAccepted(VipCustomerAcceptedRequest &request,string &backStr);
	
	//评价结果上报
	bool AppraiseAccepted(AppraiseAcceptedRequest &request,string &backStr);

	void ConvertUTF8ToANSI(const char* strUTF8,CString &strANSI); 
	void ConvertANSIToUTF8(CString &strANSI);

public:
	CustServiceSoapProxy m_custServiceSoapProxy;
	string endpoint_root;
	string action_root;

};

#endif // _SOAP_CLIENT_H_

SoapClient.cpp

////////////////////////////////// SoapClient.cpp
#include "SoapClient.h"
#include "CustServiceSoap.nsmap"
#include <sstream>
#include "stdafx.h"

using namespace std;

CSoapClient::CSoapClient()
{
	CString strModule;
	GetModuleFileName(NULL, strModule.GetBuffer(MAX_PATH), MAX_PATH);
	//注:使用该API函数得到的是程序文件完整路径文件名,去掉文件名后才是路径。
	strModule.ReleaseBuffer();
	int pos = strModule.ReverseFind('\\');
	CString strDir;
	strDir = strModule.Left(pos);
	if( strDir.Right(1) != "\\" )
	{
		strDir += "\\" ;
	}

	CString strIniDir = strDir + ("connconfig.ini");

	char rootEndpoint[MAX_PATH]={0};
	char rootAction[MAX_PATH]={0};
	endpoint_root.clear();
	action_root.clear();

	GetPrivateProfileString(_T("Third"), _T("endpoint_root"),"",rootEndpoint,MAX_PATH,strIniDir);
	GetPrivateProfileString(_T("Third"), _T("action_root"),"",rootAction,MAX_PATH,strIniDir);

	endpoint_root = rootEndpoint;
	action_root = rootAction;

	m_custServiceSoapProxy.soap->recv_timeout = 2;//接收超时(秒)
	m_custServiceSoapProxy.soap->send_timeout = 2;//发送超时(秒)
	m_custServiceSoapProxy.CustServiceSoapProxy_init(SOAP_C_UTFSTRING, SOAP_C_UTFSTRING);
}


CSoapClient::~CSoapClient(void)
{

}

void CSoapClient::SetServerURL(const CString &endpointRoot, const CString &actionRoot)
{
	//web_ROOTUrl = web_root + "/services/RestMakeReservationService";

	//m_custServiceSoapProxy.soap_endpoint = (char*)web_ROOTUrl.GetBuffer(0);
}

void CSoapClient::StopServer()
{
	m_custServiceSoapProxy.destroy(); /* clean up mem */
}

bool CSoapClient::IsVipCustomer(IsVipCustomerRequest &request,string &backStr)
{
	if(endpoint_root.empty() || action_root.empty())
	{
		write_log(LV_INFO,"后台参数没配置好,有空值");
		AfxMessageBox("请先配置后台好参数.");
		return false;
	}

	string endpointRootStr = endpoint_root + "/e-ccs/webservice/CustService.asmx";
	string actionRootStr = action_root + "/custserv/IsVipCustomer";

	_ns1__IsVipCustomer isVipCustomer;
	_ns1__IsVipCustomerResponse isVipCustomerResponse;

	char buffer[33]={0};
	string type;
	type = itoa(request.cardType,buffer,10);
	isVipCustomer.cardType = &type;
	isVipCustomer.cardNbr = &request.cardNbr;
	isVipCustomer.deviceNbr = &request.deviceNbr;

	//调用IsVipCustomer接口
	//m_custServiceSoapProxy.IsVipCustomer(endpointRootStr.c_str(),actionRootStr.c_str(),&isVipCustomer,isVipCustomerResponse);

	if (m_custServiceSoapProxy.soap->error){
		std::ostringstream stream;
		m_custServiceSoapProxy.soap_stream_fault(stream);
		backStr = stream.str();

		return false;
	}
	else
	{

	}

	return true;
}

bool CSoapClient::IsVipCustomerNew(IsVipCustomerNewRequest &request,string &backStr)
{
	//
	return true;
}

bool CSoapClient::CustomerAcceptedToMng(CustomerAcceptedToMngRequest &request,string &backStr)
{
	if(endpoint_root.empty() || action_root.empty())
	{
		write_log(LV_INFO,"后台参数没配置好,有空值");
		AfxMessageBox("请先配置后台好参数.");
		return false;
	}

	string endpointRootStr = endpoint_root + "/e-ccs/webservice/CustService.asmx";
	string actionRootStr = action_root + "/custserv/CustomerAcceptedToMng";

	_ns1__CustomerAcceptedToMng customerAcceptedToMng;
	_ns1__CustomerAcceptedToMngResponse customerAcceptedToMngResponse;

	customerAcceptedToMng.cardType = &request.cardType;
	customerAcceptedToMng.cardNbr = &request.cardNbr;
	customerAcceptedToMng.deviceNbr = &request.deviceNbr;
	customerAcceptedToMng.queueNbr = &request.queueNbr;

	//调用CustomerAcceptedToMng接口
	//m_custServiceSoapProxy.CustomerAcceptedToMng(endpointRootStr.c_str(),actionRootStr.c_str(),&customerAcceptedToMng,customerAcceptedToMngResponse);

	if (m_custServiceSoapProxy.soap->error){
		std::ostringstream stream;
		m_custServiceSoapProxy.soap_stream_fault(stream);
		backStr = stream.str();

		return false;
	}
	else
	{
		
	}

	return true;
}

bool CSoapClient::CustomerAcceptedToMngImg(CustomerAcceptedToMngImgRequest &request,string &backStr)
{
	//
	return true;
}

bool CSoapClient::VipCustomerAccepted(VipCustomerAcceptedRequest &request,string &backStr)
{
	if(endpoint_root.empty() || action_root.empty())
	{
		write_log(LV_INFO,"后台参数没配置好,有空值");
		AfxMessageBox("请先配置后台好参数.");
		return false;
	}

	string endpointRootStr = endpoint_root + "/e-ccs/webservice/CustService.asmx";
	string actionRootStr = action_root + "/custserv/VipCustomerAccepted";

	_ns1__VipCustomerAccepted vipCustomerAccepted;
	_ns1__VipCustomerAcceptedResponse vipCustomerAcceptedResponse;

	vipCustomerAccepted.deviceNbr = &request.deviceNbr;
	vipCustomerAccepted.queueNbr = &request.queueNbr;
	vipCustomerAccepted.tellerNbr = &request.tellerNbr;
	vipCustomerAccepted.cardType = &request.cardType;
	vipCustomerAccepted.cardNbr = &request.cardNbr;

	//调用VipCustomerAccepted接口
	//m_custServiceSoapProxy.VipCustomerAccepted(endpointRootStr.c_str(),actionRootStr.c_str(),&vipCustomerAccepted,vipCustomerAcceptedResponse);

	if (m_custServiceSoapProxy.soap->error){
		std::ostringstream stream;
		m_custServiceSoapProxy.soap_stream_fault(stream);
		backStr = stream.str();

		return false;
	}
	else
	{
		
	}

	return true;
}

bool CSoapClient::AppraiseAccepted(AppraiseAcceptedRequest &request,string &backStr)
{
	if(endpoint_root.empty() || action_root.empty())
	{
		write_log(LV_INFO,"后台参数没配置好,有空值");
		AfxMessageBox("请先配置后台好参数.");
		return false;
	}

	string endpointRootStr = endpoint_root + "/e-ccs/webservice/CustService.asmx";
	string actionRootStr = action_root + "/custserv/AppraiseAccepted";

	_ns1__AppraiseAccepted appraiseAccepted;
	_ns1__AppraiseAcceptedResponse appraiseAcceptedResponse;

	appraiseAccepted.deviceNbr = &request.deviceNbr;
	appraiseAccepted.queueNbr = &request.queueNbr;
	appraiseAccepted.tellerNbr = &request.tellerNbr;
	appraiseAccepted.appraiseGrade = &request.appraiseGrade;

	//调用AppraiseAccepted接口
	//m_custServiceSoapProxy.AppraiseAccepted(endpointRootStr.c_str(),actionRootStr.c_str(),&appraiseAccepted,appraiseAcceptedResponse);

	if (m_custServiceSoapProxy.soap->error){
		std::ostringstream stream;
		m_custServiceSoapProxy.soap_stream_fault(stream);
		backStr = stream.str();

		return false;
	}
	else
	{

	}

	return true;
}

void CSoapClient::ConvertUTF8ToANSI(const char* strUTF8,CString &strANSI)  //  
{  
	int nLen = ::MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,(LPCTSTR)strUTF8,-1,NULL,0);  //返回需要的unicode长度  
	WCHAR * wszANSI = new WCHAR[nLen+1];  
	memset(wszANSI, 0, nLen * 2 + 2);  
	nLen = MultiByteToWideChar(CP_UTF8, 0, (LPCTSTR)strUTF8, -1, wszANSI, nLen); //把utf8转成unicode  

	nLen = WideCharToMultiByte(CP_ACP, 0, wszANSI, -1, NULL, 0, NULL, NULL); //得到要的ansi长度  

	char *szANSI=new char[nLen + 1];  
	memset(szANSI, 0, nLen + 1);  
	WideCharToMultiByte (CP_ACP, 0, wszANSI, -1, szANSI, nLen, NULL,NULL); //把unicode转成ansi  

	strANSI = szANSI;  

	delete wszANSI;  

	delete szANSI;  

}  

void CSoapClient::ConvertANSIToUTF8(CString &strANSI)  
{  
	int nLen = ::MultiByteToWideChar(CP_ACP,MB_ERR_INVALID_CHARS,(LPCTSTR)strANSI,-1,NULL,0);
	if(nLen>1)
	{
		WCHAR * wszUTF_8 = new WCHAR[nLen+1];  
		memset(wszUTF_8, 0, nLen * 2 + 2);  

		nLen = MultiByteToWideChar(CP_ACP, 0, (LPCTSTR)strANSI, -1, wszUTF_8, nLen);  

		nLen = WideCharToMultiByte(CP_UTF8, 0, wszUTF_8, -1, NULL, 0, NULL, NULL);  

		char *szUTF8=new char[nLen + 1];  
		memset(szUTF8, 0, nLen + 1);  

		WideCharToMultiByte(CP_UTF8, 0, wszUTF_8, -1, szUTF8, nLen, NULL,NULL);  

		strANSI = szUTF8;  

		delete wszUTF_8;  

		delete szUTF8;  
	}

}

 

 

 

;