程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 理解作用域和受管Bean

理解作用域和受管Bean

編輯:關於JAVA

您在本教程中所創建的 Web 應用程序采用 application 范圍內的一個對象來統計投票數,采用 session 范圍內的一個對象來確保用戶在每個會話中只能投票一次。該應用程序采用一個 request 范圍內的對象來顯示用戶提交投票的時間。該時間存儲在 request 范圍,因為應用程序在響應被發送到客戶端浏覽器以後不再需要這個值。

本教程需要采用以下技術及資源

JavaServer Faces 組件/

Java EE 平台

1.2 和 Java EE 5*

1.1 和 J2EE 1.4

Travel 數據庫 非必須

* 為了利用 NetBeans IDE 6.0 的 Java EE 5 能力,請采用一個完全符合 Java EE 5 規范的應用程序服務器,如 Sun Java Application Server 9/GlassFish 。

此教程已針對 GlassFish v2 應用程序服務器上的應用做出調整。如果您使用的是不同的服務器,請參閱發行說明及常見問題解答以了解已知問題和變通方法。要了解受支持的服務器和 Java EE 平台的信息,請參閱發行說明。

關於作用域

當用戶停留在一個頁面上的時候,即使頁面重新顯示,例如用戶點擊一個返回空值的按鈕時,組件的值仍然被存儲。然而,用戶離開這個頁面時,組件的值隨即消失。

要讓值對其他頁面有效,或者對用戶應當返回的相同頁面有效,你需要存儲值。當你從 IDE 裡創建一個項目時, IDE 將創建三個 受管 Bean 用來存儲值:

RequestBean1

SessionBean1

ApplicationBean1

下圖所示的是一個列出了受管 Bean 的“導航”窗口。

圖表 1:默認的受管 Bean

一個受管 Bean 就是一個 JavaBean 對象,該對象被 JavaServer Faces web 應用程序所呈現並存儲於request、session 或者 application 范圍內。Web 應用程序將 RequestBean1 存儲於 request 范圍內,將 SessionBean1 存儲於 session 范圍內,並將 ApplicationBean1 存儲於 application 范圍內。

要向這些受管 Bean 添加屬性,您可以右擊“導航”窗體中的一個 bean 並在源代碼中鍵入屬性聲明。右擊 Java 編輯器中的任意處,然後選擇“重構” > “封裝字段”。然後從列表中選擇屬性並勾選要添加的方法,點擊“構造”。

在創建一個 bean 屬性來存儲值之前,您必須決定屬性值的適用作用域。因為許多用戶可能在同一時間訪問 web 應用程序,您需要使用盡可能最小的作用域以便對服務器資源進行最好的利用。下圖展示了每種作用域的持續期。

Application 作用域將持續到服務器停止該應用程序為止。您存儲在 application bean 中的值對於使用同一應用程序映射的每個會話和每個請求都是有效的。

Session 作用域在用戶第一次訪問 web 應用程序中的某一頁面時開始,當用戶的會話由於長時間處於非活動狀態而超時,或者當 web 應用程序令會話無效時,例如通過調用 session.invalidate(),會話終止。

Request 作用域在用戶提交頁面時開始,當響應徹底完成時終止,不論返回的頁面是什麼。

圖表 2: Web 應用程序的作用域

例如, 您的 web 應用程序有一個用於選擇測量類型的下拉列表(像素、厘米和英寸)。您可能要將選項列表存儲於 ApplicationBean1 中,以便當前所有的用戶會話可以共享這個列表。另一方面,您可能將用戶登陸名存儲於 SessionBean1 中,以使該用戶名對該用戶在此會話中所訪問的任何頁面都有效。如果對於當前請求您不需要其生命周期以外的信息,您可以通過將屬性置於 RequestBean1 中來節約空間開銷。

警告: 如果您已在一個導航規則的 <navigation-case> 元素中包含 <redirect> 元素,您將不能使用 request bean 。(您可以在頁面流編輯器中點擊 XML 按鈕來查看這些規則。)當頁面被提交時, <redirect> 元素將重定向頁面並在後面的頁面能夠使用任何存儲於 Request Bean 中的值之前結束請求。

當您從 IDE 中創建一個頁面時,頁面 bean 的 Java 源代碼中就包含了訪問 RequestBean1 、 SessionBean1 和 ApplicationBean1 對象的方法。要訪問這些屬性的受管 bean ,您可以使用和下面的代碼片段相似的代碼。

代碼示例 1 :訪問一個 Application Bean 屬性

ApplicationBean1 appBean = getApplicationBean1();
Option[] choices = appBean.BallotOptions();

當一個頁面在某個受管 bean 的作用域內第一次訪問其屬性時, web 應用將該受管 Bean 實例化。例如,一個 SessionBean1 對象實例直到用戶訪問一個引用了 SessionBean1 中某個屬性的頁面才存在於用戶會話中。一個 ApplicationBean1 的對象實例將在頁面首次通過任意會話訪問 application bean 時被創建,並將伴隨應用程序的運行而存在。

技巧: 添加額外的受管 Bean :

在“項目”窗口中,展開“源包”節點,右擊包節點。

選擇“新建” > “其它”,選擇 JavaServer Faces 類別並選擇“文件類型”下的作用域,然後單擊“下一步”。

鍵入新建受管 Bean 的文件名並點擊“完成”。

新建的受管 Bean 出現在“項目”窗口中的“源包”節點下。

向受管 Bean 添加屬性

該 web 應用中的頁面需要訪問以下值,在本節中您將創建它們:

ballotOptions.一個包含投票選項列表的數組屬性。因為該列表對任何會話來說都是相同的,所以該屬性屬於 application 作用域。

tally. 一個 hash map 屬性,用於記錄來自各個會話的投票。由於該屬性必須在幾個會話之間都存在,所以它也屬於 application 作用域。

hasVoted.一個布爾型屬性,用於跟蹤用戶是否已經投票。由於應用程序需要在一個會話中的幾個請求內保存這個值,所以將這個值存在該應用的 session 作用域。

timestamp. 一個 Date 類型的屬性,應用程序將用戶提交投票的時間記錄在其中,以便下一個頁面可以調用。由於應用程序在下一個頁面傳輸給浏覽器後不再需要這個值,所以該屬性存在於 request 作用域內。

完成以下步驟,向受管 Bean 添加屬性。

從主菜單選擇“文件” > “新建項目”。

在“新建項目”向導中,從“類別”列表中選擇 Web 並從“項目”列表中選擇 Web Application ,之後點擊“下一步”。

將項目命名為 Scopes 並點擊“下一步”。

在“框架”面板中,勾選 Visual Web JavaServer Faces 並點擊“完成”。

Scopes 項目的 Page1.jsp 在“可視化設計器”中被打開。

在“導航”窗口中,雙擊 ApplicationBean1 。

該操作將打開 ApplicationBean1.java 以便進行編輯。

接下來您可以添加 Application bean 屬性。在構造函數 public class ApplicationBean1 extends AbstractApplicationBean下面,添加如下聲明:private Option[] ballotOptions;
private HashMap tally;

在 Java 編輯器中右擊並選擇“修復導入”。由於不止一個包內含有 Option 類,所以 IDE 將彈出“修復導入”對話框。

對 Java EE 5 項目,選擇 com.sun.webui.jsf.model.Option。

對 J2EE 1.4 項目,選擇 com.sun.rave.web.ui.model.Option。

在 Java 編輯器中右擊並選擇“重構” > “封裝字段”。

在“封裝字段”對話框中,勾選 ballotOptions 和 tally 屬性的 getter 和 setter 方框,以創建相應的 getter 和 setter 方法,如下圖所示。

圖表 3: “封裝字段”對話框

滾動到 init 方法並將下面以粗體顯示的代碼添加到該方法的尾部。

代碼示例 2: 向 init 方法中添加的代碼

// TODO - add your own initialization code here
     // populate ballot items
     ballotOptions = new Option[] {
       new Option("java", "Java Programming Language"),
       new Option("cpp", "C++"),
       new Option("fortran", "Fortran")
     };

     // initialize counters for ballot choices
     tally = new HashMap();
     for (int i=0; i < ballotOptions.length; i++) {
       this.tally.put(ballotOptions[i].getValue(), "0");
     }

在文件的最後一個結尾括號前添加以下方法。

代碼示例 3: Application Bean 中的投票計數方法

/**
   * Vote counter for property tally.
   */
   public void incrementTallyFor(String category) {
     int count = getTallyFor(category);
     count++;
     this.tally.put(category, Integer.toString(count));
   }

   /**
   * Getter for value in property tally.
   * @param category HashMap key
   * @return Value to which the specified key is mapped
   */
   public int getTallyFor(String category) {
     String stringCount = (String) this.tally.get(category);
     if (stringCount == null) {
       return 0;
     } else {
       int count = Integer.valueOf(stringCount).intValue();
       return count;
     }
   }

按 Ctrl+S 以保存您做出的更改,並按 Ctrl+F4 以關閉該文件。

在“導航”窗口中,雙擊 SessionBean1 。 該操作將打開 SessionBean1.java 以便進行編輯。

注意:如果“導航”窗口沒有打開,點擊編輯區的 Page1 標簽,並單擊編輯工具欄中的“設計”。“導航”窗口將在 IDE 處於設計模式時出現。

接下來您可以添加 Session bean 屬性。在構造函數 public class SessionBean1 extends AbstractSessionBean 下添加如下聲明:private boolean hasVoted;

在 Java 編輯器中右擊並選擇“重構” > “封裝字段”。

在“封裝字段”對話框中,勾選 hasVoted 屬性中的 getter 和 setter 方框以創建相應的 getter 和 setter 屬性,並點擊“重構”。

滾動至 init 方法並將以下粗體顯示的代碼添加到該方法尾部。

代碼示例 4: 要向 Session Bean 的 init 方法中添加的代碼

// TODO - add your own initialization code here
     setHasVoted(false);

按 Ctrl+S 以保存您做出的更改,並按 Ctrl+F4 以關閉該文件。

在“導航”窗口中,雙擊 RequestBean1 。 該操作將打開 RequestBean1.java 以便進行編輯。

添加 Request bean 屬性。在構造函數 public class RequestBean1 extends AbstractRequestBean下添加如下聲明:private java.util.Date timestamp;

在 Java 編輯器中右擊並選擇“重構” > “封裝字段”。

在“封裝字段”對話框中,勾選 timestamp 屬性中的 getter 和 setter 方框以創建相應的 getter 和 setter 屬性,並點擊“重構”。

點擊 Page1 標簽然後點擊 Page1 的 Design 按鈕。檢查“導航”窗口以確保 request bean 、 session bean 、 以及 application bean 中的屬性與下圖所示相一致。

圖表 4: Request Bean 、 Session Bean 、 以及 Application Bean 的屬性

創建起始頁

按本節中的以下步驟創建一個如下圖所示的在浏覽器中運行的頁面。如果用戶點擊 Submit Vote 按鈕,則頁面提交用戶的投票。一旦用戶已經投票,按鈕就變為禁用以防止用戶在同一會話內再次投票。

圖表 5: Page1

在編輯工具欄中點擊 Page1

從“面板”的“基本組件”中拖一個“標簽”到頁面頂部正中,並將標簽的文本設置為 Reader's Poll: What Is Your Favorite Programming Language?

在該“標簽”組件下面放一個“單選按鈕組”組件。

在“屬性”窗口中,將該組件的 id 設置為 voteRBGroup。

右擊“單選按鈕組”組件並從彈出菜單中選擇“綁定到數據”。

此時將出現一個“綁定到數據”對話框。

在該對話框中的“綁定到對象”標簽中,選擇 ApplicationBean1 > ballotOptions 並點擊“確定”。

在“單選按鈕組”組件下方放置一個“按鈕”,並將其文本設置為 View Results 。

特別注意: 在 IE7 中存在一個已知的問題,可以影響到 JSF 1.2 按鈕組件的寬度。工作區中應當將按鈕組件放置在一個布局組件(網格面板、組面板或者布局面板)中。調整布局組件的大小將自動調整按鈕組件的大小。

在屬性窗口中,將 id 設為 viewButton 。

點擊 action 屬性的省略號按鈕 ,從下拉列表中選擇 viewButton_action 並點擊確定。

IDE 將添加 viewButton_action 事件處理器,其返回值為 null 。

在 View Results 按鈕的右邊放置一個“按鈕”組件,並將其文本設置為 Submit Vote 。

在屬性窗口中,將 id 設為 voteButton 。

點擊 disabled 屬性的省略號按鈕

該操作將打開該屬性的屬性綁定對話框。

在該對話框中,選擇“使用綁定”,點擊“綁定到對象”,並選擇 SessionBean1 > hasVoted ,如下圖所示,然後點擊“確定”。

圖表 6: 綁定 disabled 屬性

雙擊 Submit Vote 按鈕。

IDE 將添加 voteButton_action 事件處理器,而後打開該頁面的 Java 源代碼並顯示相應的方法。

用下面粗體顯示的代碼替換方法體。

代碼示例 5: voteButton_action 方法

public String voteButton_action() {

     if (voteRBGroup.getSelected() == null) {
       return null;
     }

     // Tallies are kept across all user sessions
     String votedFor = voteRBGroup.getSelected().toString();
     getApplicationBean1().incrementTallyFor(votedFor);

     // User can only vote one time per session
     getSessionBean1().setHasVoted(true);

     // Don't need the timestamp after the next request ends
     Date now = new Date();
     getRequestBean1().setTimestamp(now);

     return null;
   }

在源代碼中右擊並從彈出菜單中選擇“修復導入”。

從下拉列表中選擇 java.util.Date 並點擊“確定”。

創建結果頁

按以下步驟創建一個如下圖所示的在浏覽器中運行的頁面。該頁面顯示當前的投票計數。用戶可以通過點擊 Refresh Results 按鈕來獲得最新的投票計數,這其中包含自該頁面最後一次顯示以來所有其它用戶提交的投票。

圖表 7: Results

在“項目”窗口中,右擊您的 Scopes 項目下的 Web 頁節點,選擇“新建” > “Visual Web JSF 頁”,將該頁面命名為 Results ,並點擊“完成”來創建頁面。

在 Results 頁面的頂部中間放置一個“標簽”組件,並將其文本設為 Results 。

在該“標簽”組件的左邊放一個“按鈕”組件並將其文本設置為 Home 。

將該“按鈕”組件的 id 設置為 homeButton 。

點擊 action 屬性後的省略號按鈕 ,從“處理程序”下拉列表中選擇 homeButton_action 並單擊“確定”。

在該“標簽”組件的右邊放一個“按鈕”組件,並將其文本設置為 Refresh Results 。

將該“按鈕”組件的 id 設置為 refreshButton 。

點擊 action 屬性後的省略號按鈕 ,從“處理程序”下拉列表中選擇 refreshButton_action 並點擊“確定”。

從“組件面板”的“布局”區域內拖一個“網格面板”組件到上述“標簽”組件的下方。

在“屬性”窗口,將 cellspacing 屬性設置為 10 並將 columns 屬性設置為 1 。

拖一個“靜態文本”組件到上述“網格面板”組件內。當“網格面板”組件的邊框變為藍色實線時,放開“靜態文本”組件,如下圖所示。

圖表 8: 向“網格面板”組件中拖放一個組件

在“屬性”窗口中,將“靜態文本”組件的 id 設置為 resultsST 。 將其 text 屬性留空即可。

反選 escape 屬性的方框。

然後,您可以向該組件的 text 屬性內添加 HTML 代碼。將 escape 屬性設為 false 後,HTML 代碼將原樣輸出到浏覽器。

再拖一個“靜態文本”組件到上述“網格面板”組件內。並當“網格面板”組件的邊框變為藍色實線時,放開“靜態文本”組件。

將該“靜態文本”組件的 id 設置為 messageST 。將其 text 留空。

點擊編輯工具欄上的 “Java” 並查看該頁面的 Java 源代碼。

在“導航”窗口中,雙擊 prerender 方法將其在 Java 編輯器中打開,然後添加下面粗體所示的代碼。

代碼示例 6: prerender 方法

public void prerender() {
    // Display latest poll results
    ApplicationBean1 appBean = getApplicationBean1();
    Option[] choices = appBean.getBallotOptions();
    String str = "<table border="0" cellpadding="5">";
    for (int i = 0; i < choices.length; i++) {
     int count =
      appBean.getTallyFor(choices[i].getValue().toString());
     str = str + "<tr><td>" +
      choices[i].getLabel() +
      "</td><td>" +
      count +
      "</td></tr>";
    }
    str = str + "</table>";
    resultsST.setText(str);

    RequestBean1 reqBean = getRequestBean1();
    Date timestamp = (Date) reqBean.getTimestamp();
    if (timestamp != null) {
     messageST.setText("Your vote was recorded at " +
      (String)DateFormat.getTimeInstance(DateFormat.LONG).format(
      timestamp));
    }
   }

這段代碼將創建一個包含所有投票總數的 HTML 表格,並將這個 HTML 表格放在第一個“靜態文本”組件的 text 屬性中。如果用戶剛投過票,第二個“靜態文本”組件將顯示投票被注冊的日期和時間。

在源代碼中右擊並從彈出菜單中選擇“修復導入”。

從 Date 下拉列表中,選擇 java.util.Date 。

根據當前項目所使用的 Java EE 版本,在 Option 下拉列表中進行以下操作:

對於 Java EE 5 項目,選擇 com.sun.webui.jsf.model.Option 。

對於 J2EE 1.4 項目,選擇 com.sun.rave.web.ui.model.Option 。

定義頁面導航

按以下步驟為按鈕定義頁面導航,如下圖所示。

圖表 9 : “頁面流”編輯器

在編輯區,點擊 Results 標簽並點擊 Design 以便在可視化編輯器中查看該頁面。

在該頁面的空白處右擊並從彈出菜單中選擇“頁面導航”。

faces-config.xml 就顯示在“頁面流”編輯器中。

點擊 Page1.jsp 圖標中的加號來展開該圖標。

在 viewButton 處單擊並拖動到 Results.jsp ,將在該按鈕和 Results 頁面之間創建一個連接器。

雙擊連接器的標簽使其進入編輯模式,鍵入 view results 然後按回車。

在 voteButton 處單擊並拖動到 Results.jsp 。

雙擊連接器的標簽使其進入編輯模式,鍵入 vote 然後按回車。

點擊 Results.jsp 圖標中的加號使之展開。

在 homeButton 處單擊並拖動到 Page1.jsp。

雙擊連接器的標簽使其進入編輯模式,鍵入 home 然後按回車。

運行應用程序

要從一個浏覽器啟用多個會話,需要將應用程序設置改為在每個會話處於非活動狀態1分鐘後將其結束。然後部署並運行該應用程序。

在“文件”窗口內,展開 Scopes > web >WEB-INF ,如下圖所示。

圖表 10: “文件”窗口

雙擊 web.xml 可在編輯器中打開該文件。

在“會話超時”文本框中鍵入 1 ,如下圖所示。

圖表 11:在 web.xml 可視化編輯器中設置會話超時

保存並關閉該文件。

點擊主工具欄中的“運行主項目”按鈕

當起始頁出現的時候,選擇一個單選按鈕並點擊 Submit Vote 。

浏覽器顯示出結果頁。注意結果頁已經顯示了您提交投票的時間。

單擊 Home 即返回到起始頁。

由於您已經投過票, Submit Vote 是禁用的。

點擊 View Results 。

注意結果頁不再顯示您投票的時間。這是因為上一個請求 bean 已經超出作用域而一個新的請求 bean 已經被示例化。

等待1分鐘使會話超時。然後在浏覽器的地址欄輸入以下 URL 並按下回車來啟動一個新會話:http://localhost:8080/Scopes 。 如果沒有使用默認的服務器配置,您可能需要將 8080 改為其它端口。

再次投票並查看結果。結果中應當包含您的第一次投票。

如果您還有其他浏覽器程序,啟動那個浏覽器,在其地址欄鍵入 http://localhost:8080/Scopes 並按下回車以完成另一次投票。

在第一個浏覽器中,點擊結果頁中的 Refresh Results 。

結果中應當包含您從第二個浏覽器中提交的投票。

實現更多

運用您在本教程中所學到的來創建一個能夠提示登錄名的應用程序。添加一個頁面來顯示所有訪問該 web 應用的用戶總數。

小結

您可以使用 application bean、 session bean 以及 request bean 來存儲其它頁面需要使用的信息。

使用 application bean 來存儲應用於所有用戶會話的信息,例如一個用於下拉列表組件的靜態的選項列表。

使用 session bean 來存儲可被整個用戶會話的其它頁面所調用的信息,例如用戶的登錄名。

如果您只需要下一個頁面所需的信息,請使用 request bean 。

注意: 如果您在一個導航規則的 <navigation-case> 元素中包含了 <redirect> 元素,您不能使用 request bean 。

對於 request bean、 session bean 或者 application bean 而言,當一個頁面訪問它們的一個屬性的時候,它們就被實例化了。

要向 Session Bean 中添加一個屬性,右擊“大綱”窗口中的 Session Bean 節點並選擇“添加” > “屬性”。采用相同的步驟可以向 Request Bean 或 Application Bean 中添加屬性。

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