1. 前言
??? 在一些多功能服務系統(tǒng)的開發(fā)過程中,我們遇到了這樣的問題:作為體系框架的應用程序和基于瀏覽器和WEB頁面的網絡服務很難溝通起來。有什么方法能夠把這兩種傳統(tǒng)意義上大相徑庭的開發(fā)方式高效、穩(wěn)定地集成,以盡可能地發(fā)揮其各自的優(yōu)勢呢?
2. 問題與思考
??? 運行在瀏覽器上的HTML語言有著高效,靈活的優(yōu)勢,在JAVA程序中,通過內嵌" title="內嵌">內嵌開放式的JAVA瀏覽器Mozilla,用WEB頁面的形式實現一些用戶操作界面,能夠節(jié)約很多開發(fā)的精力。但瀏覽器的編程接口一般限于導航,對網頁內部的構件和數據的訪問支持不夠。當主程序" title="主程序">主程序中采集到的數據參數需要經由HTTP協(xié)議提交到數據遠程服務器,并由瀏覽器顯示返回的結果頁面時,如何將這些參數傳遞給瀏覽器的提交頁面,同時又使主程序能得到遠程返回的數據,便成為了一個需要解決的問題。
圖1. 問題所在——主程序與瀏覽器頁面的數據傳遞
??? 傳統(tǒng)的基于瀏覽器的Web服務模式是:瀏覽器與服務器直接建立連接關系,服務器直接返回Web頁面。如果嘗試打破這種模式,由主程序提交數據,服務器以XML文件的形式返回必要的結果數據,交由程序處理,那么數據共享的問題就得以解決。同時根據預先制定的HTML模板生成本地頁面文件,再通過瀏覽器向用戶顯示,也能達到與遠程頁面相同的效果。
圖2. 問題的解決——另一種數據傳輸模式
?
3.基本原理
??? 由JAVA實現程序的主框架,內嵌Mozilla的WebClient瀏覽器組件。發(fā)生服務請求時,在程序中利用Http網絡對象將參數以Post的方式提交至遠程Servlet數據服務器。服務端" title="服務端">服務端處理請求后返回一個包含結果數據的XML頁面。客戶端" title="客戶端">客戶端得到XML文件后使用DOM對象解析出結果數據,并根據預先設計的HTML頁面模板,通過關鍵字替換的方式在本地生成結果頁面。最后在程序中調用瀏覽器的SetURL接口指定瀏覽器打開本地頁面。
4.JAVA中的Http請求
??? Sun的jdk1.3.1中,java.net包提供了一些網絡訪問功能的對象。其中網絡地址對象URL和連接對象HttpURLConnection類用于建立一個遠程的Http訪問。
???下面是它們的一些主要方法及描述。
URL類:
?
??? 下面是使用這兩個對象對網絡上的Servlet服務器進行數據查詢的例子。
??? 使用查詢腳本的地址描述作為參數創(chuàng)建一個URL對象實例,調用URL的openConnection方法打開連接。此時程序試圖連接遠端并請求腳本服務,如成功即返回一個HttpURLConnection連接實例。
??? 用連接實例的getOutputStream方法取得它的輸出流,在輸入參數字串" title="字串">字串后,服務器從后臺數據庫中查詢出結果數據,組成XML字符流并輸出,客戶端由getInputStream得到的輸入流取得并保存XML文件。寫入參數前可以通過setRequestMethod方法設置提交方法,建議在參數較復雜時使用“POST”方法。根據HTML的協(xié)議規(guī)范,參數之間用“&”號隔開。
??? 以下是主要程序代碼,已通過jdk1.3.1調試。
//指定遠程的查詢服務腳本地址
URL url = new URL("http://192.168.0.176:7001/WebApp/BasicInfQuery");
//打開Http連接
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);
//提交參數pid和name
PrintWriter out = new PrintWriter(connection.getOutputStream());
String pid = "pid="+URLEncoder.encode(“97133225");
String name = "name="+URLEncoder.encode("yang");
out.println(pid+“&”+name);
out.close();
//讀取查詢服務返回的數據
BufferedReader in
= new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
in.close();
}
5.XML數據結構定義和文件解析
??? 以一個學生信息查詢?yōu)槔?,為XML作如下的數據結構定義:以“學生信息”為根,“學生”為節(jié)點,每個節(jié)點有一個屬性“性別”,及“姓名”、“年齡”、“電話”三個子節(jié)點。
??? 客戶端程序在提交查詢后,得到服務端程序動態(tài)生成的XML文件,然后利用JAVA下的DOM對象將文件中的數據解析出來?!拔臋n對象模型”DOM是W3C制定的XML數據概念描述,它允許開發(fā)者在 XML 結構內引用、檢索和更改 XML 結構中的各項。在Sun的jdk1.4.1中包含了XML解析接口javax.xml.parser和DOM對象,它們對XML文件的處理提供了很完整的一套接口。
??? DOM在處理XML文件之前,首先將XML文件解析成對象化的文檔(Document)。javax.xml.parsers中的DocumentBuilder通過parse方法對一個XML文件進行解析,生成一個Document對象。簡單要代碼如下:
//為解析XML作準備,創(chuàng)建DocumentBuilderFactory實例,指定DocumentBuilder
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
//解析指定的XML文件,創(chuàng)建Document對象
Document doc = db.parse(inFile);
??? 解析后的Document將所有數據以父子的節(jié)點層次結構裝入內存,這些節(jié)點可以是元素、文本、屬性或其它節(jié)點類型。節(jié)點元素對象Element提供了對其元素的值和子節(jié)點的訪問。下面是Element對象的一些方法定義和描述。
?
方法?描述???
GetAttribute(String name)?取得指定屬性名的屬性值???
GetElementsByTagName(String name)?取得指定節(jié)點名的子節(jié)點隊列?
getElementsByTagName 返回的NodeList對象實質是一個Element的隊列,其item(n)方法返回其中的第n個Element對象。
?以下一段代碼用于讀取Document對象中樹形節(jié)點的值:
Element root = doc.getDocumentElement();
//取"學生"元素列表
NodeList students = root.getElementsByTagName("學生");
for (int i = 0; i < students.getLength(); i++)
{
?//依次取每個"學生"元素
?Element student = (Element) students.item(i);
?//取學生的性別屬性
?String sex = student.getAttribute("性別");
//取"姓名"元素,其他類同
?NodeList names = student.getElementsByTagName("姓名");
?if (names.getLength() == 1) {
??Element e = (Element) names.item(0);
??Text t = (Text) e.getFirstChild();
??String name = t.getNodeValue();
?}
}
注:在Apache提供的XML開發(fā)工具包crimson的幫助下,DOM對象也能用于將一個Document的數據寫入XML文件。在我們的數據服務器端,因為生成XML文件相比較解析文件來的簡單,我們并沒有使用這一功能,但在一些XML結構較復雜的情況下,使用一個清晰的文檔對象也是很有必要的。相關的資料可參考Apache網站上crimson的開發(fā)文檔。
6.HTML模板定義和頁面的動態(tài)創(chuàng)建
??? HTML模板是在源碼中添加了一些自定義的標記(tag)的HTML文件,這些tag用于在動態(tài)創(chuàng)建頁面時指示數據字串的插入位置。
??? 對于預先設計的HTML頁面,以文本方式編輯他們的源碼。在顯示數據的位置用自定義的tag作出標記,這些tag以一個在HTML語法中不常出現的特殊符號作為起始和終止符,如”%”,以它們的數據意義來命名。例如姓名的tag定義為”%name%”,性別為”%sex%”,類似。下面是一個模板中部分代碼的舉例:
?姓名 %name%
?性別 %sex%
?年齡 %age%
??? 在創(chuàng)建頁面時,程序將模板以文本方式讀入一個String類型變量中,然后依次查找每個數據所對應的tag的位置,用表示數據的字串替換它。在Java中實現字串替換的代碼如下:
? public void ReplaceStr(String sTag, String sData){
??? int index;
??? while((index=sHTML.indexOf(sTag))>=0)
????? sHTML=sHTML.substring(0,index)+sData+sHTML.substring(index+sTag.length(),sHTML.length());
? }
??? 把所有定義的tag替換之后,就創(chuàng)建出一個表示當前操作的結果數據的動態(tài)HTML頁面。通過程序內置的瀏覽器在本地打開這個HTML頁面,最終實現了將服務結果向用戶輸出。
7.方法的優(yōu)缺點討論
優(yōu)點:
??? 成功解決了數據共享的問題,因而極大地拓展了瀏覽器在服務系統(tǒng)開發(fā)中的應用領域,從而能夠充分利用開發(fā)資源,高效的開發(fā)出基于網絡的數據服務。
??? 以XML作為數據載體,直接以數據的形式返回結果,可讀性強,易于調試。
??? XML的體積較小,可以減輕服務器和網絡的負擔。
??? 方法不僅限于JAVA程序,在其他開發(fā)平臺上也可以通過類似的辦法實現。
??? 可以通過XSL擴展XML在瀏覽器上的顯示功能,省去創(chuàng)建動態(tài)網頁的步驟。
缺點:
??? 文本形式的XML存在著不小的安全問題,對一些機密的數據需要加密后傳輸。
??? 將HTML頁面存放在客戶端的形式在多臺客戶機的情況下會對維護和更新頁面造成一定的難度,可以考慮在客戶端建立一個被動式的遠程頁面更新服務。
8.結束語
??? 因為篇幅有限,這里只舉了一個最簡單的例子,但我們仍然能體會到在應用程序的Web服務中使用瀏覽器所帶來的便捷和強大的功能。這種方法突破了數據訪問上的束縛,能夠最大限度的發(fā)揮各自的優(yōu)勢,提高了軟件的整體性能,又節(jié)約了寶貴的開發(fā)時間和精力。
參考文獻
1.Mark Birbect 等著,裴劍鋒 等譯,XML 高級編程(第2版),2002
2.Tom Myers Alexander Nakhimovsky 著,王輝 等譯,Java XML編程指南, 2001
3.Bruce Eckel 著,侯捷 譯,Java編程思想(第2版),2002
4.Dan Becker, Explore online XML data with Java programming,IBM developerWorks journal.,August 2002
?