- 論壇徽章:
- 0
|
Java與JavaScript的通信 lixiaolong3456(翻譯)
關(guān)鍵字 Java與JavaScript
出處 http://www.codeproject.com
文/ Jeremiah Talkar
信任
1. 聊天演示程序內(nèi)在的想法,連同這篇文章一起都是我自己的。我所見過的所有聊天程序不是完全基于JAVA就是HTML。我的方法是這兩種方法的一個很好的平衡。
2. 我通過在Netscape開發(fā)者站點閱讀大量的文章后收集了在JAVA和JAVASCRIPT間通信的技術(shù)信息。
3. 我第一次在讀Danny Goodman的文章時(The JavaScript Apostle on the Netscape site)偶然遇到術(shù)語“不知名的applet(Faceless applet)”。因此出于對Danny的信任我使用了這個非常切題的術(shù)語。
放棄
1. 這篇文章中討論的技術(shù)已經(jīng)在Windows 2000 Professional機器上使用Internet Explorer 5.0和 Netscape Navigator 4.7測試過了。在我所知道的最佳作品中,這些技術(shù)應(yīng)該在任一瀏覽器4.0以上的版本上運行,但我不能保證我這樣做,因為我沒有時間用這些版本將它測試出來。
2. 因為JAVASCRIPT是唯一一種在兩種主要瀏覽器都得到支持的語言,所有的腳本代碼使用這種語言。我先前在http://www.ncompasslabs.com上使用了一個可用的商業(yè)插件,這個插件可以讓Netscape Navigator支持VBScript,但我去他們的站點核實這個信息的時候,這個產(chǎn)品已經(jīng)沒有列出了。
引言
我一直從事現(xiàn)代COM的工作兩年了,現(xiàn)在是我公司的e化商業(yè)產(chǎn)品團(tuán)隊的技術(shù)領(lǐng)導(dǎo)。我明白好的界面設(shè)計和在不同環(huán)境像Visual C++, Visual Basic 還有腳本下都能很好執(zhí)行程序的重要性。基于界面的程序設(shè)計的能力在我的頭腦中已經(jīng)永遠(yuǎn)確立,并且作為一個軟件工程師我試著將它應(yīng)用到我所涉及的每件事情中。
在過去的一年里,當(dāng)ASP+腳本就要被當(dāng)作這些對象的黏合劑使用的時候,經(jīng)驗告訴我們的勤奮:所有的商業(yè)邏輯應(yīng)該被壓縮在COM對象之內(nèi)。設(shè)計和開發(fā)典型的基礎(chǔ)設(shè)施和商業(yè)對象要求一個更高的技術(shù)設(shè)備,它用來比較什么是要求實際使用同一個事物的。開發(fā)這些對象的首選環(huán)境(至少在我的團(tuán)隊中)是Visual C++ / ATL / STL。微軟也鼓勵Visual Basic成為這些對象可選擇的開發(fā)環(huán)境。
這些對象被代表性的稱為“不知名的”,因為他們實現(xiàn)許多邏輯但用戶界面除外。它的表現(xiàn)層次(presentation tier)不是一個充足的客戶就是一個不充足的客戶(這個客戶有從最終用戶表達(dá)信息和聚集信息的邏輯)。然后這樣的一個客戶用這些信息通過使用不知名的對象做一些有意義的事情。這整個想法是當(dāng)商業(yè)對象改變不頻繁時表現(xiàn)層次會代表性的要求許多客戶定制。表現(xiàn)層次要求的改變也可以通過使用較少的經(jīng)驗程序來實現(xiàn)。
應(yīng)用這些相同的原理到瀏覽器環(huán)境,當(dāng)使用一種腳本語言處理表現(xiàn)方面時,在“不知名的”二進(jìn)制模塊中壓縮高度發(fā)展的客戶方的邏輯看起來是合乎邏輯的。在Windows平臺上這些模塊的選項是Java applet和ActiveX 控件/服務(wù)器。這篇文章的焦點是使用Java applet完成這個目標(biāo),因為applet是獨立于瀏覽器,平臺和處理器的(對大部分而言)。
Applet的簡短歷史
SUN Microsystems1995年在嘹亮的號角聲中引入了Java applet。Applet立即博得WEB世界的歡心,因為它們增加了在原來是一個靜態(tài)HTML的世界的瀏覽器中動態(tài)地顯示W(wǎng)EB內(nèi)容的能力。
在最初的日子里,使用Java applet作為最好的一種在網(wǎng)頁中增加動態(tài)內(nèi)容的方式出現(xiàn)了。最初Microsoft 試圖使用他們的ActiveX Control技術(shù)反對SUN提供的Java applet,但是在網(wǎng)頁內(nèi)部使用控件存在兩個主要問題:
● 二進(jìn)制模塊是處理器指定的,因此不適合作為網(wǎng)頁的一部分運行。萬維網(wǎng)(World Wide Web)如此成功的一個主要原因是使用W3C標(biāo)準(zhǔn)HTML寫出的大部分網(wǎng)頁對瀏覽器和處理器是不可知的事實。ActiveX控件正好不符合這個范例。
● 安全是一個大問題,因為控件編寫者有足夠的權(quán)利在客戶機器上存取資源。簽了名的控件允許任何一個人查看網(wǎng)頁并聰明地作出是否應(yīng)該在他/她的機器上下載一個特定控件的決定,但是所有他進(jìn)行的是一個按鈕意外的點擊(或者是高興地忽略),這樣就留下了易受攻擊的客戶機,這也正符合惡意控件編寫者的意圖。
當(dāng)動態(tài)HTML終于開始成型時,事情徹底地改變了。文檔對象模型(Document Object Model )作為可以設(shè)計的組件,它們用它們自己的屬性和方法揭露了網(wǎng)頁元素。即使Internet Explorer和Netscape Navigator瀏覽器執(zhí)行動態(tài)HTML有許多不同,但使用腳本代碼程序化的改變顯示頁內(nèi)容本身的根本主題就是是一個巨大的成功。Applet突然開始看起來是又舊又粗糙的。W3C對動態(tài)HTML的認(rèn)可最終對高度發(fā)展的,動態(tài)網(wǎng)頁的新種類調(diào)整了語氣。
在瀏覽器內(nèi)是使用Java applet有以下列出的幾種優(yōu)點:
● Applet(對大多數(shù)Applet而言)可以在多瀏覽器,平臺和處理器上工作。
● JAVA語言是典型的一種強大的概念性語言。
● JDK有許多典型的且只在高層類庫中創(chuàng)建的有用的類。
● 技術(shù)中已經(jīng)構(gòu)思了安全,applet只能用默認(rèn)值在方框中運行。如果它們要打破方框的限制則Applet必須是已經(jīng)簽了名的。
● Applet可以就發(fā)回用戶化信息,上傳/下載文件等而與網(wǎng)頁服務(wù)器取得聯(lián)系。簽了名的applet可以與任何一個服務(wù)器聯(lián)系,而不僅僅是一個它們的主機。
● 通過“查看源文件”選項不能看到applet代碼,因此保護(hù)了知識產(chǎn)權(quán)。
● JAVA的.class文件非常小,結(jié)果是下載非?。
使用Java apple的缺點:
● 在一次瀏覽器對話中,下載applet不是網(wǎng)頁使用它們的第一時間顯示就是網(wǎng)頁隨后刷新后顯示。Applet在瀏覽器對話中不長駐客戶機。事實上在大多數(shù)場合下這可以作為一種優(yōu)勢考慮。
● Applet要花很長時間初始化。
● 因為JAVA的.class文件是被JAVA虛擬機(Java virtual machine ,JVM)解釋的字節(jié)代碼,所以applet運行比本地代碼慢。
● 一個applet只是瀏覽器上真正狀態(tài)的一部分,它不會無縫完好地出現(xiàn)在網(wǎng)頁內(nèi)容中。層疊樣式單(Cascading style sheets ,CSS)也不會直接影響applet占有的矩形區(qū)域。
● Netscape Navigator 4.x有十個活動applet的限制。我不知道Internet Explorer 4.0+有任何一種這樣的限制。
使用Java applets的快速回顧
Java applets通過使用用applet標(biāo)簽被包含進(jìn)一個HTML網(wǎng)頁中。W3C 站點上HTML 4.01說明書的13.4節(jié)詳細(xì)地說明了這個標(biāo)記。它也提到贊成<object>;,而不贊成使用這個標(biāo)記。
一個簡單地包含applet的HTML網(wǎng)頁如下所示:
<html>;
<head>;
<title>;Calculator</title>;
</head>;
<body>;
<applet id="Calculator" width="300" height="500" code ="Calculator.class" codebase=".">;
<param name="InitialMode" value="Normal">;
</applet>;
</body>;
</html>;
上例中用到的屬性解釋如下:
Id
Applet實例的標(biāo)識符?蛻舴侥_本代碼能知道使用這個id的applet。
Width
這個屬性指定了applet顯示域的初始寬度(不包括applet創(chuàng)建的窗口或者對話框)。即使我經(jīng)成功使用了寬度0用 “放棄”一節(jié)中提到的瀏覽器,還是推薦使用值1作為最小的可能寬度。
Height
這個屬性指定了applet顯示域的初始高度(不包括applet創(chuàng)建的窗口或者對話框)。就像用寬度屬性一樣,推薦使用值1作為最小的可能寬度。
Code
這個屬性指定了任一類文件(包含applet編譯的applet子類或者能夠得到類的路徑,包括類文件自身)的名字,它在談到applet的codebase時會作出解釋。
Codebase
這個屬性指定applet的基本URI. 如果這個屬性沒有指定,那么它默認(rèn)最近的文檔為同一個基本URI。
只有code, width和height 屬性是必須的。
Param標(biāo)記包含一對名字的值,它允許applet第一次運行時安裝自己。
在上面的applet調(diào)用一個方法的JAVASCRIPT函數(shù)如下,它非常簡單:
<script language=Javascript>;
function SetCalculatorMode(Mode)
{
document.Calculator.SetCalculatorMode (Mode);
// Alternative way to reference the applet.
// document.applets[0].SetCalculatorMode(Mode);
}
</script>;
勞動力的分工
在這篇文章的引言部分,我暗示當(dāng)通過JavaScript代碼處理表現(xiàn)形式時,高度發(fā)展的瀏覽器方正處理的一個方法是被壓縮進(jìn)不知名的Java applets中的。這個方法要求在Java和JavaScript間雙向通信。下面幾章會研究可用的選項。
通過JAVASCRIPT代碼存取Java applet暴露的成員和函數(shù)是直截了當(dāng)?shù)模裆弦还?jié)中的SetCalculatorMode()函數(shù)說明的一樣。文檔內(nèi)的applet不是通過使用它的Id / Name就是使用applet收集的索引來查詢。
例如:
document.Calculator.SetCalculatorMode(Mode);// or document.applets[0].SetCalculatorMode(Mode);
使用netscape.javascript.JSObject類和netscape.javascript.JSException類完成了其它方向(Java to JavaScript)的通信。為了找到這些類在什么位置,我在我的硬盤驅(qū)動器上尋找所有包含字符串“JSObject”的文件。令我吃驚的是,這些文件在許多不同的程序中得到廣泛地使用,包括是Visual Interdev工程一部分的庫。
如果Netscape Navigator 4.0+安裝在你的機器上,這些.class文件在 <Navigator Installation Directory>;\communicator\program\java\classes 目錄下的Java40.jar 文件中可用。
我也在<Windows Installation Directory>;\Java\Packages目錄下的四個不同的.zip文件中尋找這些.class文件。這些.zip文件顯然是Microsoft產(chǎn)品安裝的,因為它們包含許多com.ms包。它們的用途是這兩個類對任一瀏覽器都是可用的,你可以設(shè)置你的CLASSPATH環(huán)境變量給任一個上述路徑。一個可選的方法是使用一個程序像WINZIP從.jar或者.zip文件中解壓縮這些文件到你的applet目錄下。
JSObject類
引用JSObject類成員函數(shù)的簡短描述是為了更好的理解這個類的用途。
public static JSObject getWindow (Applet applet )
這個靜態(tài)方法對含有給出的applet窗口返回一個JSObject。例如:JSObject MainWindow = JSObject.getWindow ( this );
public Object call ( String methodName, Object args[ ] )
這個函數(shù)從Java applet內(nèi)部調(diào)用一個JavaScript方法。例如:
JSObject MainWindow = JSObject.getWindow ( this );
String Arguments[ ] = {"90", "2"}; // {" ercent complete", "Time remaining"}
MainWindow.call ( "UpdateProgressIndicator", Arguments );
public Object eval ( String s )
這個方法求一個JavaScript表達(dá)式的值。表達(dá)式是這個對象上下文中待求的JavaScript源代碼的一個字符串。例如:
JSObject MainWindow = JSObject.getWindow ( this );
JSObject UserName = MainWin.eval ( "document.UserInfoForm.UserName" );
public Object getMember ( String name )
這個方法檢索JavaScript對象的一個索引成員,等價于JavaScript對象的this.name。:
JSObject MainWindow = JSObject.getWindow ( this );
JSObject DocumentPage = (JSObject)MainWindow.getMember ( "document" );
JSObject UserInfoForm = (JSObject) DocumentPage.getMember ( "UserInfoForm" );
JSObject UserName = (JSObject) UserInfoForm.getMember ( "UserName" );
public Object getSlot ( int index)
這個方法檢索JavaScript對象的一個索引成員,等價于JavaScript對象的this [index]。例如:
JSObject MainWindow = JSObject.getWindow ( this );
JSObject DocumentPage = (JSObject)MainWindow.getMember ( "document" );
JSObject Applets = (JSObject) DocumentPage.getMember ( "applets" );
Object theApplet = Applets.getSlot ( index );
public void removeMember ( String name )
這個方法刪除一個JAVASCRIPT對象的指定成員。
public void setMember ( String name, Object value )
這個方法設(shè)置一個JAVASCRIPT對象的指定成員。它等價于JavaScript對象的this.name = value。例如:
JSObject MainWin = JSObject.getWindow ( this );
JSObject DocumentPage = (JSObject) MainWin.getMember ( "document" );
JSObject UserInfoForm = (JSObject) DocumentPage.getMember ( "UserInfoForm" );
JSObject UserName = (JSObject) UserInfoForm.getMember ( "UserName" );
UserName.setMember ( "value", "Jeremiah S. Talkar" );
public void setSlot ( int index, Object value )
這個方法設(shè)置一個JAVASCRIPT對象的索引成員。它等價于JavaScript對象的this[index] = value。
public String toString ()
這個方法將JSObject轉(zhuǎn)換成一個字符串。
上面的例子是很清楚的。JSObject類的公共方法試圖在JavaApplet中調(diào)用JavaScript函數(shù)時是不受限制的。他們也可以使一個applet直接處理文檔對象模型元素。
這些類完整的文檔可以在http://developer.netscape.com/docs/manuals/communicator/jsref/pkg.htm上得到。
文檔也解釋了怎樣在Java和JavaScript間處理數(shù)據(jù)類型。
MAYSCRIPT屬性的意義
即使applet使用JSObject調(diào)用JavaScript函數(shù),或者直接訪問文檔對象模型,如果applet標(biāo)簽沒有包含在MAYSCRIPT屬性中的話JSObject的方法就會失敗。這一點能使網(wǎng)頁設(shè)計者測定一個applet是否能喚起JavaScript。
不知名的applet間的通信
在網(wǎng)頁內(nèi)使用不知名的,但可以再度使用的Java applet時,一個applet需要與另一個applet直接通信是可能的。這樣的一個呼叫也可以通過一個媒介JavaScript函數(shù)通信,但熟悉所有可用的選項總是比較好的。
java.applet包的AppletContext接口對applet的上下文實行一個訪問限制,像插入applet的瀏覽器,一個applet在網(wǎng)頁上還有其它的applet也在同樣一個網(wǎng)頁上。
例如,下面是一個HTML頁包含兩個applet:
html>;
<head>;
<title>;Communication between applets</title>;
</head>;
<body>;
<applet code="CircleArea.class" name="CircleArea" width=1 height=1>;
</applet>;
<applet code=" ICalculator.class" name=" ICalculator" width=1 height=1>;
</applet>;
...
</body>;
</html>;
下面的代碼表明了AppletContext對象的用法:
AppletContext context = getAppletContext();
PICalculator PIApplet = (PICalculator) context.getApplet ( " ICalculator" );
PIApplet.getValueOfPI();
另一個選項是使用AppletContext::getApplets()方法,它返回了一個訪問文檔內(nèi)所有applet的枚舉類型。即使applet間的通信是標(biāo)準(zhǔn)Java applet API的一部分,它也不會在所有允許JAVA的瀏覽器中得到支持。其它applet的核心編碼也是堅定不移的。最好的方法可以是使用JAVASCRIPT函數(shù)來處理這種通信。
JAVA的IUnknown: ueryInterface類對象是類層次的根。每個類有一個超類對象。所有對象,包括數(shù)組,實現(xiàn)這個類的方法。Object::getClass()方法返回有許多能探索JAVA類自身詳細(xì)資料的有用的函數(shù)的“類”。雖然在這篇文章的前面部分已經(jīng)作過詳細(xì)的解釋,我還是想指出getInterfaces()方法使動態(tài)接口的發(fā)現(xiàn)通過一個JAVA類實現(xiàn)。
我沒有試過在JAVASCRIPT內(nèi)調(diào)用getClass()方法,因此不能評論它的可行性。但是使用基礎(chǔ)類型的applet,這種功能性可以輕易地使它對腳本代碼可用。
安裝示例文件
這篇文章的示例代碼已經(jīng)在Java2JavaScript.zip文件中壓縮。示例文件演示了一個已經(jīng)在客戶方自身簡單地發(fā)送消息的一個聊天程序。用戶在不同的機器上加入這個聊天中,一條消息發(fā)送給服務(wù)器,然后廣播給所有的參加者。
組成示例的文件是:
ISession.java
定義ISession 接口的源文件
ISession.class
Isession接口的Java字節(jié)代碼
ChatClient.java
演示ChatClient applet的源文件
ChatClient.class
ChatClient applet類的Java字節(jié)代碼
CompileChatClient.bat
簡單的JAVA源文件的批處理文件
TestChatClient.htm
支持ChatClient applet HTML文件
JSObject.class
JSObject類的字節(jié)代碼
JSException.class
JSException類的字節(jié)代碼
安裝和運行示例程序的步驟是:
● 在運行有Personal Web Server或者Internet Information Server的機器上解壓縮Java2JavaScript.zip到你所選擇的目錄。
● 確保安裝目錄下的netscape\javascript 子目錄中的JSObject和JSException類文件是可用的。
● 右擊安裝目錄選擇“屬性”。
● 點擊“網(wǎng)頁共享”標(biāo)簽,選定“共享這個文件夾”單選按鈕,在彈出的對話框中接受默認(rèn)值“虛擬目錄”。
● 最后,啟動Internet Explorer 4.0+ 或者 Netscape Navigator 4.0+程序,然后輸入URL http:// <機器名>;/<虛擬目錄>;/TestChatClient.htm。
在輸入框中輸入一些文本,然后點擊相應(yīng)的“SEND”按鈕,你就會看到消息在聊天窗口中出現(xiàn)。
示例代碼解釋
聊天程序是網(wǎng)頁上流行的合作機制。我見過的聊天程序有兩種類型:
● 一種是管理用戶界面和服務(wù)器通信的Java applet。
● 另一種是每隔幾秒就通過自動刷新來顯示最后一次刷新后的所有新消息的HTML網(wǎng)頁。
最近我不得不為我們E化商業(yè)產(chǎn)品的聊天程序?qū)崿F(xiàn)產(chǎn)品質(zhì)量。經(jīng)過許多考慮后,我決定使用一個混合的方法。首先最重要的,Java applet是執(zhí)行Isession接口的一個不知名的applet。
public interface ISession
{
// Type is used to differentiate the actual message string
// and can be set to ‘Text’, Hyperlink’ etc.
// Should be invoked first to indicate to the server that a
// new person has joined the chat.
public int BeginSession(String strAuthor, String strOptions, String strType, String strMessage);
// Should be invoked when the author wants to exit the chat.
public int EndSession(String strAuthor, String strType, String strMessage);
// Used to send the chat messages.
public int SendMessage(String strAuthor, String strType, String strMessage);
}
我已經(jīng)把聊天程序產(chǎn)品版本中的這個接口作了輕微地修改,包括EndSession()和SendMessage()的Author參數(shù)。這是因為我的演示程序使用一個applet在兩個不同聊天者間傳遞聊天消息。
ChatClient.java文件是Isession接口的實際執(zhí)行文件。如果它們執(zhí)行時瀏覽器就調(diào)用函數(shù)init(), start()和stop()。描述文檔窗口的JSObject是在執(zhí)行init()方法后得到的。
// Get the JavaScript window that will have the various scripts that this applet will call.
m_JScriptWin = JSObject.getWindow(this);
因為Java applet調(diào)用兩個不同的JavaScript函數(shù),我決定使WEB開發(fā)者能像applet的參數(shù)一樣指定這些函數(shù)的名字,直到為同一個applet提供默認(rèn)值。
m_strMessageHandler = getParameter("MessageHandler" ;
m_strErrorHandler = getParameter("ErrorHandler" ;
BeginSession()和EndSession()是只執(zhí)行SendMessage()的虛擬執(zhí)行函數(shù)。
SendMessage()呼叫在m_strMessageHandler成員變量中指定的JavaScript函數(shù)名字。默認(rèn)值是“HandleSessionMessage”。相關(guān)代碼如下所示:
if (m_JScriptWin != null)
{
String Arguments[] = {strAuthor, strType, strMessage};
m_JScriptWin.call(m_strMessageHandler, Arguments);
}
HandleSessionError()調(diào)用一個在m_strErrorHandler成員變量中指定的JavaScript函數(shù)名字。默認(rèn)值是“HandleSessionError”.
TestChatClient.htm文件處理聊天的表現(xiàn)方面。applet使用<applet>;標(biāo)記包含在網(wǎng)頁中。
<applet id="ChatApplet" width="1" height="1" code="ChatClient.class" codebase="." VIEWASTEXT mayscript>;
<param name="MessageHandler" value="HandleSessionMessageEx">;
<param name="ErrorHandler" value="HandleSessionErrorEx">;
</applet>;
參數(shù)指定applet調(diào)用的兩個JavaScript函數(shù)的名字。我只表明名字除默認(rèn)值外說明了這個方法是多么靈活,網(wǎng)頁中的兩個窗體模擬兩個人正與對方聊天。相關(guān)的HTML也是簡單易懂的。
實際上消息本身是在<DIV>;上顯示的。在Internet Explorer中,我使用表格對象模型在單個的行中顯示每條消息。因此ChatMessagesTable是在<DIV>;上定義的。
最后,HandleSessionMessagesEx()JavaScript函數(shù)處理所有的表現(xiàn)方面。在Internet Explorer內(nèi),每條消息發(fā)出后ChatMessagesTable表就增加新行。如果需要也將顯示滾動條。在Netscape Navigator內(nèi),我給Messages變量附加新消息,并使用后者更新ChatMessages <DIV>;。既然滾動條不會自動在Netscape <DIV>;(是一個真正的LAYER)上顯示,那么我在頂部顯示最后一條接收到的消息。我已經(jīng)找到了在Navigator內(nèi)怎樣支持LAYER滾動條的文章,但是與這個范例無關(guān)。
最后的思考
這篇文章努力介紹瀏覽器方邏輯的一些(優(yōu)雅的)技術(shù)。像我早先在這篇文章中提到的,JSObject在許多程序中使用廣泛,包括微軟公司。同樣,你需要考慮你的個人環(huán)境來確定這里介紹的技術(shù)是否可用。
至于這篇文章所附的示例程序,我覺得允許JavaScript / DHTML實現(xiàn)聊天的介紹使這個代碼能夠通過入門水平/低級程序員維護(hù)。用戶界面的定制使用DHTML / JavaScript也很容易。加之,它允許看上去與余下的網(wǎng)頁內(nèi)容相一致,且更強大的表現(xiàn)技術(shù)。
在這個程序的產(chǎn)品版本中,我增加了在參與者機器上交換打開的超連接,使用層疊樣式單動態(tài)的選擇消息顏色等的支持。
歡迎任何信息反饋!
|
|