前言
之前写了一篇c++发布webService服务,可惜阅读量极少,但是也确实帮助了一位有需要的人,也算是一点点欣慰。现在我再写一篇c++调用webService服务篇,包括中文传输和文件上传。
项目需要这个东西,我写一个代码示例,具体的项目代码肯定不会发布出来。遇到的坑有不少,好在一一解决了,该科学上网还是得科学上网,能解决不少问题。可恶的是文件上传的代码示例网络上居然有人用来弄积分,还要34积分,真的是可恶,一点开源精神都没有,这里要小小的鄙视一下这类人。
一、gsoap2.8
这里我下载的gsoap是最新的2.8,我们如果要上传中文的话,会遇到乱码问题。这里我们要解决一下乱码问题,不然c++上传到webService接口中会显示乱码。我这里的接口是用java写的接口,这里我为了简单说明,我会将中文参数传递和文件整合到一起,就不逐一的演示了。
这里我的接口代码我是使用springboot用cxf框架发布的webService接口,这不是重点。
java接口代码示例:
public String fileCall(DataHandler file, String params) { file.getInputStream(); System.out.printLin(params); }
我们首先要知道这个接口的wsdl地址,需要使用gsoap根据这个wsdl地址生成相关的代理类。
重点:在下面的目录中新建一个api.bat(名字可以随便起,建议使用项目名称)
原因:这里涉及到了中文字符串的调用,所以需要这样进行处理。
这里我是在win64位代码编写的,如果有需求也可以在win32下生成,步骤是一样的。
文件内容:
xsd__string = | std::wstring | wchar_t*
在当前目录下打开cmd命令窗口,shift+鼠标左键
执行如下的命令:
一般来说都是会成功的,只要严格按照我的要求来做
//这是第一条命令,执行完毕后会出现api.h头文件
.\wsdl2h.exe -o .\api.h http://localhost:8081/api/services/api?wsdl -t api.bat
//这是第二条命令,执行完后会出现如下的文件
.\soapcpp2.exe -C .\api.h -I .\api\ -x
二、编写测试调用代码
现在最关键的地方已经来了,这里还要再三的批评一下某些人,c++调用webService的代码竟然还要下载收积分!真的是可恶。
而且国内的某度搜索也不给力,搞的我直接用了科学上网,再使用我的poor English 终于得到一篇较为完美的c++上传文件的文档,自己再骚味改动一下就迫不及待地发布出来了。
好了,废话不多说,直接上码吧!
导入相关的头文件,这里注意的是,还需要导入 gsoap 文件夹内的两个文件,还有导入文件不要导入多的!
导入的文件:
这里不要自作聪明使用Clion,老老实实使用VS2010或者其他年份的版本,同样的代码,VS可以,Clion报错,说是找不到相关的定义,这里我就不吐槽了。
编写测试代码,我们编写一个Test.cpp,代码如下
我在给webService服务上传了一个本地文件,然后还传递了一些参数信息
xsd__base64Binary这个东西就是生成代码的关键类
#include <iostream>
#include <stdio.h>
#include "soapH.h"
#include "IApiWebServiceSoapBinding.nsmap"
#include <fstream>
using namespace std;
using std::ifstream;
int main(){
//SOAP客户端
struct soap m_oSoap;
//测试文件调用对象
class ns1__fileCall fileCallObject;
//测试文件返回对象
class ns1__fileCallResponse fileCallResponse;
//这里我们转到fileCallObject上,发现需要使用这个类
class xsd__base64Binary remoteFile;
//申明一个内存
unsigned char *buffer;
int fileLen;
FILE *file;
//这个rb是什么意思我也不知道
file = fopen("D:\\test\\测试文件上传文本文档.txt","rb");
if(!file){
fprintf(stderr, "Unable to open file %s", "测试文件上传文本文档.txt");
return 0;
}
//GET FILE LENGTH
fseek(file, 0, SEEK_END);
fileLen=ftell(file);
fseek(file, 0, SEEK_SET);
//ALLOCATE MEMORY
buffer=(unsigned char *)soap_malloc(&m_oSoap,fileLen+1);
if (!buffer)
{
fprintf(stderr, "Memory error! :( ");
fclose(file);
return 0;
}
//READ FILE CONTENTS INTO BUFFER AND CLOSE FILE
fread(buffer, fileLen, 1, file);
fclose(file);
remoteFile.__ptr=buffer;
remoteFile.__size=fileLen;
//soap初始化
soap_init(&m_oSoap);
//调用函数参数赋值
fileCallObject.file = &remoteFile;
fileCallObject.params=L"测试中文信息";
//发送webService请求
int nResult = soap_call___ns1__fileCall(&m_oSoap,NULL,NULL,&fileCallObject,fileCallResponse);
if (SOAP_OK == nResult) {
//输出返回结果
wchar_t *strResult = fileCallResponse.return_;
wcout.imbue(locale("chs"));
wcout<<"wcout:"<<strResult<<endl;
}
//关闭soap
soap_destroy(&m_oSoap);
soap_end(&m_oSoap);
soap_done(&m_oSoap);
system("pause");
return 0;
}
ctrl+F5,使用VS编译一下,编译成功后,双击运行
我在本地接口打了断点,很清楚的就可以看到这个len长度和buf信息。
中文参数,可以看到我的传参是prams =测试中文信息
到了这一步就大功告成!让我们一起鄙视那些需要积分下载的人吧!