標籤:c++ java
一、 前言
本篇講述如果通過C++用戶端訪問Java服務端發布的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。
三、 Java服務端開發Step1 開發Java服務介面
1、 建立Java項目,匯入CXF lib目錄下的Jar包。
2、 定義WebService介面。
import javax.jws.WebMethod;import javax.jws.WebService;@WebServicepublic interface WSWebServiceIF { @WebMethod public String helloWebService(); @WebMethod public String helloWebService2(String param);}
3、 實現WebService介面
import java.nio.charset.Charset;public class WSWebService implements WSWebServiceIF{ @Override public String helloWebService() { return "Hello WS Webservice!"; } @Override public String helloWebService2(String param) { System.out.println("接收到輸入參數:" + param); String str = "1212312abns傳回值帶中文。"; return new String(str.getBytes(Charset.forName("UTF-8"))); }}
Step2藉助CXF發布WebService服務
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;import org.apache.cxf.jaxws.JaxWsServerFactoryBean;public class StartUp { public static void main(String[] args) { JaxWsServerFactoryBean jwfbean = new JaxWsServerFactoryBean(); // 將服務發布到原生10009連接埠上,服務名是WS。 jwfbean.setAddress("http://localhost:10009/WS"); jwfbean.setServiceClass(WSWebServiceIF.class); jwfbean.setServiceBean(new WSWebService()); jwfbean.create(); // 阻塞線程、等待外部訊息請求。 while(true) { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } }}
藉助CFX,用JAVA語言開發WebService服務是非常簡單的。環境配置簡單,幾句代碼就搞定。
注意:localhost在host檔案中設定是否正確,如果設定為其它無效IP。會導致服務發布失敗。
服務發布成功後可以在瀏覽器中查看服務的介面檔案了(WSDL)。
四、 C++用戶端開發Step1 使用gsoap-2.8\gsoap\bin\win32\wsdl2h.exe產生用戶端標頭檔。
執行該命令列,在wsdl2h.exe同目錄下產生hellowebservice.h標頭檔。產生C++版本,不使用STL的標頭檔。wsdl2h.exe命令還有很多參數可選,wsdl2h.exe –h顯示協助資訊。
Step2 使用gsoap-2.8\gsoap\bin\win32\ soapcpp2.exe產生樁檔案。藉助這些樁函數,在C++中可以像調用本地函數一樣訪問遠程伺服器上的WebService服務。
Soapcpp2.exe還有很多參數可選,輸入 soapcpp2.exe –h可查看協助。執行上述命令後產生的如下檔案(將紅框內的檔案拷貝到VS2010工程中):
stdsoap.h和stdsoap.cpp檔案從gsoap-2.8\gsoap目錄下拷貝過來。
Step3 開發用戶端調用代碼
#include "stdafx.h"#include "soapH.h"// 將UTF-8字元傳喚為寬字元,用於在控制台顯示wchar_t* MulityByteToWideChar(UINT CodePage, char *str){ DWORD dwNum = MultiByteToWideChar(CodePage, 0, str, -1, 0, 0); wchar_t *pwText = new wchar_t[dwNum]; MultiByteToWideChar(CodePage, 0, str, -1, pwText, dwNum); return pwText;}// 將寬字元轉換為UTF-8模式。用於傳遞參數。char* WideCharToMulityByte(UINT CodePage, wchar_t *str){ int len = WideCharToMultiByte(CodePage, 0, str, -1, 0, 0, 0, 0); char* output = new char[len + 2]; WideCharToMultiByte(CodePage, 0, str, -1, output, len + 1, 0, 0); return output;}int _tmain(int argc, _TCHAR* argv[]){ struct soap soapObject; soap_init(&soapObject); soap_set_mode(&soapObject, SOAP_C_UTFSTRING); // 測試代碼,路徑寫入程式碼。 const char* server = "http://localhost:10009/WS/WSWebServiceIF?wsdl"; // 調用無輸入參數的介面 ns1__helloWebServiceResponse rsp; ns1__helloWebService ns1; soap_call___ns1__helloWebService(&soapObject, server, "", &ns1, rsp); // 調用有輸入參數、有傳回值的介面。範例代碼中輸入參數是一個字串、傳回值也是 // 一個字串。需要傳遞更多的資訊可以加多個參數,也可以傳一個json串, 把所需內容都包在裡面。 // 推薦後一種做法。 ns1__helloWebService2 ns11; ns11.arg0 = WideCharToMulityByte(CP_UTF8, L"12341asasas帶中文"); ns1__helloWebService2Response rsp2; soap_call___ns1__helloWebService2(&soapObject, server, "", &ns11, rsp2); wchar_t* wcReturn = MulityByteToWideChar(CP_UTF8, rsp2.return_); printf("接收到傳回值:%s\n", wcReturn); soap_end(&soapObject); soap_done(&soapObject); return 0;}
Step3 調實驗證
先用Eclipse啟動Java服務端,再在VS2010中啟動用戶端,單步調試。查看介面調用和傳參,傳回值資訊。
C++與Java通過WebService通訊(上)