了解作用域和受管 Bean
在本教程中,您将结合使用 NetBeans IDE 和 Visual Web JSF 应用程序开发功能来创建一个应用程序,以说明如何使用应用程序、会话和请求作用域对应用程序的对象进行管理。作用域指的是对象的可用性(或上下文)及其在 Web 应用程序中的预定生命周期。
您在本教程中创建的 Web 应用程序将使用一个应用程序作用域对象来统计投票,使用一个会话作用域对象来确保每个用户在每个会话期间只能投票一次。该应用程序还使用请求作用域对象来显示用户提交投票的时间。此提交时间存储在请求作用域中,因为在将响应发送到客户端浏览器之后,应用程序就不再需要该值。
预计时间:45 分钟
目录

要学习本教程,您需要具备以下软件和资源。
* 要利用 NetBeans IDE 的 Java EE 5 功能,请使用完全符合 Java EE 5 规范的应用服务器,例如 GlassFish V2 UR2 应用服务器。如果使用的是其他服务器,请查阅发行说明和常见问题解答,了解已知问题和解决方法。有关支持的服务器和 Java EE 平台的详细信息,请参见发行说明。
关于作用域
只要用户停留在某个页面上,系统就会记住其组件值,即使重新显示该页面(例如,当用户单击某个按钮后返回 null 时)也是如此。但是,当用户离开该页面后,其组件值就会消失。
要使其他页面可以访问这些值,或者当用户返回同一页面时可以访问这些值,则需要对它们进行存储。在 IDE 中创建项目时,IDE 会创建三种用于存储这些值的受管 Bean:
RequestBean1
SessionBean1
ApplicationBean1
下图显示了包含缺省受管 Bean 的“导航”窗口。

受管 Bean 是 JavaBeans 对象,JavaServer Faces Web 应用程序对该对象进行实例化并将其存储在请求作用域、会话作用域或应用程序作用域中。Web 应用程序将 RequestBean1 存储在请求作用域中,将 SessionBean1 存储在会话作用域中,并将 ApplicationBean1 存储在应用程序作用域中。
要向其中某个受管 Bean 中添加属性,请在“导航”窗口中双击该 Bean,然后在源代码中键入属性声明。在 Java 编辑器中的任意位置单击鼠标右键,然后选择“重构”>“封装字段”。然后从列表中选择该属性,选择要添加的方法,再单击“重构”。
在创建 Bean 属性来存储值之前,必须为该属性的值确定相应的作用域。由于多个用户可以同时访问一个 Web 应用程序,因此,您需要尽可能使用最小的作用域以充分利用服务器资源。下图显示了每种类型作用域的持续时间。
- 应用程序作用域将一直持续到服务器停止该应用程序为止。使用相同应用程序映射的每个会话以及每个请求都可以访问存储在应用程序 Bean 中的值。
- 会话作用域从用户第一次访问 Web 应用程序中的页面开始,直至由于不活动导致用户会话超时而结束,或者直至 Web 应用程序使会话失效(例如,通过调用
session.invalidate())而结束。
- 请求作用域从用户提交页面开始,直至完全呈现响应(不论是哪个页面)而结束。

例如,您所创建的 Web 应用程序包含一个度量单位类型(像素、厘米和英寸)的下拉列表。您可能需要在 ApplicationBean1 中存储选项列表,以便让所有并行的用户会话都可以共享该列表。另一方面,您可能还需要在 SessionBean1 中存储用户的登录名,以使该登录名可用于用户在此会话中访问的所有页面。如果您不需要有关当前请求的生命周期之外的信息,则可以通过将此属性放在 RequestBean1 中来节省空间。
警告:如果将 <redirect> 元素包含在导航规则的 <navigation-case> 元素中,则不能使用请求 Bean。(在页面导航编辑器中单击 "XML" 按钮时,可以看到这些规则)。在提交页面时,<redirect> 元素先重定向该页并结束请求,接下来,后续页面才能使用请求 Bean 中存储的任何值。
在 IDE 中创建页面时,页面 Bean 的 Java 源代码包含用于访问 RequestBean1、SessionBean1 和 ApplicationBean1 对象的方法。要访问这些受管 Bean 的属性,请使用类似于以下代码片段中的语句的代码。
| 代码样例 1:访问应用程序 Bean 属性 |
ApplicationBean1 appBean = getApplicationBean1(); Option[] choices = appBean.BallotOptions();
|
Web 应用程序将在页面第一次(在 Bean 的作用域内)访问受管 Bean 中的属性时,实例化该受管 Bean。例如,只有当用户访问了引用 SessionBean1 属性的页面时,用户会话中才会出现 SessionBean1 对象的实例。ApplicationBean1 对象实例是在任何会话中的页面第一次访问应用程序 Bean 时创建的,而且只要 Web 应用程序处于运行状态,它就会存在。
提示:要添加其他的受管 Bean,请执行以下操作:
- 在“项目”窗口中展开“源包”节点,右键单击包节点。
- 选择“新建”>“其他”,选择 "JavaServer Faces" 类别以及“文件类型”下的范围,然后单击“下一步”。
-
键入新的受管 Bean 的文件名,然后单击“完成”。
新的受管 Bean 将出现在“项目”窗口中的“源包”节点下。
向受管 Bean 添加属性
此 Web 应用程序中的页需要访问以下值,您将在本部分创建这些值:
ballotOptions。包含选票选项列表的数组属性。由于此列表对于所有会话来说都是相同的,因此该属性位于应用程序作用域中。
tally。累计所有会话投票的散列映射属性。因为它必须存在于会话之间,所以位于应用程序作用域中。
hasVoted。跟踪用户是否已投票的布尔型属性。由于应用程序需要在单个会话的多个请求之间保留该值,因此应用程序将其存储在会话作用域中。
timestamp。Date 属性,应用程序在其中记录用户提交投票的时间以备下一个页面使用。由于在呈现下一个页面后应用程序不再需要该值,因此应用程序将其存储在请求作用域中。
请完成以下步骤,以便向受管 Bean 添加属性。
- 从主菜单中,选择“文件”>“新建项目”。
- 在“新建项目”向导中,从“类别”列表中选择 "Java Web",从“项目”列表中选择“Web 应用程序”,然后单击“下一步”。
- 将项目命名为
Scopes。
- (可选)选中“使用专用文件夹存储库”复选框,并指定库文件夹的位置。有关此选项的详细信息,请参见共享项目库。
- 单击“下一步”。
- 选择要与此项目一起使用的应用服务器,然后单击“下一步”。
-
在“框架”面板中,选中 "Visual Web JavaServer Faces",然后单击“完成”。
将在可视设计器中打开 Scopes 项目的 Page1.jsp。
-
在“导航”窗口中,双击 ApplicationBean1。
这将打开 ApplicationBean1.java 以进行编辑。
- 接下来您可以添加应用程序 Bean 属性。在构造函数 public class ApplicationBean1 extends AbstractApplicationBean 下添加以下声明:
private Option[] ballotOptions;
private HashMap tally;
-
在 Java 编辑器中单击鼠标右键,然后选择“修复导入”。由于多个包中含有 Option 类,因此将出现“修复导入”对话框。
- 对于 Java EE 5 项目,请选择
com.sun.webui.jsf.model.Option。
- 对于 J2EE 1.4 项目,请选择
com.sun.rave.web.ui.model.Option。
- 在源代码编辑器中单击鼠标右键,然后选择“重构”>“封装字段”。
-
在“封装字段”对话框中,选中相应的复选框以便为 ballotOptions 和 tally 属性创建 getter 和 setter 方法,如下图所示。

-
滚动至 init 方法,并将下面以粗体显示的代码添加到方法的底部。
代码样例 2:要添加到应用程序 Bean 的 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:应用程序 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 处于设计模式时,将会出现“导航”窗口。
- 接下来您可以添加会话 Bean 属性。在构造函数 public class SessionBean1 extends AbstractSessionBean 下添加以下声明:
private boolean hasVoted;
- 在 Java 编辑器中单击鼠标右键,然后选择“重构”>“封装字段”。
- 在“封装字段”对话框中,选中相应的复选框以便为 hasVoted 属性创建 getter 和 setter 方法,然后单击“重构”。
-
滚动至 init 方法,并将下面以粗体显示的代码添加到方法的底部。
代码样例 4:要添加到会话 Bean 的 init 方法的代码 |
// TODO - add your own initialization code here setHasVoted(false);
|
- 按 Ctrl-S 组合键保存更改,然后按 Ctrl-F4 组合键关闭文件。
- 在“导航”窗口中,双击 "RequestBean1"。这将打开 RequestBean1.java 以进行编辑。
- 添加请求 Bean 属性。在构造函数 public class RequestBean1 extends AbstractRequestBean 下添加以下声明:
private java.util.Date timestamp;
- 在 Java 编辑器中单击鼠标右键,然后选择“重构”>“封装字段”。
- 在“封装字段”对话框中,选中相应的复选框以便为 timestamp 属性创建 getter 和 setter 方法,然后单击“重构”。
-
单击 "Page1" 标签,然后单击 Page1 的“设计”按钮。检查“导航”窗口,以确保请求 Bean、会话 Bean 和应用程序 Bean 中的属性与下图匹配。
创建起始页
按照本节中的步骤,创建如下图所示的页面(正在浏览器中运行)。如果用户单击 "Submit Vote" 按钮,此页面将提交用户的投票。用户投票后,该按钮将变为禁用状态,从而防止用户在该会话中再次投票。

- 在编辑工具栏中单击 "Page1"。
- 将一个标签组件从组件面板的“基本”类别拖放到页面的顶部中央,并将其 text 属性设置为
Reader's Poll: What Is Your Favorite Programming Language?。
- 将一个单选按钮组组件拖放到标签组件的下方。
- 在“属性”窗口中,将该单选按钮组组件的
id 设置为 voteRBGroup。
- 右键单击该单选按钮组组件,然后选择添加绑定属性。
-
右键单击该单选按钮组组件,然后从弹出式菜单中选择“绑定到数据”。
将出现“绑定到数据”对话框。
- 在该对话框的“绑定到对象”标签中,选择 "ApplicationBean1" > "ballotOptions",然后单击“确定”。
- 将一个按钮组件拖放到单选按钮组组件的下方,并将其 text 属性设置为
View Results。
注意:IE7 存在一个已知问题,它会影响 JSF 1.2 按钮组件的宽度。解决方法是,将按钮组件放在布局组件(网格面板、组面板或布局面板)中。调整布局组件大小时,将会自动调整按钮组件的大小。
- 在“属性”窗口中,将该按钮组件的
id 属性设置为 viewButton。
- 右键单击按钮组件,然后选择“添加绑定属性”。
-
单击 action 属性的省略号按钮
,从下拉列表中选择 viewButton_action,然后单击“确定”。
IDE 将添加 viewButton_action 事件处理程序,该程序返回 null。
- 将一个按钮组件拖放到 "View Results" 按钮的右侧,然后将其 text 属性设置为
Submit Vote。
- 在“属性”窗口中,将该按钮组件的
id 设置为 voteButton。
- 右键单击按钮组件,然后选择“添加绑定属性”。
-
单击 disabled 属性的省略号按钮
。
这将打开该属性的属性绑定对话框。
-
在该对话框中,选择“使用绑定”,单击“绑定到对象”,选择 "SessionBean1" > "hasVoted"(如下图所示),然后单击“确定”。

-
双击 "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" 按钮以获得最新的计票,该计票包括自最后一次显示页面以来其他用户提交的投票。

- 在“项目”窗口中,右键单击 Scopes 项目下的“Web 页”节点,选择“新建”>“Visual Web JSF 页”,将页面命名为
Results,然后单击“完成”以创建该页面。
- 将一个标签组件拖放到 "Results" 页的顶部中央,并将其 text 属性设置为
Results。
- 将一个按钮组件拖放到标签组件的左侧,并将其 text 属性设置为
Home。
- 将该按钮组件的
id 设置为 homeButton。
- 右键单击按钮组件,然后选择“添加绑定属性”。
- 单击
action 属性的省略号按钮
,从“处理程序”下拉列表中选择 homeButton_action,然后单击“确定”。
- 将一个按钮组件拖放到标签组件的右侧,并将其 text 属性设置为
Refresh Results。
- 将该按钮组件的
id 设置为 refreshButton。
- 右键单击按钮组件,然后选择“添加绑定属性”。
- 单击
action 属性的省略号按钮
,从“处理程序”下拉列表中选择 refreshButton_action,然后单击“确定”。
- 将一个网格面板组件从组件面板的“布局”类别拖放到标签组件的下方。
- 在“属性”窗口中,将
cellspacing 属性设置为 10,将 columns 属性设置为 1。
-
将一个静态文本组件拖动到网格面板组件中。当该网格面板组件的边框变为蓝色实线时,放置静态文本组件,如下图所示。
- 在“属性”窗口中,将静态文本组件的
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 表,并将该表放到第一个静态文本组件的 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。
指定页面导航
按照下面的步骤,为按钮指定页面导航(如下图所示)。

- 在编辑区中,单击 "Results" 标签,然后单击“设计”在可视设计器中查看该页面。
-
右键单击页面中的空白处,然后从弹出式菜单中选择“页面导航”。
这将在页面流编辑器中显示 faces-config.xml
- 单击 "Page1.jsp" 图标中的 + 号将该图标放大。
- 从 "viewButton" 单击并拖动到 "Results.jsp",以便在该按钮和 Results 页之间创建一条连线。
- 双击该连线的标签以更改为编辑模式,键入
view results,然后按 Enter 键。
- 从 voteButton 单击并拖动到 Results.jsp。
- 双击该连线的标签以更改为编辑模式,键入
vote,然后按 Enter 键。
- 单击 "Results.jsp" 图标中的 + 号将该图标放大。
- 从 homeButton 单击并拖动到 Page1.jsp。
- 双击该连线的标签以更改为编辑模式,键入
home,然后按 Enter 键。
运行应用程序
要通过同一个浏览器来启用多个会话,请配置应用程序,以便在每个会话处于不活动状态的时间达到一分钟时结束该会话。然后部署并运行该应用程序。
-
在“文件”窗口中,展开 "Scopes" > "web" > "WEB-INF",如下图所示。
- 双击 web.xml 节点,在编辑器中打开该文件。
-
在“会话超时”文本框中键入 1,如下图所示。
- 保存并关闭该文件。
-
单击主工具栏中的“运行主项目”按钮
。
注意:缺省情况下,将在启用“在保存时编译”功能的情况下创建项目,因此无需先编译代码即可在 IDE 中运行应用程序。有关“在保存时编译”功能的详细信息,请参见创建、导入和配置 Java 项目指南的“在保存时编译”部分。
-
当起始页出现时,选中一个单选按钮,然后单击 "Submit Vote"。
浏览器将显示结果页。请注意,结果页上会显示您提交投票的时间。
-
单击 "Home" 返回到起始页。
由于您已经投票,因此将禁用 "Submit Vote"。
-
单击 "View Results"。
请注意,结果页上不再显示您投票的时间。这是因为以前的请求 Bean 超出作用域,并且已实例化新的请求 Bean。
- 请等待一分钟,以使会话超时。然后,在浏览器的地址文本框中键入以下 URL 并按 Enter 键启动新的会话:
http://localhost:8080/Scopes。如果未使用缺省的服务器配置,则可能需要将 8080 更改为其他端口。
- 再次投票并检查结果。结果应当包括第一次的投票。
- 如果具有不同的浏览器应用程序,请启动该浏览器,在浏览器的地址文本框中键入
http://localhost:8080/Scopes,然后按 Enter 键。提交另一个投票。
-
在第一个浏览器中,单击结果页中的 "Refresh Results"。
结果应当包括通过第二个浏览器提交的投票。
执行更多操作
利用在本教程中所学到的知识,您可以构建一个提示输入登录名的应用程序。然后,添加一个页面,该页面用于显示已访问此 Web 应用程序的用户的数量(不包括每位用户重复访问的次数)。
小结
您可以使用应用程序 Bean、会话 Bean 和请求 Bean 来存储信息以供其他页面使用。
另请参见
本页的最新修改时间:2008 年 10 月 22 日