使用“数据约束”组件访问数据库
在此教程中,您将使用 NetBeans IDE 6.5 创建并部署 Web 应用程序,以显示 IDE 包装的数据库的“主从”数据。在此应用程序中,从 JSF 1.2 (Woodstock) 下拉列表中选择一个人,应用程序就会在表格中显示该人的所有行程记录。
在使用此教程前,请您熟悉 IDE 的基本内容并阅读 NetBeans Visual Web JSF 开发入门 以了解 NetBeans IDE 的开发环境。
预计时间:30 分钟
目录

要学习本教程,您需要具备以下软件和资源。
* 要利用 NetBeans IDE 的 Java EE 5 功能,请使用完全符合 Java EE 5 规范的应用服务器,例如 GlassFish Application Server V2 UR2。如果使用的是其他服务器,请查阅发行说明和常见问题解答,了解已知问题和解决方法。有关支持的服务器和 Java EE 平台的详细信息,请参见发行说明。
在此教程中,您将构建一个 Travel Center 应用程序,部署后的应用程序如下图所示。

首先,将表格和下拉列表组件添加到新项目创建的缺省 Page 1.jsp 页中。
-
创建名称为 DataboundComponents 新Web 应用程序项目,在此将使用 GlassFish V2 Application Server 和 Visual Web JavaServer Faces 框架。
IDE 将创建一个名称为 Page1 的页面,并在“可视设计器”中显示它。
- 展开“组件面板”中的“ Woodstock 基本”节点,将“标签”组件拖到此页面左侧。键入
选择姓名:并按下 Enter 键。
- 将“下拉列表”组件拖到“标签”组件的右侧。
-
在“标签”组件的“属性”窗口中,选择 personIdDD 作为 for 属性,如下图所示。

- 右键单击“文本字段”组件并选择“添加绑定属性”。
-
从“组件面板”拖动一个“消息组”组件放到页面的偏僻位置上,例如页面右上角。
此组件对诊断编程错误卓有成效。通过调用 info ( String )、 error ( String )、 warn ( String )或 fatal ( String )方法,可以使诊断消息显示在此组件上。“消息组”组件用于显示 String 变量的值。另外,缺省情况下,有关运行时错误、验证错误和转换错误都显示在此组件中。
建立数据库
在本节中,在 IDE 中建立 travel 数据库和 MySQL 数据库。
- 确保已经在您的机器中安装和运行 MySQL 数据库服务器。有关连接 MySQL 数据库的更多信息,请参见连接到 MySQL 数据库。
-
在“服务”窗口中,右键单击 “MySQL 服务器”节点并选择“创建数据库”。
此时将打开“创建新数据库”对话框。

-
从“新建数据库名称”下拉列表中,选择“样例数据库: travel”,然后单击“确定”。
在“服务”窗口中,travel 数据库出现在“ MySQL 服务器”节点下方。

连接到数据库
“服务”窗口将出现在 IDE 工作区的左侧,其中包含了一个数据库节点。数据库节点显示了所有的数据库驱动和已添加到 IDE 的连接。
绑定数据库到组件后,就在组件和数据库表之间创建了两个层:行集层和数据提供器层。行集用于连接数据库,执行查询并管理结果集。数据提供器层为访问多种类型的数据提供通用接口,如从行集到 Array 对象及 Enterprise JavaBeans 对象。
通常,仅与行集对象工作的时间是需要设置查询参数的时候。在很多其他情况下,应该使用数据提供器访问并操作数据。可以通过使用数据提供器 API 来降低难度,因为无论您包装何种数据(即无论你使用哪个数据提供器工具),相同的 API 都能起作用。
在教程的本节中,您将使用来自 Travel 数据库的个人表提供给“下拉列表”组件选择。
-
在“服务”窗口中,展开“数据库”节点并检查是否已连接到 Travel 数据库。
如果 Travel 数据库的 jdbc 节点标记是断开的并且不能展开节点,则表示 IDE 没有连上数据库。要连接 travel 数据库,右键单击 travel 的 jdbc 节点并从弹出式菜单中选择“连接”。
-
展开 "travel" >“表”节点。
在“表”下,可以看到数据库中的每个表节点,例如 "carrental" 和 "flight"。下图显示了已展开表节点的“服务”窗口。
-
从“服务”窗口中,将 person 表拖放到“下拉列表”中。
abc 文本将出现在“下拉列表”组件中。 abc 文本表明显示字段绑定到 String 对象,该对象在此情况下是 SQL varchar 类型的数据库列。另外,IDE 为数据库表添加了不可见的 personDataProvider 组件。personDataProvider 组件出现在“导航”窗口中。IDE 还将为 SessionBean1 添加 personRowSet 属性。
-
右键单击“下拉列表”并从弹出式菜单中选择“绑定到数据”。此时将出现“绑定到数据”对话框,如下图所示。
绑定数据到“下拉列表”组件后,必须指定列表(显示字段)中显示的内容和基础程序(值字段)中使用的值。通常,您希望从数据库表中显示有意义的值(例如姓名),但是在底层程序中使用唯一的标识符(例如个人的 ID )。但是,在此应用程序中,将“值”字段和“显示”字段同时绑定到相同的数据库列 person.name,在紧接的两步中将描述该内容。
- 在“绑定到数据”对话框中,从“值字段”列表中选择 person.personid 使组件的 getSelected 方法为当前的选择返回 person.personid。
- 从“显示字段”列表中选择 person.name 以便浏览器使用 person.name 数据库列中的值填充下拉列表。
- 单击“确定”。
-
在主工具栏中,单击“运行”>“运行主项目”。
注意:缺省情况下,创建项目时会启用保存时编译功能,因此在 IDE 中运行应用程序无需首先编译代码。有关保存时编译功能的更多信息,请参见创建、导入和配置 Java 项目指南的“保存时编译”一节。
IDE 将保存所有的更改,然后生成、部署并运行 Web 应用程序。首先,在 IDE 的底部出现“输出”窗口。IDE 将在此窗口写出编译和部署的准备信息。(因此,如果生成遇到任何问题,首先检查“输出”窗口。)接下来,对话框显示部署的情况。部署完成之后,IDE 将在 Web 浏览器中打开应用程序 。 浏览器呈现该页面时,应用程序使用 person 表的name 列数据填充下拉列表。
添加“表”组件
接下来,在应用程序中添加“表”组件并将此组件连接到数据库表。
- 从“组件面板”中拖动“表”组件并放到“下拉列表”组件下。
- 在“服务”窗口中,展开 "travel" >“表”节点。
-
从“服务”窗口拖动一个 trip 表放到“表”组件标题栏上。
注意:如果将 trip 数据库放到表组件的其他部分,就会打开“选择目标”对话框。在“选择目标”对话框中,选择 table1 并单击“确定”。
-
右键单击“表”组件并选择“表布局”。
在“表布局”方框中的“选定”列表显示所有表的列。使用来自“选定”列表的项指定“表”组件中应该显示的列。
- 除 trip.depdate 、 trip.depcity 和 trip.destcity 外,使用 Ctrl-Click 选择“选定”列表中的所有条目。
-
单击 "<" 按钮。
选择的条目移动到“可用的”列表中,以下三个条目保留在“可选”列表中,如下图所示:
-
单击“确定”。
现在,可视设计器在“表”组件中显示了三列,如下图所示。
接下来,在 tripRowSet 对象中修改 SQL 查询以便查询也返回来自 triptype 表的数据。还要修改“表”组件以显示 trip 类型的描述。
-
在“导航”窗口中,如果 "SessionBean1" 节点还未展开,则将其展开。
-
在“导航”窗口的 "SessionBean1" 部分,右键单击 tripRowSet 节点并选择“编辑 SQL 语句”。
在编辑区显示出“查询编辑器”和 "tripRowSet" 标签。
提示:如果“输出”窗口处于打开状态,请将其关闭以便留出更多的空间使用“查询编辑器”
-
在“服务”窗口中,将 "Travel" > 表 > triptype 表拖放到“设计”视图:
此时将显示另一个表格图,并且两个表格图之间存在链接。此链接表示连接。注意在“源代码”方格中 IDE 怎样修改 select 语句。
-
在 triptype 表中清除 triptypeid 的复选框。
此操作删除了来自结果集和“源代码”方格中 SQL 查询的列,如下图所示。
- 保留查询编辑器为打开状态。
- 在编辑区,单击 Page1 标签。
-
在可视编辑器中,右键单击“表”组件并选择“表布局”。
此时将显示“表布局”对话框。由于更改了 tripRowSet SQL 查询,您可以显示更多列。
-
将 triptype.description 列添加到“可选”列表并单击“确定”。
在“表”组件中显示第四列。
为 TRIP 表添加“数据提供器”后,IDE 将创建 RowSet 对象,同时 SQL 查询返回表中所有列对应的行。 此时部署并运行应用程序,“表”组件会在 TRIP 表中显示所有的行程信息。
对于此应用程序,“表”组件仅显示从“下拉列表”组件中选择了姓名的个人行程信息。通过编辑 tripRowSet 对象的查询,在“下拉列表”组件和“表”组件间创建“主从”关系,您就可以限制表中的显示信息。
- 在编辑区单击 jdbc:mysql://localhost:3306/travel 以切换到“查询编辑器”。
- 在“查询编辑器”的“设计网格”中,右键单击 personid 行的任意单元格并选择“添加查询条件”。
- 设置“比较”下拉列表为
= 等于,选择“参数”单选按钮并单击“确定”。
-
在 personid 的“条件”栏,看到 =? ,以上操作在 SQL 查询中添加以下 WHERE 字句。
| Code Sample 1: WHERE Clause in the SQL Query |
WHERE trip.personid = ?
|
-
在“查询编辑器”的“设计网格”中,在 DEPDATE 行单击“排序类型”单元格并从下拉列表中选择“升序”。
IDE 自动设置“排序顺序”并向 SQL 查询中添加排序字句。
- 关闭“查询编辑器”。
-
在“可视设计器”中,双击“下拉列表”组件。
在 Java 编辑器中打开 Page1 类的源代码,光标停留在 personIdDD_processValueChange 方法的主体内。首次双击“下拉列表”组件时, IDE 创建此事件处理程序的桩模块。
-
用以下粗体显示的代码替换 personIdDD_processValueChange 方法的主体。
| 代码样例 2:下拉列表组件的值更改事件处理 |
public void personIdDD_processValueChange(ValueChangeEvent event) { try { getSessionBean1().getTripRowSet().setObject( 1, personIdDD.getSelected()); tripDataProvider.refresh(); } catch (Exception e) { error("Cannot switch to person " + personDataProvider.getValue( "PERSON.PERSONID")); log("Cannot switch to person " + personDataProvider.getValue( "PERSON.PERSONID"), e); } }
|
此代码将把下拉列表中当前选择的 NAME 对应的 PERSONID 值绑定到 tripRowSet 对象准备好的 SQL 语句的参数中,执行查询,并得到新的结果集。
在查询 PERSONID 值中的 setObject 方法替换?查询 PERSONID 值 refresh 方法提交新的查询并刷新结果集。 学习更多有关两者之一的方法,右键单击方法调用并选择从下拉式菜单中“显示 Javadoc”。 通过选择“帮助” > “Javadoc 引用” > “数据提供器和帮助”> “Javadoc 引用” >“行集”查看“数据提供器”和“行集 Javadoc ”。
log 方法发送消息,应用服务器日志关联的栈跟踪信息帮助发现和诊断用户问题。在“服务”窗口,右键单击服务器节点并从弹出式菜单中选择“查看服务器日志”,可以查看该服务器日志。
- 按 Alt-Shift-F 重新设置代码格式。
- 在源代码中查找
prerender 方法。
-
用以下粗体显示的代码替换 prerender 方法的主体。
| 代码样例 3:首次打开页面时同步主从数据 |
public void prerender() { if ( personIdDD.getSelected() == null ) { try { personDataProvider.cursorFirst(); getSessionBean1().getTripRowSet().setObject( 1, personDataProvider.getValue("PERSON.PERSONID")); tripDataProvider.refresh(); } catch (Exception e) { error("Cannot switch to person " + personDataProvider.getValue("PERSON.PERSONID")); log("Cannot switch to person " + personDataProvider.getValue("PERSON.PERSONID"), e); } } }
|
在 Web 浏览器开始显示页面之前,调用 prerender 方法中的代码。
- 按 Alt-Shift-F 重新设置代码格式。
- 在编辑工具栏单击“设计”返回“可视设计器”。
-
右键单击“下拉列表”组件并选择“更改后自动提交”。
在“属性”窗口,onchange 属性中显示以下代码。
| Code Sample 4: onchange Property Code |
Webuijsf.suntheme.common.timeoutSubmitForm(this.form, 'personIdDD');
|
现在,如果用户在运行的 Web 应用程序中更改下拉列表的选择, Web 浏览器自动提交页面。
-
在主工具栏中单击“运行主项目”。
注意:缺省情况下,创建项目时会启用保存时编译功能,因此在 IDE 中运行应用程序无需首先编译代码。有关保存时编译功能的更多信息,请参见创建、导入和配置 Java 项目指南的“保存时编译”一节。
- 从“下拉列表”组件中选择个人,查看“表”组件怎样同步主从数据。单击 DESTCITY 列头处查看“表”组件怎样将行进行排序。
更多内容
试试看。在“下拉列表”组件的右边添加大小约为 2 cm 的“静态文本”组件。右键再次单击“静态文本”组件并选择“添加绑定属性”。右键再次单击“静态文本”组件并选择“绑定到数据”。在“数据提供器”下拉列表中选择 personDataProvider ,并将该组件绑定到 person.jobtitle 。运行程序并从下拉列表中选择不同的姓名。注意工作标题不发生变化,这是因为应用程序需要同步 personDataProvider 和从下拉列表中选择的项目。在 prerender 方法中添加以下粗体显示的代码并再次运行应用程序。工作标题现在应该和选择的姓名相匹配。
| 代码样例 5:同步 personDataProvider 与所选个人 |
public void prerender() { if ( personIdDD.getSelected() == null ) { try { personDataProvider.cursorFirst(); getSessionBean1().getTripRowSet().setObject( 1, personDataProvider.getValue("PERSON.PERSONID")); tripDataProvider.refresh(); } catch (Exception e) { error("Cannot switch to person " + personDataProvider.getValue("PERSON.PERSONID")); log("Cannot switch to person " + personDataProvider.getValue("PERSON.PERSONID"), e); } } else { try { // Synchronize data provider with current selection personDataProvider.setCursorRow( personDataProvider.findFirst( "PERSON.PERSONID", personIdDD.getSelected())); } catch (Exception e) { error("Cannot switch to person " + personIdDD.getSelected()); log("Cannot switch to person " + personIdDD.getSelected(), e); } } }
|
试试看。操作表的布局选项。右键单击“表”组件并从弹出式菜单中选注“表格布局”。将“标题文本”更改为 Departure Date、Departure City ,Destination City 和 Description。使用对话框中的“选项”表设置表的标题为 Trips 。选择“启用分页”并设置“页面大小”为 3 。运行应用程序并查看您的更改怎样影响了表的显示方式。
注意:如果使用分页选择,在 personIdDD_processValueChange 方法中的 tripDataProvider.refresh() 语句后添加以下代码: tableRowGroup1.setFirst(0); 。这确保从下拉菜单中选择新的姓名时总能显示首页。在“导航”窗口中,展开 "Page1" > "html1" > "body1" > "table1" ,右键单击 tableRowGroup1 并选择“添加绑定属性”。
试试看。使用“下拉列表”组件和“表”组件构建 Web 应用程序。使“下拉列表”组件显示 triptype.description 。使“表”组件显示所有的 trip 记录,此记录和选择的 TRIPTYPE 有相同的 TRIPTYPEID 。
试试看。您可能会怀疑:在 prerender 和 personIdDD_processValueChange 方法中复制的代码是否会导致详细行集的双重刷新。答案是否定的。为了说明该问题,将 log method-name 语句添加到构造函数 prerender 和 personIdDD_processValueChange 中。在“服务”窗口中,右键单击服务器节点并选择“查看服务器日志”。运行程序并选择新的姓名。在服务器日志(在“输出”窗口中)中,看到方法是按以下次序调用:
- 构造函数
- prerender
- 构造函数
- personIdDD_processValueChange
浏览器首次请求页面时,应用程序创建 Page1 实例并调用prerender。服务器将发送响应(HTML 页面),并销毁 Page1 实例。应用程序并不会调用值更改事件处理程序,因为应用程序只有在提交页面时(在本例中,选择一个新的个人时)才会生成值更改事件。
从下拉列表中选择新的姓名时,浏览器提交页面。此应用程序创建 Page1 的新实例并从先前的实例(它们在请求中通过)中恢复值。 因为这是传回请求(提交),同时姓名已经更改,所以应用程序生成值更改事件。因此调用 personIdDD_processValueChange 并且应用程序刷新行集。
调用值更改事件处理程序后,应用程序将调用 prerender 方法。由于现在下拉列表中有选择值,应用程序将跳过 prerender 方法中的 if 部分。
结束语
将组件绑定到数据库表的步骤如下:
- 通过将数据库表的节点拖到组件上或从弹出式菜单中选择“绑定到数据”并从下拉列表中选择存在的“数据提供器”的方法绑定组件到数据库。
- 使用“绑定到数据”对话框配置数据库,以控制组件显示的列,对于列表型的组件,还要控制其返回的具体列。也可以使用“表布局”菜单操作配置“表”组件所显示的具体数据库表的列。
- 在“导航”窗口中,打开“行集”对象的“查询编辑器”,修改“行集”对象的查询。
- 调用“行集”对象的
setObject 方法,以设置查询参数的值。调用数据提供器的 refresh 方法执行查询并刷新结果集。
- 使用“更改后自动提交”菜单操作以便在组件值更改时自动提交页面。
-
执行以下步骤以同步从组件和主组件。
- 将代码添加到 Page Bean 的
prerender 方法,调用从“行集”对象的setObject方法以设置查询参数为某些缺省值(例如在下拉菜单中显示第一个人)。然后调用 refresh 方法执行查询。
- 将主组件绑定到 processValueChanged 方法。使用此方法调用从“行集”对象的
setObject 方法以设置新查询参数。然后调用 refresh 方法执行查询。
另请参见
本页的最后修改时间:2008 年 10 月 22 日