Java Web系統常用的第三方接口
編寫人:阿蜜果
日期:2010-12-21
版權所有,轉載請注明出處:http://www.tkk7.com/amigoxie/archive/2010/12/21/341257.html
1. Web Service接口
1.1 接口方式說明和優點
在筆者的開發生涯中,當作為接口提供商給第三方提供接口時,以及作為客戶端去調用第三方提供的接口時,大部分時候都是使用Web Service接口,Web Service作為接口使用廣泛的原因,與它的特點息息相關。
Web Service的主要目標是跨平臺的可互操作性,為了實現這一目標,Web Service 完全基于XML(可擴展標記語言)、XSD(XML Schema)等獨立于平臺、獨立于軟件供應商的標準,是創建可互操作的、分布式應用程序的新平臺。因此使用Web Service有許多優點:
1.1.1 跨防火墻的通信
如果應用程序有成千上萬的用戶,而且分布在世界各地,那么客戶端和服務器之間的通信將是一個棘手的問題。因為客戶端和服務器之間通常會有防火墻或者代理服務器。要調用Web Service,可以直接使用SOAP客戶端,然后把它和應用程序連接起來。不僅縮短了開發周期,還減少了代碼復雜度,并能夠增強應用程序的可維護性。
1.1.2 跨程序語言的應用程序集成
在企業的各種應用系統中,很多系統不是使用相同的語言編寫的,例如有的使用Java,有的使用php、C#、asp。當各種系統之間需要交互時,可使用各種語言都通用的WSDL定義接口,對外將需要的接口暴露給指定的客戶。
XML Web services 提供了在松耦合環境中使用標準協議(HTTP、XML、SOAP 和 WSDL)交換消息的能力。消息可以是結構化的、帶類型的,也可以是松散定義的。
1.1.3 軟件和數據重用
Web Service在允許重用代碼的同時,可以重用代碼背后的數據。使用Web Service,再也不必像以前那樣,要先從第三方購買、安裝軟件組件,再從應用程序中調用這些組件;只需要直接調用遠端的Web Service就可以了。
另一種軟件重用的情況是,把好幾個應用程序的功能集成起來,通過Web Service “暴露”出來,就可以非常容易地把所有這些功能都集成到你的門戶站點中,為用戶提供一個統一的、友好的界面。
可以在應用程序中使用第三方的Web Service 提供的功能,也可以把自己的應用程序功能通過Web Service 提供給別人。兩種情況下,都可以重用代碼和代碼背后的數據。
1.2 重要概念
1.2.1 何為Web Service?
Web Service是構建互聯網分布式系統的基本部件,它是一個應用程序,它向外界暴露出一個能夠通過Web進行調用的API。這就是說,別人能夠用編程的方法通過Web來調用這個應用程序。
它通過標準通信協議,在互聯網上以服務的方式發布有用的程序模塊,目前大部分是用SOAP作為通信協議。
它提供一份詳細的接口說明書,來幫助用戶構建應用程序,這個接口說明書叫WSDL(Web服務描述語言,Web Service Description Language)。
通常已發布的Web Service要注冊到管理服務器,便于使用者查詢和使用。這個是通過UDDI(統一描述、發現和集成,Universal Discovery Description and Integration)來完成的。
1.2.2 何為SOAP協議?
SOAP定義SOAP消息的XML格式(XML格式),如果你用一對SOAP標記(SOAP Elements)把XML文檔括起來,那么這個就是一個SOAP消息。
SOAP規范還定義了怎樣用XML來描述程序數據,怎樣執行RPC(遠程過程調用,Remote Procedure Call)。大多數SOAP解決方案都支持RPC-style應用程序,因為很多程序員已對DCOM或CORBA熟悉。它還支持Document-style應用程序(SOAP消息只包含XML文本信息)。Document-style應用程序有很好的靈活性,所以很多用RPC很難構建的Web Service用這種方式構建。
最后SOAP規范還定義了HTTP消息是怎樣傳輸SOAP消息的。這并不代表SOAP只能用HTTP來作為傳輸協議,MSMQ、SMTP、TCP/IP都可以做SOAP的傳輸協議。
安全性對于應用程序來說是很重要的。那么SOAP的安全性如何呢?對于把HTTP作為傳輸協議的SOAP來說是沒有問題的,因為HTTP協議已經有很好的安全構架。那么用其他傳輸協議會出現安全問題嗎?這方面也已經有相關規范
(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnglobspec/html/ws-security.asp)。
1.2.3 何為WSDL?
WSDL是一種XML文檔,它定義SOAP消息和這些消息是怎樣交換的。IDL(Interface Description Language,接口描述語言)是用于COM和CORBA的,WSDL是用于SOAP的。WSDL是一種XML文檔,所以可以閱讀和編輯,但很多時候是用工具來創建、由程序閱讀。
舉個實例,當讀者需要使用第三方的Web Service構建應用程序。你可以向接口提供商索取使用WSDL文檔,在該文檔中詳細的說明了各個方法的方法名、參數和參數類型等信息。在Java等編程語言的IDE(例如My Eclipse)中,可以根據Web Servie生成對應的測試代碼,稍微修改一下即可。
1.2.4 何為UDDI?
UDDI可以比喻成電話本,電話本里記錄的是電話信息,而UDDI記錄的是Web Service信息。可以不把Web Service注冊到UDDI。但如果要讓全球的人知道這個Web Service,最好還是注冊到UDDI。
UDDI目錄說明文件也是一個XML文檔,它包括三個部分。“白頁(White Paper)”說明提供Web Service的公司(人)信息,比如說名稱、地址和聯系方式等等。“黃頁(Yellow Paper)”說明UDDI目錄的分類,比如說金融、服務和印刷等等。“綠頁(green Paper)”說明接口(Web Service 提供的)的詳細信息。 UDDI提供多種查詢方式,來幫助你找到需要的Web Service。如果你查詢與財務有關的Web Service,那么UDDI會提供詳細的信息。
1.2.5 何為XML?
XML(Extensible Markup Language)即可擴展標記語言,它與HTML一樣,都是SGML(Standard Generalized Markup Language,標準通用標記語言)。在Web Service接口中,WSDL和UDDI目錄文件都是一種XML文檔,XML解決了數據表示的問題。
1.2.6 何為XSD?
XML解決了數據表示的問題,但它沒有定義一套標準的數據類型,更沒有說怎么去擴展這套數據類型。例如,整型數到底代表什么?16位,32位,還是64位?
W3C制定的XML Schema(XSD)就是專門解決這個問題的一套標準。它定義了一套標準的數據類型,并給出了一種語言來擴展這套數據類型。Web Service就是用XSD來作為其數據類型系統的。
1.3 開發Web Service接口和調用測試
在Java IDE環境中開發Web Service接口,以及如何調用第三方的WSDL文檔如何進行接口測試的參考文章詳見:
1)《使用XFire+Spring構建Web Service(一)——helloWorld篇》:
http://www.tkk7.com/amigoxie/archive/2007/09/26/148207.html
2)《使用XFire+Spring構建Web Service(二)》:
http://www.tkk7.com/amigoxie/archive/2007/09/28/149074.html
3)《根據wsdl生成對應的Java代碼進行接口測試(一)》:
http://www.tkk7.com/amigoxie/archive/2009/11/20/303038.html
1.4 開發舉例
1.4.1 作為提供商提供hello world的接口
參見:《使用XFire+Spring構建Web Service(一)——helloWorld篇》:
http://www.tkk7.com/amigoxie/archive/2007/09/26/148207.html
1.4.2作為提供商提供用戶信息查詢接口
參見:《使用XFire+Spring構建Web Service(二)》:
http://www.tkk7.com/amigoxie/archive/2007/09/28/149074.html
2. js接口
2.1 接口方式說明和優缺點
在開發的過程中,也遇到過需要調用第三方接口的情況,例如筆者在完成的一個股票查詢的小demo中,就需要調用新浪提供的股票查詢的js接口。另外有一次,在系統中使用了第三方的GIS系統,調用的也是js接口。因為調用js接口的門檻很低,所以有的接口供應商會提供多種調用接口的方式,例如Web Servivce接口和js接口等。
對于瀏覽器來說,script標簽的src屬性所指向資源就跟img標簽的src屬性所指向的資源一樣,都是一個靜態資源,瀏覽器會在適當的時候自動去加 載這些資源,而不會出現所謂的跨域問題。這樣我們就可以通過該屬性將要訪問的數據對象引用進當前頁面而繞過js跨域問題。當然,前提是接口必須是返回一段js腳本,如一個json對象數組定義的腳本:
modlist = [
{"modname": "mod1", "usernum": 200, "url": "/widget/info/1"},
{"modname": "mod2", "usernum": 300, "url" : "/widget/info/2"},
…
];
但script標簽也有一定的局限性,并不能解決所有js跨域問題。script標簽的src屬性值不能動態改變以滿足在不同條件下獲取不同數據的需求, 更重要的是,不能通過這種方式正確訪問以xml內容方式組織的數據。
2.2 開發舉例
2.2.1 新浪股票查詢的js接口
功能說明:stockDetail.jsp根據傳入的stockId參數,調用新浪股票查詢提供的js接口返回股票結果信息,并解析返回結果,將股票信息在頁面展示出來。
stockDetail.jsp代碼參考如下:

<%
@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<%
String stockId = request.getParameter("stockId");
if (stockId == null) {
stockId = "000001";
}
%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>股票查詢結果</title>
<link href="<%=request.getContextPath() %>/css/style.css" type="text/css" rel="stylesheet">
<script type="text/javascript" src="http://hq.sinajs.cn/list=s_sh<%=stockId %>" charset="gb2312"></script>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
</head>
<body onload="">
<div class="bodyDiv">
<table>
<tr>
<td colspan="2" valign="bottom" align="left"
style="width:176px; background: url(<%=request.getContextPath() %>/images/line2_bg.gif) repeat-x;border-bottom: 1px solid #b0bec7;"
height="19">
<span class="titleFont">
<font class="newTitleFont"><b>股票查詢結果</b></font>
</span>
</td>
</tr>
<tr>
<td>指數名稱: </td>
<td><span id="stockName"> </span></td>
</tr>
<tr>
<td>當前點數: </td>
<td><span id="currentPoint"> </span></td>
</tr>
<tr>
<td>當前價格: </td>
<td><span id="currentPrice"> </span></td>
</tr>
<tr>
<td>漲跌率: </td>
<td><span id="ratio"> </span></td>
</tr>
<tr>
<td>成交額(w): </td>
<td><span id=turnVolume> </span></td>
</tr>
<tr>
<td colspan="2" valign="bottom" align="right"
style="width:176px; background: url(<%=request.getContextPath() %>/images/line2_bg.gif) repeat-x;border-bottom: 1px solid #b0bec7;"
height="19">
<span class="titleFont">
<font class="newTitleFont"><b>1日K線 0返回</b></font>
</span>
</td>
</tr>
</table>
</div>

<script language="javascript">
<!--
// 查詢結果的格式為:指數名稱,當前點數,當前價格,漲跌率,成交量(手),成交額(萬元)
// 解析字符串
var stockValue = hq_str_s_sh<%=stockId %>;
var stockArray = stockValue.split(",");
document.getElementById("stockName").innerText = stockArray[0];
document.getElementById("currentPoint").innerText = stockArray[1];
document.getElementById("currentPrice").innerText = stockArray[2];
document.getElementById("ratio").innerText = stockArray[3];
document.getElementById("turnVolume").innerText = stockArray[5];
-->
</script>
</body>
</html>
帶上6位stockId參數(例如:值為000002),實時的A股(代號為s_sh000002)查詢結果如下圖所示:

在文件頭部可看到如下一句引入了新浪提供的js:
<script type="text/javascript" src="http://hq.sinajs.cn/list=s_sh<%=stockId %>" charset="gb2312"></script>
用如下語句獲得通過接口查詢到的數據:
var stockValue = hq_str_s_sh<%=stockId %>; 2.2.2 對外提供js接口
對外提供js接口只需要通過<script src="..." type="..."/>請求的地址返回的是JSON字符串即可。
在本實例中,用到了筆者一篇JSON文章的實例(《JSON知識總結入門篇》:http://www.tkk7.com/amigoxie/archive/2010/09/25/332832.html),在上面進行了小幅修改,簡便起見,沒有創建任何的Java類,提供的對外的js接口是直接通過json.txt,通過該文件返回一個JSON字符串,在實際的應用情況中,可以是一個Ation等。
json.txt定義了JSON格式的字符串,并定義放在json這個變量中,jsInterface.html文件請求遠端的一個路徑,而后解析返回的JSON串,并打印出來。json.txt在遠端的一個服務器上,例如該文件訪問地址為:http://test.com/json.txt,文件的內容如下:
var json={
"programmers": [
{ "firstName": "阿蜜果", "lastName":"McLaughlin", "email": "brett@newInstance.com" },
{ "firstName": "范范", "lastName":"Hunter", "email": "jason@servlets.com" },
{ "firstName": "高子", "lastName":"Harold", "email": "elharo@macfaq.com" }
],
"authors": [
{ "firstName": "安安", "lastName": "Asimov", "genre": "science fiction" },
{ "firstName": "Tad", "lastName": "Williams", "genre": "fantasy" },
{ "firstName": "Frank", "lastName": "Peretti", "genre": "christian fiction" }
],
"musicians": [
{ "firstName": "茂茂", "lastName": "Clapton", "instrument": "guitar" },
{ "firstName": "Sergei", "lastName": "Rachmaninoff", "instrument": "piano" }
]
}

在本地創建一個jsInterface.html網頁,使用<script type="text/javascript" src=”…”/>請求返回json字符串的路徑信息,接著進行打印,該文件代碼如下:
<html>
<head>
<title>JS Interface Test</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="http://test.com/json.txt"></script>

<script type="text/javascript">
alert(json.programmers[0].firstName + ',' + json.programmers[0].lastName + ',' + json.programmers[0].email);
alert(json.programmers[1].firstName + ',' + json.programmers[1].lastName + ',' + json.programmers[1].email);
alert(json.programmers[2].firstName + ',' + json.programmers[2].lastName + ',' + json.programmers[2].email);
alert(json.authors[0].firstName + ',' + json.authors[0].lastName + ',' + json.authors[0].genre);
alert(json.authors[1].firstName + ',' + json.authors[1].lastName + ',' + json.authors[1].genre);
alert(json.authors[2].firstName + ',' + json.authors[2].lastName + ',' + json.authors[2].genre);
alert(json.musicians[0].firstName + ',' + json.musicians[0].lastName + ',' + json.musicians[0].instrument);
alert(json.musicians[1].firstName + ',' + json.musicians[1].lastName + ',' + json.musicians[1].instrument);
</script>
</head>
<body>
</body>
</html> 運行后可看到運行結果與《JSON知識總結入門篇》第一個實例的運行結果一致。
3. http接口
3.1 接口方式說明和優缺點
需要為第三方提供一個接口,本來打算繼續使用Web Service接口,結果那邊的開發人員說,他們沒有使用過Web Service接口(是做IPTV的一個公司),希望我們能夠提供http方式的接口。
另外我們一般在提供Web Sservice接口的同時,也對外提供http接口。
3.2 開發實例
3.2.1 向http接口發送消息的使用小程序
本實例對自己提供請求信息為xml格式的http接口,將xml格式的請求信息發給http接口的地址后,將調用接口的返回消息簡單的顯示在頁面,為了簡便起見,筆者沒有對js代碼進行包裝。
該html文件代碼如下:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GB2312">
<title>http interface test</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">

<script>
// XMLHttpRequest
var http_request = false;

function send_request(method, url, content, responseType, callback)
{
http_request = false;
// XMLHttpRequest

if(window.XMLHttpRequest)
{
//Mozilla
http_request = new XMLHttpRequest();

if(http_request.overrideMimeType)
{
//MIME
http_request.overrideMimeType("text/xml");
}

} else if(window.ActiveXObject)
{
//IE

try
{
http_request = new ActiveXObject("Msxml2.XMLHTTP");

} catch (e)
{

try
{
http_request = new ActiveXObject("Microsoft.XMLHTTP");
}

catch (e)
{}
}
}

if(!http_request)
{
window.alert("XMLHttpRequest create Error.");
return false;
}

if(responseType.toLowerCase() == "text" || responseType.toLowerCase() == "xml")
{
http_request.onreadystatechange = callback;

} else
{
window.alert("error responseType.");
return false;
}

if(method.toLowerCase() == "get")
{
http_request.open(method, url, true);

} else if(method.toLowerCase() == "post")
{
http_request.open(method, url, true);
http_request.setRequestHeader("Content-Type", "text/xml");

} else
{
window.alert("http method error.");
return false;
}
http_request.send(content);
}
function submitInfo()

{
var form = document.httpTestForm;
var pathInfo = form.pathInfo.value;
var xmlInfo = form.xmlInfo.value;
form.returnInfo.value = "wait
";
send_request("POST", pathInfo, xmlInfo, "xml", showHttpTestBack);
}

function showHttpTestBack()
{
if(http_request.readyState == 4)

{
if(http_request.status == 200)

{
var responseInfo = http_request.responseText;
var form = document.httpTestForm;
form.returnInfo.value = responseInfo;
}
}
}
</script>
</head>
<body>
<form name="httpTestForm" action="" method="post">
<table width="100%" border="1">
<tr>
<td colspan="2" align="center">
<b>http interface Test</b>
</td>
</tr>
<tr>
<td>xmlInfo:</td>
<td>
<textarea id="xmlInfo" name="xmlInfo" cols="100" rows="5"></textarea>
</td>
</tr>
<tr>
<td>pathInfo:</td>
<td>
<input type="text" name="pathInfo" value="http://192.168.2.154:16000/Mbd/http/video" size="100" />
</td>
</tr>
<tr>
<td>returnInfo:</td>
<td>
<textarea name="returnInfo" id="returnInfo" cols="100" rows="5"></textarea>
</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="button" name="submitButton1" value="Submit" onclick="javascript:submitInfo()" />
</td>
</tr>
</table>
</form>
</body>
</html>

訪問該頁,頁面很簡單,輸入正確的xml請求消息,和正確的路徑信息,點擊“Submit”按鈕,通過ajax調用http端口,并在成功取得信息后將返回結果顯示在最后一個文本框:

3.2.2 作為提供商提供http接口
在這個實例中,服務器提供了一個http接口,在這里是一個jsp頁面的訪問地址,實際應用過程中,可以是Servlet或Action的訪問地址,在這個實例中,客戶端發送http get發送請求,帶上了hotel(賓館信息)和name(顧客姓名),http接口程序拿到參數信息后,根據一定算法檢查分配空閑房間號,這里為了簡便起見,只是隨機的生成一個數字返回給客戶端。http接口的簡單程序httpInterface.jsp如下所示:

<%
@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<%
Double room = 500 * Math.random();
out.write("hotel=" + request.getParameter("hotel")
+ ";name=" + request.getParameter("name")
+ ";room=" + room.intValue());
out.close();
%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>http Interface</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
</head>
<body>
</body>
</html>
可在IE上帶上參數訪問這個地址,可看到參考的結果信息,例如訪問http://IP:端口/應用名稱/httpInterface.jsp?hotel=motel&name=amigo,參考返回結果如下:
hotel=motel;name=amigo;room=407
4. 參考文章
1)《Web Service入門》:http://tech.it168.com/j/2007-09-09/200709092111735.shtml
2)《Web Service簡介特點,優點,缺點》:
http://hi.baidu.com/linjk03/blog/item/4ee93b03a5d29a8dd43f7cd5.html
3)《Web Service百度百科》:
http://baike.baidu.com/view/67105.htm
4)《如何解決js跨域問題》:
http://www.yaronspace.cn/blog/index.php/archives/542
posted on 2010-12-21 17:24
阿蜜果 閱讀(8733)
評論(3) 編輯 收藏 所屬分類:
Java 、
解決方案