程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 實現applet跨框架和浏覽器窗口彼此通信

實現applet跨框架和浏覽器窗口彼此通信

編輯:關於JAVA

摘要

您可能認為能讓 applet 彼此通信的唯一選擇就是使用 getApplet。不幸的是,getApplet 方法僅返回與發出調用的 applet 在同一個 HTML 頁面上的 applet,這樣就限制了您通過 applet 間的通信構建有趣界面的方式。這篇技巧說明的替代方法能使處於不同框架甚至不同浏覽器窗口中的 applet 彼此調用對方的方法。

java.applet 包中的 AppletContext 類包含兩個成員方法,即 getApplet 和 getApplets。通過使用這兩個方法,一個 applet 就可以找到其他 applet 並調用它們的方法。要這樣做必須滿足下面的安全要求:

這些 applet 來自同一個服務器上的同一個目錄中。

這些 applet 運行於同一個浏覽器窗口中的同一個頁面上。

這樣設計安全限制可能有很好的原因;但是,後一個要求限制了利用 applet 間的通信制作有趣的多 applet 界面的方式。

試考慮這樣一種情況:

您剛編好一個很好的股票市場交易 applet,並決定為它編寫一個良好的幫助系統。您希望幫助系統也是一個 applet,並希望將它與股票市場交易 applet 在不同的浏覽器框架中運行。您作出這個決定可能是出於網站結構方面的考慮,也可能是出於始終顯示幫助系統的需要。另外,您希望使幫助系統根據用戶當前在股票交易 applet 中進行的操作轉至正確的信息/指導(就像 Microsoft Office 套件中的“回形針”一樣)。您甚至計劃在幫助系統中編制向導,這些向導可遠程指出問題,並可遠程執行股票市場交易 applet 中的任務。

這一方案中體現的思想很不錯。但是,因為這兩個 applet 處於不同的頁面上,所以 AppletContext 中的 Java API 無法幫助您實現這個想法 -- 但這篇技巧可以幫助您。

使用 AppletContext API

在說明 applet 間通信的替代機制前,我將首先簡要說明一下 getApplet 和 getApplets 這兩個方法是如何工作的。一個 applet 通過使用 getApplet 方法可以按名稱找到同一個 HMTL 頁面中的另一個 applet,而通過使用 getApplets 方法可以找到同一個頁面上的所有 applet。這兩個方法如果成功執行,則會向調用者返回一個或多個 Applet 對象。調用者一旦找到一個 Applet 對象,它就可能調用這個 Applet 的公用方法。

假定有下面這樣一段 HTML 代碼:

<applet code="Applet1" width="400" height="100" name="app1">
  </applet>
  <br>
  <applet code="Applet2" width="400" height="100" name="app2">
  </applet>
  <br>

通過使用 applet 標記中的 name 屬性,您就可以用下面的方式引用一個特定的 applet:

Applet theOtherApplet = getApplet("app1");

theOtherApplet.anyMethod(); //調用任一個公用方法

或者,您也可以用以下的代碼來檢索這個頁面上的所有 applet:

  Enumeration allAppletsOnSamePage = getApplets();
  while(allAppletsOnSamePage.hasMoreElements()) {
    Applet appl = (Applet) allAppletsOnSamePage.nextElement();
    appl.anyMethod(); //調用任一個公用方法
  }

當發出調用的 applet 在它所在的同一個 HTML 頁面上檢索到一個或幾個 applet 之後,它就可以調用這些 applet 的公用方法。

使用靜態數據結構

不幸的是,如果使用標准方法,則只能與同一個 HTML 頁面中的 applet 通信。幸運的是,您很容易就可以避開這個限制。使 applet 間跨頁面通信的方法基於這樣一個事實,即如果兩個 applet 的 codebase 相同,則即使它們是在不同的浏覽器窗口中被加載的,它們也共享同一個運行時環境。粗略地說,codebase 就是從中加載 applet 的那個目錄。請參閱文後的java//jw-tips/tip101/index.shtml#resources">參考資源,其中有一個鏈接指向有關 codebase 的一篇教程。

由於運行時環境是共享的,因此所有 applet 實例都可以訪問靜態域和靜態結構,這樣這些靜態域和結構就可用來在不同 applet 之間傳遞信息。

applet 不僅可以存儲諸如整數、字符和字符串這樣的簡單數據類型,而且每個 applet 都可以將其自身(實例)的一個引用存儲在一個靜態域(可能在它自己的類中)中。任何 applet 都可以訪問這個域,從而獲得指向這個實例的引用。

這聽起來復雜嗎?不,一點也不復雜。我首先舉一個簡單的例子。假定您的一個 applet (AppletA.class) 在一個框架中,而另一個 applet (AppletB.class) 在另一個框架中,而且這兩個 applet 都是從同一個 codebase 加載的。

您現在希望授予 AppletA 訪問 AppletB 的公用方法的權限。您必須讓 AppletB 將其自身的一個引用存儲在一個靜態公用域中,就像下面這樣:

  public class AppletB {
    public static AppletB selfRef = null; // 初始歸零
    public void init() {
      // 生成對該實例的引用
      selfRef = this;
    }
    ...
  }

現在您就可以從 AppletA 訪問 AppletB 的實例了:

  public class AppletA {
    AppletB theOtherApplet = null;
    public void callAppletB() {
      // 獲取靜態域,其中存儲著指向 AppletB 的
      // 實例的指針。
      theOtherApplet = AppletB.selfRef;
      // 此後就可以調用實例方法了,
      // 如下所示...
      theOtherApplet.repaint();
    }
    ...
  }

這就是我們所要做的全部工作。因為運行時環境是由不同的 applet 共享的,所以即便 applet 不在同一個頁面上,這個方法同樣奏效。

值得注意的一點是,上面的代碼並沒有處理在啟動 AppletB 之前就調用 AppletA 中的 callAppletB 方法的情況。如果發生這種情況,則 selfRef 將是 null,這樣不能進行任何通信。

一種更通用的方法

當然,還有一種更通用的方法。您可以創建這樣一個類,創建它的唯一目的就是在靜態數據結構中存儲 applet 的引用。稍後您將看到的 AppletList 類就屬於這種情況。希望其他 applet 訪問自己的公用方法的 applet 實例通過 AppletList 將自己注冊。按照 AppletContext.getApplet(string name) 中的模式,每個注冊項都與一個字符串相關聯。當一個 applet 調用某個 applet 的引用時,這個字符串就起關鍵字的作用。

通常,applet 是按下面的方式注冊的:

  public class AppletA {
    public void start() {
      AppletList.register("Stock-trade-applet", this);
      ...
    }
  }

另一個 applet 獲取對它的訪問權:

  public class AppletB {
    public void run() {
      AppletA tradeApplet =
        (AppletA) AppletList.getApplet("Stock-trade-applet");
      ...
    }
  }

當該 applet 停止運行時,您必須緊記在 AppletList 中撤銷注冊:

  public void stop() {
    AppletList.remove("Stock-trade-applet");
    ...
  }

AppletList 類的完整源代碼如下所示:

0: import java.util.*;
1: import java.applet.Applet;
2:
3: public class AppletList {
4: private static Hashtable applets = new Hashtable();
5:
6: public static void register(String name, Applet applet) {
7: applets.put(name,applet);
8: }
9:
10: public static void remove(String name) {
11: applets.remove(name);
12: }
13:
14: public static Applet getApplet(String name) {
15: return (Applet) applets.get(name);
16: }
17:
18: public static Enumeration getApplets() {
19: return applets.elements();
20: }
21:
22: public static int size() {
23: return applets.size();
24: }
25: }

要獲得說明如何使用這個類的示例,請在java//jw-tips/tip101/index.shtml#resources">參考資源中下載 exampleCode.zip。

局限性

正如我在前面提到的那樣,必須從同一個 codebase 中加載這些 applet。此外,如果浏覽器的兩個不同副本正在運行,並且 applet 被加載到每個副本中,則 applet 可能無法彼此通信(取決於浏覽器的版本和設置),因為它們可能不再共享同一個運行時環境。但是,如果是浏覽器本身衍生出新的浏覽器窗口,則沒有任何問題。

該技巧已在幾個平台和幾個浏覽器版本中通過測試,但在某些配置中每個 applet 的運行時環境可能是獨立的。該技巧已在下面的操作系統和浏覽器組合中通過測試:

Windows 2000: Internet Explorer 5.0,Internet Explorer 5.5,Netscape Navigator 4.72,Opera 4.01 Windows 98: Internet Explorer 4.72,Internet Explorer 5.0,Netscape Navigator 4.02 Mac OS 9: Internet Explorer 4.5,Netscape Navigator 4.5 Red Hat 6.2: Netscape Navigator 4.73

小結

這篇技巧說明了能使 applet 彼此通信的一種替代方法。這種方法以 Java API 的 getApplet() 方法不支持的方式工作。這篇技巧中介紹的知識增大了將 applet 作為網站或內部網的一部分的可能性 -- 可以用它替代或補充 getApplets 方法。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved