標籤:c++ java
一、 前言
本篇講述如何通過Java用戶端訪問C++服務端發布的SOAP模式的WebService介面。文檔中的範例代碼拷貝出去即可運行,所有的代碼都是本地測試OK的;本文不但解決了介面調用的問題,同時解決了中文亂碼的問題。
二、 環境準備
1、 CXF組件:Java端用於發布WebService服務的開源組件,內部內建jetty Web容器。
2、 Gsoap組件:C++端使用者訪問WebService服務的組件。使用的是gsoap-2.8。這兩個組件可以直接google,官網下載。
3、 Eclipse:Java開發IDE。
4、 VS 2010:C++開發IDE。
三、 C++服務端開發Step1 定義WebService介面檔案helloWebService.h
//gsoap ns service name: wscplus//gsoap ns service style: rpc//gsoap ns service namespace: http://localhost:10010/wscplus.wsdl//gsoap ns service location: http://localhost:10010//gsoap ns schema namespace: urn:wscplusint ns__hellowebservice(char* param, char** result);
定義介面需要注意:
1、 介面傳回值是int型.
2、 介面名稱定義格式為 ns__xxx。
3、 輸入參數是字串指標,輸出參數是指標的指標。同樣,可以通過json串傳遞更多的內容。
4、 函數頭注釋按給的範例定義。在注釋中定義服務IP,連接埠,wsdl檔案名稱。如果函數頭未按指定格式定義,使用soapcpp2.exe轉換時將產生不了wsdl檔案。
Step2使用gsoap-2.8\gsoap\bin\win32\ soapcpp2.exe產生服務端代碼。
產生了如下檔案:
Step3 將頭.h.cpp\nsmap拷貝到VS2010工程中,編譯。
編譯不過,將soapServerLib.cpp中的#include “soapC.cpp”、#include “soapServer.cpp”注釋掉。
Step4實現WebService介面
// 實現WebService介面
int ns__hellowebservice(struct soap* soapObject, char* param, char** result){ wchar_t* param1 = MulityByteToWideChar(CP_UTF8, param); printf("接收到Java用戶端傳過來的參數-param: %s\n", WideCharToMulityByte(CP_ACP, param1)); *result = WideCharToMulityByte(CP_UTF8, L"abKJLcd123e12一大堆中文輸出參數"); return SOAP_OK;}
介面實現函數的第一個參數是struct soap* soapObject。後面的參數與helloWebService.h中定義的介面一致。為了保證中文傳輸不亂碼,接收的參數和傳回值都做了編碼轉換。
Step5 實現http_get函數,返回wsdl檔案資訊
// 編寫get響應請求,目的是為了在瀏覽器中輸入url能看到wsdl檔案。
// 也方便在soapUI等Webservice介面調試工具中能直接調用定義的介面。
int http_get(struct soap* soapObject){ FILE*fd = NULL; // wscplus.wsdl 是執行soapcpp2.exe命令時產生的。把他拷貝到了目前的目錄下。 fd = fopen("wscplus.wsdl", "rb"); //open WSDL file to copy if (!fd) { return 404; //return HTTP not found error } soapObject->http_content = "text/xml"; //HTTP header with text /xml content soap_response(soapObject, SOAP_FILE); for(;;) { size_t r = fread(soapObject->tmpbuf,1, sizeof(soapObject->tmpbuf), fd); if (!r) { break; } if (soap_send_raw(soapObject, soapObject->tmpbuf, r)) { break; //cannot send, but little we can do about that } } fclose(fd); soap_end_send(soapObject); return SOAP_OK;}
Step6 發布WebService服務
int _tmain(int argc, _TCHAR* argv[]){ struct soap soapObject; soap_init(&soapObject); soap_set_mode(&soapObject, SOAP_C_UTFSTRING); soapObject.fget = http_get; soap_set_namespaces(&soapObject, namespaces); int ret = soap_bind(&soapObject, NULL, 10010, 100); if (ret < 0) { return -1; } while (true) { // 阻塞線程,等待外部請求 ret = soap_accept(&soapObject); if (ret < 0) { return -1; } soap_serve(&soapObject); soap_end(&soapObject); } return 0;}
四、 Java用戶端開發Step1建好Java項目,匯入CXF lib目錄下的Jar包。
不能不說Java的開源組件太好用,傻瓜式開發。C++的gsoap太麻煩了。
Step2 開發用戶端代碼, 調用WebService介面。
import java.nio.charset.Charset;import java.rmi.RemoteException; import javax.xml.namespace.QName; import javax.xml.rpc.ParameterMode;import javax.xml.rpc.ServiceException;import org.apache.axis.client.Call; import org.apache.axis.client.Service;import org.apache.axis.encoding.XMLType;public class StartupClient { public static void main(String[] args) { try { String endpoint = "http://localhost:10010/wscplus?wsdl"; Service service = new Service(); Call call = (Call)service.createCall(); call.setTargetEndpointAddress(endpoint); // 設定調用的介面,指定輸入參數,輸出參數 call.setOperationName(new QName("urn:wscplus", "hellowebservice")); call.addParameter("param", XMLType.XSD_STRING, ParameterMode.IN); call.addParameter("result", XMLType.XSD_STRING, ParameterMode.OUT); call.setReturnType(XMLType.XSD_STRING); String str = "237anastasiaABG293729一大堆中文輸入參數"; String strParam = new String(str.getBytes(Charset.forName("UTF-8"))); String result = (String)call.invoke(new Object[]{strParam}); System.out.println("擷取C++服務端傳回值-result: " + result); } catch (ServiceException e) { e.printStackTrace(); } catch (RemoteException e) { e.printStackTrace(); } }}
五、 調實驗證
先啟動服務端,在eclipse中啟動用戶端單步調試,可以看輸出參數,傳回值資訊。
C++與Java通過WebService通訊(下)