Java與JavaScript的通訊

來源:互聯網
上載者:User

1.  聊天示範程式內在的想法,連同這篇文章一起都是我自己的。我所見過的所有聊天程式不是完全基於JAVA就是HTML。我的方法是這兩種方法的一個很好的平衡。

2.  我通過在Netscape開發人員網站閱讀大量的文章後收集了在JAVA和JAVASCRIPT間通訊的技術資訊。

3.  我第一次在讀Danny Goodman的文章時(The JavaScript Apostle on the Netscape site)偶然遇到術語“不知名的applet(Faceless applet)”。因此出於對Danny的信任我使用了這個非常切題的術語。

放棄

1.  這篇文章中討論的技術已經在Windows 2000 Professional機器上使用Internet Explorer 5.0和 Netscape Navigator 4.7測試過了。在我所知道的最佳作品中,這些技術應該在任一瀏覽器4.0以上的版本上運行,但我不能保證我這樣做,因為我沒有時間用這些版本將它測試出來。

2.  因為JAVASCRIPT是唯一一種在兩種主要瀏覽器都得到支援的語言,所有的指令碼代碼使用這種語言。我先前在http://www.ncompasslabs.com上使用了一個可用的商業外掛程式,這個外掛程式可以讓Netscape Navigator支援VBScript,但我去他們的網站核實這個資訊的時候,這個產品已經沒有列出了。

引言

我一直從事現代COM的工作兩年了,現在是我公司的e化商業產品團隊的技術領導。我明白好的介面設計和在不同環境像Visual C++, Visual Basic 還有指令碼下都能很好執行程式的重要性。基於介面的程式設計的能力在我的頭腦中已經永遠確立,並且作為一個軟體工程師我試著將它應用到我所涉及的每件事情中。

在過去的一年裡,當ASP+指令碼就要被當作這些對象的黏合劑使用的時候,經驗告訴我們的勤奮:所有的商業邏輯應該被壓縮在COM對象之內。設計和開發典型的基礎設施和商業對象要求一個更高的技術裝置,它用來比較什麼是要求實際使用同一個事物的。開發這些對象的首選環境(至少在我的團隊中)是Visual C++ / ATL / STL。微軟也鼓勵Visual Basic成為這些對象可選擇的開發環境。

這些對象被代表性的稱為“不知名的”,因為他們實現許多邏輯但使用者介面除外。它的表現層次(presentation tier)不是一個充足的客戶就是一個不充足的客戶(這個客戶有從終端使用者表達資訊和聚集資訊的邏輯)。然後這樣的一個客戶用這些資訊通過使用不知名的對象做一些有意義的事情。這整個想法是當商業對象改變不頻繁時表現層次會代表性的要求許多客戶定製。表現層次要求的改變也可以通過使用較少的經驗程式來實現。

應用這些相同的原理到瀏覽器環境,當使用一種指令碼語言處理表現方面時,在“不知名的”二進位模組中壓縮高度發展的客戶方的邏輯看起來是合乎邏輯的。在Windows平台上這些模組的選項是Java applet和ActiveX 控制項/伺服器。這篇文章的焦點是使用Java applet完成這個目標,因為applet是獨立於瀏覽器,平台和處理器的(對大部分而言)。

Applet的簡短曆史

SUN Microsystems1995年在嘹亮的號角聲中引入了Java applet。Applet立即博得WEB世界的歡心,因為它們增加了在原來是一個靜態HTML的世界的瀏覽器中動態地顯示WEB內容的能力。

在最初的日子裡,使用Java applet作為最好的一種在網頁中增加動態內容的方式出現了。最初Microsoft 試圖使用他們的ActiveX Control技術反對SUN提供的Java applet,但是在網頁內部使用控制項存在兩個主要問題:

●     二進位模組是處理器指定的,因此不適合作為網頁的一部分運行。全球資訊網(World Wide Web)如此成功的一個主要原因是使用W3C標準HTML寫出的大部分網頁對瀏覽器和處理器是不可知的事實。ActiveX控制項正好不符合這個範例。

●     安全是一個大問題,因為控制項編寫者有足夠的權利在客戶機器上存取資源。簽了名的控制項允許任何一個人查看網頁並聰明地作出是否應該在他/她的機器上下載一個特定控制項的決定,但是所有他進行的是一個按鈕意外的點擊(或者是高興地忽略),這樣就留下了易受攻擊的客戶機,這也正符合惡意控制項編寫者的意圖。

當動態HTML終於開始成型時,事情徹底地改變了。文件物件模型(Document Object Model )作為可以設計的組件,它們用它們自己的屬性和方法揭露了網頁元素。即使Internet Explorer和Netscape Navigator瀏覽器執行動態HTML有許多不同,但使用指令碼代碼程式化的改變顯示頁內容本身的根本主題就是是一個巨大的成功。Applet突然開始看起來是又舊又粗糙的。W3C對動態HTML的認可最終對高度發展的,動態網頁的新種類調整了語氣。

在瀏覽器內是使用Java applet有以下列出的幾種優點:

●     Applet(對大多數Applet而言)可以在多瀏覽器,平台和處理器上工作。

●     JAVA語言是典型的一種強大的概念性語言。

●     JDK有許多典型的且只在高層類庫中建立的有用的類。

●     技術中已經構思了安全,applet只能用預設值在方框中運行。如果它們要打破方框的限制則Applet必須是已經簽了名的。

●     Applet可以就發回使用者化資訊,上傳/下載檔案等而與網頁伺服器取得聯絡。簽了名的applet可以與任何一個伺服器聯絡,而不僅僅是一個它們的主機。

●     通過“查看源檔案”選項不能看到applet代碼,因此保護了智慧財產權。

●     JAVA的.class檔案非常小,結果是下載非常快。

使用Java apple的缺點:

●     在一次瀏覽器對話中,下載applet不是網頁使用它們的第一時間顯示就是網頁隨後重新整理後顯示。Applet在瀏覽器對話中不長駐客戶機。事實上在大多數場合下這可以作為一種優勢考慮。

●     Applet要花很長時間初始化。

●     因為JAVA的.class檔案是被JAVA虛擬機器(Java virtual machine ,JVM)解釋的位元組代碼,所以applet運行比本地代碼慢。

●     一個applet只是瀏覽器上真正狀態的一部分,它不會無縫完好地出現在網頁內容中。層疊樣式單(Cascading style sheets ,CSS)也不會直接影響applet佔有的矩形地區。

●     Netscape Navigator 4.x有十個活動applet的限制。我不知道Internet Explorer 4.0+有任何一種這樣的限制。

使用Java applets的快速回顧

Java applets通過使用用applet標籤被包含進一個HTML網頁中。W3C 網站上HTML 4.01說明書的13.4節詳細地說明了這個標記。它也提到贊成<object>,而不贊成使用這個標記。

一個簡單地包含applet的HTML網頁如下所示:

<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執行個體的標識符。客戶方指令碼代碼能知道使用這個id的applet。

Width
這個屬性指定了applet顯示域的初始寬度(不包括applet建立的視窗或者對話方塊)。即使我經成功使用了寬度0用 “放棄”一節中提到的瀏覽器,還是推薦使用值1作為最小的可能寬度。

Height
這個屬性指定了applet顯示域的初始高度(不包括applet建立的視窗或者對話方塊)。就像用寬度屬性一樣,推薦使用值1作為最小的可能寬度。

Code
這個屬性指定了任一類檔案(包含applet編譯的applet子類或者能夠得到類的路徑,包括類檔案自身)的名字,它在談到applet的codebase時會作出解釋。

Codebase
這個屬性指定applet的基本URI. 如果這個屬性沒有指定,那麼它預設最近的文檔為同一個基本URI。

只有code, width和height 屬性是必須的。

Param標記包含一對名字的值,它允許applet第一次運行時安裝自己。

在上面的applet調用一個方法的JAVASCRIPT函數如下,它非常簡單:

<script language=Javascript>
function SetCalculatorMode(Mode)
{
   document.Calculator.SetCalculatorMode (Mode);
   // Alternative way to reference the applet.
   // document.applets[0].SetCalculatorMode(Mode);
}
</script>
勞動力的分工

在這篇文章的引言部分,我暗示當通過JavaScript代碼處理表現形式時,高度發展的瀏覽器方正處理的一個方法是被壓縮排不知名的Java applets中的。這個方法要求在Java和JavaScript間雙向通訊。下面幾章會研究可用的選項。

通過JAVASCRIPT代碼存取Java applet暴露的成員和函數是直截了當的,像上一節中的SetCalculatorMode()函數說明的一樣。文檔內的applet不是通過使用它的Id / Name就是使用applet收集的索引來查詢。

例如:

document.Calculator.SetCalculatorMode(Mode);// or document.applets[0].SetCalculatorMode(Mode);

使用netscape.javascript.JSObject類和netscape.javascript.JSException類完成了其它方向(Java to JavaScript)的通訊。為了找到這些類在什麼位置,我在我的硬碟上尋找所有包含字串“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產品安裝的,因為它們包含許多com.ms包。它們的用途是這兩個類對任一瀏覽器都是可用的,你可以設定你的CLASSPATH環境變數給任一個上述路徑。一個可選的方法是使用一個程式像WINZIP從.jar或者.zip檔案中解壓縮這些檔案到你的applet目錄下。

JSObject類

引用JSObject類成員函數的簡短描述是為了更好的理解這個類的用途。

public static JSObject getWindow (Applet applet )

這個靜態方法對含有給出的applet視窗返回一個JSObject。例如:JSObject MainWindow = JSObject.getWindow ( this );

public Object call ( String methodName, Object args[ ] )

這個函數從Java applet內部調用一個JavaScript方法。例如:

JSObject MainWindow = JSObject.getWindow ( this );
String Arguments[ ] = {"90", "2"};       // {"Percent complete", "Time remaining"}
MainWindow.call ( "UpdateProgressIndicator", Arguments );
public Object eval ( String s )

這個方法求一個JavaScript運算式的值。運算式是這個物件內容中待求的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 )
這個方法設定一個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 )
這個方法設定一個JAVASCRIPT對象的索引成員。它等價於JavaScript對象的this[index] = value。
public String toString ()

這個方法將JSObject轉換成一個字串。

上面的例子是很清楚的。JSObject類的公用方法試圖在JavaApplet中調用JavaScript函數時是不受限制的。他們也可以使一個applet直接處理文件物件模型元素。

這些類完整的文檔可以在http://developer.netscape.com/docs/manuals/communicator/jsref/pkg.htm上得到。

文檔也解釋了怎樣在Java和JavaScript間處理資料類型。

MAYSCRIPT屬性的意義

即使applet使用JSObject調用JavaScript函數,或者直接存取文件物件模型,如果applet標籤沒有包含在MAYSCRIPT屬性中的話JSObject的方法就會失敗。這一點能使網頁設計者測定一個applet是否能喚起JavaScript。

不知名的applet間的通訊

在網頁內使用不知名的,但可以再度使用的Java applet時,一個applet需要與另一個applet直接通訊是可能的。這樣的一個呼叫也可以通過一個媒介JavaScript函數通訊,但熟悉所有可用的選項總是比較好的。

java.applet包的AppletContext介面對applet的上下文實行一個訪問限制,像插入applet的瀏覽器,一個applet在網頁上還有其它的applet也在同樣一個網頁上。

例如,下面是一個HTML頁包含兩個applet:

html>
<head>
<title>Communication between applets</title>
</head>
<body>
<applet code="CircleArea.class" name="CircleArea" width=1 height=1>
</applet>
<applet code="PICalculator.class" name="PICalculator" width=1 height=1>
</applet>
...
</body>
</html>

下面的代碼錶明了AppletContext對象的用法:

AppletContext context = getAppletContext();
   PICalculator PIApplet = (PICalculator) context.getApplet ( "PICalculator" );
   PIApplet.getValueOfPI();

另一個選項是使用AppletContext::getApplets()方法,它返回了一個訪問文檔內所有applet的枚舉類型。即使applet間的通訊是標準Java applet API的一部分,它也不會在所有允許JAVA的瀏覽器中得到支援。其它applet的核心編碼也是堅定不移的。最好的方法可以是使用JAVASCRIPT函數來處理這種通訊。

JAVA的IUnknown::QueryInterface類對象是類層次的根。每個類有一個超類對象。所有對象,包括數組,實現這個類的方法。Object::getClass()方法返回有許多能探索JAVA類自身詳細資料的有用的函數的“類”。雖然在這篇文章的前面部分已經作過詳細的解釋,我還是想指出getInterfaces()方法使動態介面的發現通過一個JAVA類實現。

我沒有試過在JAVASCRIPT內調用getClass()方法,因此不能評論它的可行性。但是使用基礎類型的applet,這種功能性可以輕易地使它對指令碼代碼可用。

安裝樣本檔案

這篇文章的範例程式碼已經在Java2JavaScript.zip檔案中壓縮。樣本檔案示範了一個已經在客戶方自身簡單地發送訊息的一個聊天程式。使用者在不同的機器上加入這個聊天中,一條訊息發送給伺服器,然後廣播給所有的參與者。

組成樣本的檔案是:

ISession.java
定義ISession 介面的源檔案

ISession.class
Isession介面的Java位元組代碼

ChatClient.java
示範ChatClient applet的源檔案

ChatClient.class
ChatClient applet類的Java位元組代碼

CompileChatClient.bat
簡單的JAVA源檔案的批次檔

TestChatClient.htm
支援ChatClient applet HTML檔案

JSObject.class
JSObject類的位元組代碼

JSException.class
JSException類的位元組代碼

安裝和運行樣本程式的步驟是:

●     在運行有Personal Web Server或者Internet Information Server的機器上解壓縮Java2JavaScript.zip到你所選擇的目錄。

●     確保安裝目錄下的netscape\javascript 子目錄中的JSObject和JSException類檔案是可用的。

●     右擊安裝目錄選擇“屬性”。

●     點擊“網頁共用”標籤,選定“共用這個檔案夾”選項按鈕,在彈出的對話方塊中接受預設值“虛擬目錄”。

●     最後,啟動Internet Explorer 4.0+ 或者 Netscape Navigator 4.0+程式,然後輸入URL http:// <機器名>/<虛擬目錄>/TestChatClient.htm。

在輸入框中輸入一些文本,然後點擊相應的“SEND”按鈕,你就會看到訊息在聊天視窗中出現。

範例程式碼解釋

聊天程式是網頁上流行的合作機制。我見過的聊天程式有兩種類型:

●     一種是系統管理使用者介面和伺服器通訊的Java applet。

●     另一種是每隔幾秒就通過自動重新整理來顯示最後一次重新整理後的所有新訊息的HTML網頁。

最近我不得不為我們E化商業產品的聊天程式實現產品品質。經過許多考慮後,我決定使用一個混合的方法。首先最重要的,Java applet是執行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);
}
我已經把聊天程式產品版本中的這個介面作了輕微地修改,包括EndSession()和SendMessage()的Author參數。這是因為我的示範程式使用一個applet在兩個不同聊天者間傳遞聊天訊息。

ChatClient.java檔案是Isession介面的實際執行檔案。如果它們執行時瀏覽器就調用函數init(), start()和stop()。描述文件視窗的JSObject是在執行init()方法後得到的。

// Get the JavaScript window that will have the various scripts that this applet will call.
   m_JScriptWin = JSObject.getWindow(this);

因為Java applet調用兩個不同的JavaScript函數,我決定使WEB開發人員能像applet的參數一樣指定這些函數的名字,直到為同一個applet提供預設值。

m_strMessageHandler = getParameter("MessageHandler");
m_strErrorHandler = getParameter("ErrorHandler");
BeginSession()和EndSession()是只執行SendMessage()的虛擬執行函數。
SendMessage()呼叫在m_strMessageHandler成員變數中指定的JavaScript函數名字。預設值是“HandleSessionMessage”。相關代碼如下所示:
if (m_JScriptWin != null)
{
   String Arguments[] = {strAuthor, strType, strMessage};
   m_JScriptWin.call(m_strMessageHandler, Arguments);
}
HandleSessionError()調用一個在m_strErrorHandler成員變數中指定的JavaScript函數名字。預設值是“HandleSessionError”.
TestChatClient.htm檔案處理聊天的表現方面。applet使用<applet>標記包含在網頁中。
<applet id="ChatApplet" width="1" height="1" code="ChatClient.class" codebase="." VIEWASTEXT mayscript>
<param name="MessageHandler" value="HandleSessionMessageEx">
<param name="ErrorHandler" value="HandleSessionErrorEx">
</applet>
參數指定applet調用的兩個JavaScript函數的名字。我只表明名字除預設值外說明了這個方法是多麼靈活,網頁中的兩個表單類比兩個人正與對方聊天。相關的HTML也是簡單易懂的。
實際上訊息本身是在<DIV>上顯示的。在Internet Explorer中,我使用表格物件模型在單個的行中顯示每條訊息。因此ChatMessagesTable是在<DIV>上定義的。
最後,HandleSessionMessagesEx()JavaScript函數處理所有的表現方面。在Internet Explorer內,每條訊息發出後ChatMessagesTable表就增加新行。如果需要也將顯示捲軸。在Netscape Navigator內,我給Messages變數附加新訊息,並使用後者更新ChatMessages <DIV>。既然捲軸不會自動在Netscape <DIV>(是一個真正的LAYER)上顯示,那麼我在頂部顯示最後一條接收到的訊息。我已經找到了在Navigator內怎樣支援LAYER捲軸的文章,但是與這個範例無關。
最後的思考
這篇文章努力介紹瀏覽器方邏輯的一些(優雅的)技術。像我早先在這篇文章中提到的,JSObject在許多程式中使用廣泛,包括微軟公司。同樣,你需要考慮你的個人環境來確定這裡介紹的技術是否可用。
至於這篇文章所附的樣本程式,我覺得允許JavaScript / DHTML實現聊天的介紹使這個代碼能夠通過入門水平/低級程式員維護。使用者介面的定製使用DHTML / JavaScript也很容易。加之,它允許看上去與餘下的網頁內容相一致,且更強大的表現技術。
在這個程式的產品版本中,我增加了在參與者機器上交換開啟的超串連,使用層疊樣式單動態選擇訊息顏色等的支援。
歡迎任何資訊反饋

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.