通过数据库生成 JavaServer Faces 2.x CRUD 应用程序

在本教程中,您将使用 NetBeans IDE 来创建一个与后端数据库进行交互的 Web 应用程序。使用该应用程序可以查看和修改数据库中包含的数据,也称为 CRUD(创建、读取、更新和删除)功能。您将开发的应用程序依赖于以下技术。

  • JavaServer Faces (JSF) 2.x,用于前端 Web 页、验证处理和请求-响应周期的管理。
  • Java Persistence API (JPA) 2.0,通过 EclipseLink 从数据库中生成实体类,并管理事务。(EclipseLink 是 JPA 的引用实现,也是 GlassFish Server 的默认持久性提供器。)
  • Enterprise JavaBeans (EJB) 3.1,提供了用于访问实体类的无状态 EJB,并且包含了应用程序的业务逻辑。

此 IDE 提供了两种可为应用程序生成所有代码的向导。一种是 "Entity Classes from Database"(通过数据库生成实体类)向导,您可以通过所提供的数据库来生成实体类。在创建实体类之后,可使用“通过实体类创建 JSF 页”向导为实体类创建 JSF 受管 Bean 和 EJB,以及一组用于处理实体类数据视图的 Facelets 页。本教程的最后部分了解应用程序为可选章节,其中提供了大量练习有助于您更好地理解应用程序并进一步熟悉此 IDE。

此页上的内容适用于 NetBeans IDE 7.2、7.3、7.4 和 8.0

目录

要学完本教程,您需要具备以下软件和资源。

软件或资源 要求的版本
NetBeans IDE 7.2、7.3、7.4、8.0、Java EE 包
Java 开发工具包 (JDK) 7 或 8
GlassFish Server 开源版 3.x、4.x
mysql-consult.zip (MySQL)

javadb-consult.zip (JavaDB)
N/A

注:

  • NetBeans IDE Java EE 包还包括本教程所需的 GlassFish Server(一种 Java EE 兼容的服务器)。
  • 要获取本教程的解决方案项目,请下载 ConsultingAgencyJSF20.zip

创建数据库

本教程使用了一个名为 consult 的咨询代理数据库。安装 IDE 时,该数据库并未包括在其中,因此需要首先创建该数据库以按照本教程完成后续的学习。

consult 数据库旨在演示 IDE 对处理各种数据库结构所提供的支持范围。因此,该数据库不应作为数据库设计的推荐范例或最佳做法。相反,它尝试将可能会在数据库设计中遇到的许多相关功能包含了进来。例如,consult 数据库包含了所有可能的关系类型、复合主键和许多不同的数据类型。有关此数据库结构的更详细概览,请参见下表。

注:

  • 本教程使用 MySQL 数据库服务器,但也可使用 JavaDB 数据库服务器来完成本教程的学习。要在 JavaDB 中创建该数据库,请下载并解压缩 javadb-consult.zip 档案文件。此档案文件包含用于创建、放置和填充 consult 数据库的 SQL 脚本。
  • 有关配置 IDE 使用 MySQL 的详细信息,请参见连接 MySQL 数据库教程。
  • 有关配置 IDE 以使用 JavaDB 的详细信息,请参见使用 Java DB (Derby) 数据库教程。


执行以下步骤以创建数据库并通过 IDE 与其进行连接。

  1. 下载 mysql-consult.zip 并将此档案解压缩到本地系统。在解压缩档案时您将看到用于创建和填充数据库的 SQL 脚本。档案中还包含了用于拖放表的脚本。
  2. 在 "Services"(服务)窗口中,展开 "Databases"(数据库)节点,右键单击 "MySQL" 节点并选择 "Start Server"(启动服务器)。
  3. 右键单击 MySQL 服务器节点并选择 "Create Database"(创建数据库)。
  4. 在 "Create MySQL Database"(创建 MySQL 数据库)对话框中键入 consult 作为数据库名称。单击 "OK"(确定)。"Databases"(数据库)节点 (jdbc:mysql://localhost:3306/consult [root on Default schema]) 下随即出现一个新的节点。
  5. 右键单击新节点并选择 "Connect"(连接)。
  6. 从主菜单中选择 "File"(文件)> "Open File"(打开文件)并导航至解压缩的文件 mysql_create_consult.sql。单击 "Open"(打开)。该文件会自动在 SQL 编辑器中打开。
    SQL 编辑器的屏幕快照
  7. 确保在 SQL 编辑器工具栏的 "Connection"(连接)下拉列表中选择了 consult 数据库,然后单击 "Run SQL"(运行 SQL)("Run SQL"(运行 SQL)按钮) 按钮。

    单击 "Run SQL"(运行 SQL)时,"Output"(输出)窗口中出现以下输出内容。

    "Output"(输出)窗口的屏幕快照

检查数据库结构

要确认已正确创建了表,请展开数据库连接节点下的 "Tables"(表)节点。您可以展开表节点来查看表的列、索引和任意外键。可以右键单击列并选择 "Properties"(属性)来查看有关该列的其他信息。

"Services"(服务)窗口的屏幕快照

注:如果在 "Tables"(表)节点下未看到任何表,右键单击 "Tables"(表)节点并选择 "Refresh"(刷新)。

consult 数据库的结构可看出该数据库包含了具有多种关系和各种字段类型的表。通过数据库创建实体类时,IDE 会为各种字段类型自动生成相应的代码。

consult 数据库的实体关系图

下表描述了 consult 数据库中的表。

数据库表 描述 设计功能
CLIENT 咨询机构的客户 非生成的复合主键(其字段不构成外键)
CONSULTANT 咨询机构的员工,客户可基于合同对其进行聘用 包括一个 LONG VARCHAR 类型的简历字段
CONSULTANT_STATUS 顾问在咨询机构的状态(例如,可能为活动和非活动的状态) CHAR 类型的非生成主键
RECRUITER 负责联络客户和顾问的咨询机构的员工  
PROJECT 客户配有咨询机构顾问的项目 包含了构成 CLIENT 表的外键的两个字段的非生成复合主键
BILLABLE 顾问在某个项目中工作的小时数,咨询机构据其向相关客户收费 包括一个 CLOB 类型的工件字段
ADDRESS 客户账单地址  
PROJECT_CONSULTANT 一个连接表,表示当前为哪些项目指派了哪些顾问 交叉引用了 PROJECT 和 CONSULTANT,其中前者有一个复合主键

consult 数据库包含了多种关系。在通过数据库创建实体类时,IDE 将基于列的 SQL 类型自动生成相应的 Java 类型的属性。下表描述了 consult 数据库的实体关系。(未显示反向关系。)

实体 相关实体 关系信息 描述
CLIENT RECRUITER 进行手动编辑,允许为空值的一对一关系;如果不进行手动编辑,允许为空值的一对多关系 一个 CLIENT 有多个 RECRUITER,而一个 RECRUITER 没有或有一个 CLIENT(如果不进行手动编辑)
CLIENT ADDRESS 不允许为空值的一对一关系 一个 CLIENT 有一个 ADDRESS,而一个 ADDRESS 没有或有一个 CLIENT
CLIENT PROJECT 不允许为空值的一对多关系;在 "Project" 实体中,客户字段的值是 "Project" 主键的一部分 一个 CLIENT 有多个 PROJECT,而一个 PROJECT 只有一个 CLIENT
CONSULTANT PROJECT 多对多关系 一个 CONSULTANT 有多个 PROJECT,而一个 PROJECT 也有多个 CONSULTANT
CONSULTANT BILLABLE 不允许为空值的一对多关系 一个 CONSULTANT 有多个 BILLABLE,而一个 BILLABLE 有一个 CONSULTANT
CONSULTANT_STATUS CONSULTANT 不允许为空值的一对多关系 一个 CONSULTANT_STATUS 有多个 CONSULTANT,而一个 CONSULTANT 有一个 CONSULTANT_STATUS
CONSULTANT RECRUITER 允许为空值的一对多关系 一个 CONSULTANT 没有或有一个 RECRUITER,而一个 RECRUITER 有多个 CONSULTANT
BILLABLE PROJECT 不允许为空值的一对多关系 一个 BILLABLE 有一个 PROJECT,而一个 PROJECT 有多个 BILLABLE

既然已经创建了数据库,那么就可以创建 Web 应用程序,并使用 "Entity Classes from Database"(通过数据库生成实体类)向导基于数据库表生成实体类。

创建 Web 应用程序项目

在本练习中,您将创建一个 Web 项目并将 JavaServer Faces 框架添加到该项目中。在创建项目时,需要在新建项目向导的 "Frameworks"(框架)面板中选择 "JavaServer Faces"。

  1. 从主菜单中,选择 "File"(文件)> "New Project"(新建项目)(Ctrl-Shift-N 组合键;在 Mac 上为 ⌘-Shift-N 组合键)。
  2. 从 "Java Web" 类别中选择 "Web Application"(Web 应用程序)。单击 "Next"(下一步)。
  3. 键入 ConsultingAgency 作为项目名称,并设置项目位置。单击 "Next"(下一步)。
  4. 将服务器设置为 "GlassFish",并将 Java EE 版本设置为 "Java EE 6 Web" 或 "Java EE 7 Web"。单击 "Next"(下一步)。
  5. 在 "Frameworks"(框架)面板中,选择 "JavaServer Faces" 选项。单击 "Finish"(完成)。

单击 "Finish"(完成),此时 IDE 生成 Web 应用程序项目并在编辑器中打开 index.xhtml

通过数据库生成实体类

在 IDE 中连接到数据库后,可以使用 "Entity Classes from Database"(通过数据库生成实体类)向导基于数据库中的表快速生成实体类。IDE 可以为所选的每个表生成实体类,也可以为相关表生成任何需要的实体类。

  1. 在 "Projects"(项目)窗口中,右键单击 ConsultingAgency 项目节点,并选择 "New"(新建)> "Entity Classes from Database"(通过数据库生成实体类)。(如果未列出此选项,请选择 "Other"(其他)。然后,在文件向导中,选择 "Persistence"(持久性)类别,再选择 "Entity Classes from Database"(通过数据库生成实体类)。)
  2. 从 "Data Source"(数据源)下拉列表中选择 "New Data Source"(新建数据源)以打开 "Create Data Source"(创建数据源)对话框。
  3. 键入 jdbc/consult 作为 JNDI 名称,并选择 jdbc:mysql://localhost:3306/consult 连接作为数据库连接。
    "Create Datasource"(创建数据源)对话框
  4. 单击 "OK"(确定)以关闭对话框并返回到向导。consult 数据库中的表出现在 "Available Tables"(可用表)列表框中。
  5. 单击 "Add All"(全部添加)按钮以选择数据库中包含的所有表。单击 "Next"(下一步)。
    "New Entities from Database"(通过数据库新建实体)向导
  6. 键入 jpa.entities 作为包名称。
  7. 确认已选中用于生成命名查询和创建持久性单元的复选框。单击 "Finish"(完成)。

单击 "Finish"(完成),此时 IDE 将在项目的 jpa.entities 包中生成实体类。

使用向导通过数据库创建实体类时,IDE 会检查数据库表之间的关系。在 "Projects"(项目)窗口中,如果展开 jpa.entities 包节点,则可以看到 IDE 为每个表(PROJECT_CONSULTANT 表除外)生成了一个实体类。因为 PROJECT_CONSULTANT 是一个连接表,所以 IDE 没有为其创建实体类。

"Projects"(项目)窗口的屏幕快照

IDE 还为带有复合主键的表生成了两个额外的类:CLIENTPROJECT。这些表的主键类(ClientPK.javaProjectPK.java)在其名称后附加了 PK

如果查看为实体类生成的代码,可以发现向导为自动生成的 ID 字段添加了 @GeneratedValue 标注,还为实体类中的某些字段添加了 @Basic(optional = "false") 标注。基于 @Basic(optional = "false") 标注,“通过实体类创建 JSF 页”向导可以生成包含检查的代码,这些检查可防止那些字段出现不允许为空值的列违规。


通过实体类生成 JSF 页

创建了实体类之后,便可以创建用于显示和修改数据的 Web 接口。您将使用“通过实体类创建 JSF 页”向导来生成 JavaServer Faces 页。向导生成的代码将基于实体类中包含的持久性标注。

对于每个实体类,向导都会生成以下文件。

  • 扩展 AbstractFacade.java 的无状态会话 Bean
  • JSF 会话范围的受管 Bean
  • 包含 CRUD 功能的四个 Facelets 文件(Create.xhtmlEdit.xhtmlList.xhtmlView.xhtml)的目录

向导还会生成以下文件。

  • 包含实体实例的创建、检索、修改和删除业务逻辑的 AbstractFacade.java
  • JSF 受管 Bean 所使用的实用程序类(JsfUtilPaginationHelper
  • 本地化消息的属性包,以及项目的 Faces 配置文件(如果不存在 faces-config.xml 文件,则会创建一个)中的相应条目
  • 辅助 Web 文件(包括所呈现组件的默认样式表)和一个 Facelets 模板文件

生成 JSF 页:

  1. 在 "Projects"(项目)窗口中,右键单击项目节点,然后选择 "New"(新建)> "JSF Pages from Entity Classes"(通过实体类创建 JSF 页)打开该向导。(如果未列出此选项,请选择 "Other"(其他)。然后,在文件向导中,选择 "JavaServer Faces" 类别,然后选择 "JSF Pages from Entity Classes"(通过实体类创建 JSF 页)。)

    "Available Entity Classes"(可用的实体类)框列出了项目中所包含的七个实体类。该框并未列出可嵌入类(ClientPK.javaProjectPK.java)。

  2. 单击 "Add All"(全部添加)以将所有类移动到 "Selected Entity Classes"(选定的实体类)框中。
    "New JSF Pages from Entity Classes"(通过实体类新建 JSF 页)向导
    单击 "Next"(下一步)。
  3. 在向导的“步骤 3”即 "Generate JSF Pages and Classes"(生成 JSF 页和类)中,键入 jpa.session 作为 JPA 会话 Bean 包。
  4. 键入 jsf 作为 JSF 类包。
  5. 在 "Localization Bundle Name"(本地化包名称)字段中输入 "/resources/Bundle"。这样将生成一个名为 resources 的包,其中将包含 Bundle.properties 文件。(如果将此字段保留为空,则在项目的默认包中将创建属性包。)
    "New JSF Pages from Entity Classes"(通过实体类新建 JSF 页)向导,步骤 3

    要使 IDE 能更好地适应您的项目约定,可以定制由向导生成的任何文件。单击 "Customize Template"(定制模板)链接以修改向导所使用的文件模板。
    "Customize Template"(定制模板)下拉列表
    通常,可以使用 "Template Manager"(模板管理器)("Tools"(工具)> "Templates"(模板))来访问和更改 IDE 维护的所有模板。

  6. 单击 "Finish"(完成)。IDE 在 jpa.session 包中生成无状态会话 Bean,并在 jsf 包中生成 JSF 会话范围的受管 Bean。每个无状态会话 Bean 用于处理相应实体类的操作,其中包括通过 Java 持久性 API 创建、编辑和销毁实体类的实例。每个 JSF 受管 Bean 用于实现 javax.faces.convert.Converter 接口,并执行将相应实体类的实例转换为 String 对象的操作,反之亦然。

如果展开 "Web Pages"(Web 页)节点,则可以看到 IDE 为每个实体类生成了一个文件夹。每个文件夹都包含 Create.xhtmlEdit.xhtmlList.xhtmlView.xhtml 文件。IDE 还通过向每个 List.xhtml 页中插入链接来修改 index.xhtml 文件。

"Projects"(项目)窗口中的 "Web Pages"(Web 页)目录的屏幕快照

每个 JSF 受管 Bean 都对应四个相应的 Facelets 文件,并且包含调用相应会话 Bean 中的方法的代码。

展开 resources 文件夹节点以查找由向导生成的 jsfcrud.css 默认样式表。如果在编辑器中打开应用程序欢迎页面 (index.xhtml) 或 Facelets 模板文件 (template.xhtml),将会看到该文件包含了对样式表的引用。

<h:outputStylesheet name="css/jsfcrud.css"/>

每个实体类所对应的四个 Facelets 文件中的每个文件都使用 Facelets 模板文件。

如果展开 "Source Packages"(源包)节点,则可以看到向导生成的会话 Bean、JSF 受管 Bean、实用程序类和属性包。

"Projects"(项目)窗口中的 "Source Packages"(源包)目录的屏幕快照

为了注册属性包的位置,向导还生成了一个 Faces 配置文件 (faces-config.xml)。如果展开 "Configuration File"(配置文件)节点并在 XML 编辑器中打开 faces-config.xml,则可以看到该文件包含了以下条目。

<application>
    <resource-bundle>
        <base-name>/resources/Bundle</base-name>
        <var>bundle</var>
    </resource-bundle>
</application>

此外,如果展开新的 resources 包,则会发现 Bundle.properties 文件,该文件包含了客户端默认语言的消息。这些消息是由实体类属性派生而来的。

要添加新的属性包,请右键单击 Bundle.properties 文件并选择 "Customize"(定制)。使用 "Customizer"(定制器)对话框可以将新的语言环境添加到您的应用程序中。


了解应用程序

既然您的项目已包含了实体类、用于控制实体类的 EJB 会话 Bean 和 JSF 驱动的用于显示和修改数据库的前端,那么请尝试运行该项目以查看结果。

以下是一系列可选的小练习,可用来进一步熟悉应用程序,以及 IDE 所提供的功能。

检查已完成的项目

  1. 要运行项目,请在 "Projects"(项目)窗口中右键单击项目节点并选择 "Run"(运行),或单击主工具栏中的 "Run Project"(运行项目)("Run Project"(运行项目)按钮) 按钮。

    当显示应用程序的欢迎页面时,将提供一个链接列表,用于查看包含在每个数据库表中的条目。

    浏览器中的 ConsultingAgency 欢迎页

    当完成了 "JSF Pages from Entity Classes"(通过实体类创建 JSF 页)向导时,链接将添加到欢迎页面 (index.xhtml)。这些链接将作为 Facelets 页(为“咨询机构”数据库提供 CRUD 功能)的入口点。

    <h:body>
        Hello from Facelets
        <h:form>
            <h:commandLink action="/address/List" value="Show All Address Items"/>
        </h:form>
        <h:form>
            <h:commandLink action="/billable/List" value="Show All Billable Items"/>
        </h:form>
        <h:form>
            <h:commandLink action="/client/List" value="Show All Client Items"/>
        </h:form>
        <h:form>
            <h:commandLink action="/consultant/List" value="Show All Consultant Items"/>
        </h:form>
        <h:form>
            <h:commandLink action="/consultantStatus/List" value="Show All ConsultantStatus Items"/>
        </h:form>
        <h:form>
            <h:commandLink action="/project/List" value="Show All Project Items"/>
        </h:form>
        <h:form>
            <h:commandLink action="/recruiter/List" value="Show All Recruiter Items"/>
        </h:form>
    </h:body>
  2. 单击 "Show All Consultant Items" 链接。查看上面的代码,则可以看到目标页为 /consultant/List.xhtml。(在 JSF 2.x 中,由于隐式导航所以文件扩展名是推断出来的。)
    Consultants 页
    数据库目前不包含任何样例数据。可以通过单击 "Create New Consultant" 链接和使用提供的 Web 窗体手动添加数据。此操作将触发 /consultant/Create.xhtml 页进行显示。还在 IDE 中运行 SQL 脚本以使用样例数据填充表。以下子部分对这两个选项进行了说明。

您可以单击索引链接返回到欢迎页面列出的链接。这些链接提供了保存在每个数据库表中数据的视图,并触发了每个实体文件夹中 List.xhtml 文件的显示。稍后会有说明,在将数据添加到表之后,会显示其他链接,其中每个条目都允许您查看 (View.xhtml)、编辑 (Edit.xhmtl) 和销毁单个表记录的数据。

注:如果应用程序部署失败,请参见下面的疑难解答部分。(另请参见使用 MySQL 数据库创建简单的 Web 应用程序的“疑难解答”部分。)

使用 SQL 脚本填充数据库

运行提供的脚本,该脚本会生成数据库表的样例数据。脚本 (mysql_insert_data_consult.sql) 包含在咨询机构数据库 zip 文件中,该文件可从所需软件表中下载。

根据所使用的数据库服务器(MySQL 或 JavaDB),您可以运行提供的脚本,该脚本会为数据库表生成样例数据。对于 MySQL,该脚本为 mysql_insert_data_consult.sql。对于 JavaDB,该脚本为 javadb_insert_data_consult.sql。两个脚本分别包含在各自的档案文件中,可以通过所需软件表进行下载。

  1. 从主菜单中选择 "File"(文件)> "Open File"(打开文件),然后导航到脚本在您的计算机上的位置。单击 "Open"(打开)。文件会自动在 IDE 的 SQL 编辑器中打开。
  2. 确保在 SQL 编辑器工具栏的 "Connection"(连接)下拉列表中选择了 consult 数据库。
    SQL 编辑器和插入数据脚本的屏幕快照

    在编辑器中右键单击并选择 "Run Statement"(运行语句),或单击 "Run SQL"(运行 SQL)("Run SQL"(运行 SQL)按钮) 按钮。您可以在 "Output"(输出)窗口中查看脚本运行的结果。

  3. 重新启动 GlassFish Server。这是使服务器可以重新加载和缓存 consult 数据库中包含的新数据所必需的步骤。为此,请在 "Output" 窗口中单击 "GlassFish Server" 标签("GlassFish Server" 标签显示服务器日志。),然后单击左旁注中的 "Restart Server"(重新启动服务器)("Restart Server"(重新启动服务器)按钮) 按钮。服务器即会停止,然后重新启动。
  4. 重新运行项目,然后单击 "Show All Consultant Items" 链接。将看到该列表不再为空。
    显示表条目的 "Consultants" 页

了解 Facelets 页中的编辑器支持

  1. 在编辑器中打开 /consultant/List.xhtml 页。第 8 行表明该页的呈现依赖于 Facelets template.xhtml 文件。
    <ui:composition template="/template.xhtml">

    要显示行号,请右键单击编辑器的左旁注,然后选择 " Show Line"(显示行号)。

  2. 使用 IDE 的 "Go to File"(转至文件)对话框来打开 template.xhtml。按 Alt-Shift-O 组合键(在 Mac 上为 Ctrl-Shift-O 组合键),然后开始键入 template
    "Go to File"(转至文件)对话框

    单击 "OK"(确定)(或按 Enter 键)。

  3. 模板将使用 <ui:insert> 标记将其他文件的内容插入到其标题和正文中。将光标置于 <ui:insert> 标记上,然后按 Ctrl-空格键调用文档弹出式窗口。
    编辑器中显示的文档弹出式窗口

    可以在 JSF 标记及其属性上按 Ctrl-空格键调用文档弹出式窗口。您查看的文档是从正式的 JSF 标记库文档所提供的描述中获取的。

  4. 切换回 List.xhtml 文件(按 Ctrl-Tab 组合键)。<ui:define> 标记用来定义将应用于模板标题和正文的内容。为每个实体类生成的所有 4 个 Facelets 文件(Create.xhtmlEdit.xhtmlList.xhtmlView.xhtml)都使用了此模式。
  5. 将您的光标置于任何 EL 表达式(用于包含在 Bundle.properties 文件中的本地化消息)上。按 Ctrl-空格键查看本地化消息。
    属性包中的消息的代码完成弹出式窗口

    在上图上,可以看到 EL 表达式解析为 "List",该表达式将应用到模板标题,并且可以从呈现在浏览器中的页面得到验证。

  6. 滚动到文件底部并找到 Create New Consultant 链接的代码(第 92 行)。如下所示:
    <h:commandLink action="#{consultantController.prepareCreate}" value="#{bundle.ListConsultantCreateLink}"/>
  7. commandLinkaction 属性上按 Ctrl-空格键以调用文档弹出式窗口。

    action 属性表示在浏览器中单击链接时处理请求的方法。将提供以下文档:

    方法表达式,用于表示在用户激活此组件时要调用的应用程序操作。该表达式的值必须为一个没有参数且返回对象(调用其 toString() 以派生逻辑结果)的公共方法,该对象将被传递到此应用程序的 NavigationHandler。

    换句话说,action 值通常是指 JSF 受管 Bean 中的一个方法,其值为 String。然后 JSF 的 NavigationHandler 会使用该字符串将请求转发到相应的视图中。可通过以下步骤来验证这一点。
  8. 将光标置于 consultantController 上,然后按 Ctrl-空格组合键。编辑器的代码完成表明 consultantController 是一个 JSF 受管 Bean。
    在编辑器中调用的代码完成
  9. 将光标移动到 prepareCreate,然后按 Ctrl-空格组合键。代码完成列出了包含在 ConsultantController 受管 Bean 中的方法。
    在编辑器中调用的代码完成
  10. 按 Ctrl 键(在 Mac 上为 ⌘ 键),然后将鼠标悬停在 prepareCreate 上。形成了一个链接,您可以直接导航至 ConsultantController 受管 Bean 中的 prepareCreate() 方法。
    编辑器中显示的链接
  11. 单击链接并查看 prepareCreate() 方法(如下所示)。
    public String prepareCreate() {
        current = new Consultant();
        selectedItemIndex = -1;
        return "Create";
    }
    该方法将返回 CreateNavigationHandler 在后台收集信息,并将 Create 字符串应用于以视图(为响应请求而发送)为目标的路径:/consultant/Create.xhtml。(在 JSF 2.x 中,由于隐式导航所以文件扩展名是推断出来的。)

通过字段验证来了解数据库完整性

  1. 在浏览器的 Consultants List 页中,单击 "Create New Consultant" 链接。正如之前子部分中的说明,此操作将触发呈现 /consultant/Create.xhtml 页。
  2. 在窗体中输入以下详细信息。目前,将 RecruiterIdStatusId 字段保留为空。

    字段
    ConsultantId 2
    Email
    Password jack.smart
    HourlyRate 75
    BillableHourlyRate 110
    HireDate 07/22/2008
    Resume I'm a great consultant.Hire me - You won't be disappointed!
    RecruiterId ---
    StatusId ---
  3. 单击 "Save"(保存)。当您执行此操作后,将对 StatusId 字段标记一个验证错误。
    包含样例数据的 "Create New Consultant" 页
    为什么会出现这种情况?重新检查“咨询机构”数据库的实体关系图。如上面的关系表中所述,CONSULTANTCONSULTANT_STATUS 表共享一个不允许为空值的一对多的关系。所以,CONSULTANT 表中的每一个条目都必须包含对 CONSULTANT_STATUS 表中条目的引用。这将通过链接这两个表的 consultant_fk_consultant_status 外键来表示。

    可以通过在 "Services"(服务)窗口中展开一个表的 "Foreign Keys"(外键)节点(Ctrl-5 组合键;在 Mac 上为 ⌘-5 组合键)来查看表中保存的外键。

    "Services"(服务)窗口 - consultant 表的外键
  4. 要解决验证错误,请从 StatusId 下拉列表中选择 entity.ConsultantStatus[statusId=A]

    注:RecruiterId 字段可保留为空。正如数据库实体关系图中所示,在 CONSULTANTRECRUITER 表之间存在一个允许为空值的一对多的关系,这就意味着 CONSULTANT 中的条目不需要与一个 RECRUITER 条目相关联。
  5. 单击 "Save"(保存)。将显示一条消息,表明顾问条目已成功保存。如果单击 Show All Consultant Items,将看到新条目列在表中。

通常,生成的 Facelets 页会为产生下列问题的用户输入提供出错信息:

  • 不允许为空值的表单元格中出现了空字段。
  • 对不可更改的数据(例如主键)进行了修改。
  • 插入数据的类型不正确。
  • 当用户视图与数据库不再同步时对数据进行了修改。

编辑实体类

在前面的子部分中,您看到了 StatusId 下拉列表是如何为您提供不那么容易使用的 entity.ConsultantStatus[statusId=A] 选项。您可能已经注意到:此下拉列表中针对每一项显示的文本都是每个遇到的 ConsultantStatus 实体(即,调用了实体类的 toString() 方法)的字符串表示。

该子部分将演示您可以使用编辑器的代码完成、文档和导航支持作此结论的方式。此外,还教您为下拉列表准备更加易于使用的消息。

  1. 在编辑器中打开 /consultant/Create.xhtml 文件。这是您刚在浏览器中看到的 "Create New Consultant" 窗体。向下滚动到 StatusId 下拉列表的代码处(如下面粗体所示)。
        <h:outputLabel value="#{bundle.CreateConsultantLabel_resume}" for="resume" />
        <h:inputTextarea rows="4" cols="30" id="resume" value="#{consultantController.selected.resume}" title="#{bundle.CreateConsultantTitle_resume}" />
        <h:outputLabel value="#{bundle.CreateConsultantLabel_statusId}" for="statusId" />
        <h:selectOneMenu id="statusId" value="#{consultantController.selected.statusId}" title="#{bundle.CreateConsultantTitle_statusId}" required="true" requiredMessage="#{bundle.CreateConsultantRequiredMessage_statusId}">
            <f:selectItems value="#{consultantStatusController.itemsAvailableSelectOne}"/>
        </h:selectOneMenu>
        <h:outputLabel value="#{bundle.CreateConsultantLabel_recruiterId}" for="recruiterId" />
        <h:selectOneMenu id="recruiterId" value="#{consultantController.selected.recruiterId}" title="#{bundle.CreateConsultantTitle_recruiterId}" >
            <f:selectItems value="#{recruiterController.itemsAvailableSelectOne}"/>
        </h:selectOneMenu>
    </h:panelGrid>
  2. 检查应用于 <f:selectItems> 标记的 valuevalue 属性决定了为下拉列表中每项显示的文本。

    itemsAvailableSelectOne 上按 Ctrl-空格组合键。编辑器的代码完成表示 ConsultantStatusControllergetItemsAvailableSelectOne() 方法返回了 SelectItem 对象的数组。
    在编辑器中调用的代码完成
  3. 按 Ctrl 键(在 Mac 上为 ⌘ 键),然后将鼠标悬停在 itemsAvailableSelectOne 上。形成了一个链接,您可以直接导航至 ConsultantStatus 实体源代码中的 getItemsAvailableSelectOne() 方法。单击该链接。
  4. 将光标置于方法签名中的 SelectItem[] 返回值上,然后按 Ctrl-空格键调用文档弹出式窗口。
    在 Java 类中调用的文档弹出式窗口

    单击 "documentation"(文档)窗口中的 "web browser"(Web 浏览器)("Web browser"(Web 浏览器)图标) 图标以在外部 Web 浏览器中打开 Javadoc。

    正如您所看到的,SelectItem 类属于 JSF 框架。文档中提到的 UISelectOne 组件使用您在上述步骤 1 中检查的标记中的 <h:selectOneMenu> 标记来表示。
  5. 按 Ctrl 键(在 Mac 上为 ⌘ 键),然后将鼠标悬停在 findAll() 上。随即出现一个弹出式窗口,显示方法签名。
    方法签名的弹出式窗口
    可以看到此处的 ejbFacade.findAll() 返回了 ConsultantStatus 对象的 List
  6. 导航至 JsfUtil.getSelectItems。将鼠标悬停在 getSelectItems 上并按 Ctrl 键(在 Mac 上为 ⌘),然后单击显示的链接。

    注:回想一下,JsfUtil 是在您完成“通过实体类创建 JSF 页”向导时生成的一个实用程序类。

    该方法对实体列表(即 ConsultantStatus 对象的 List)执行循环操作,为每个实体创建 SelectItem。如下面粗体所示,每个 SelectItem 都是使用实体对象和对象的标签来创建的。
    public static SelectItem[] getSelectItems(List<?> entities, boolean selectOne) {
        int size = selectOne ? entities.size() + 1 : entities.size();
        SelectItem[] items = new SelectItem[size];
        int i = 0;
        if (selectOne) {
            items[0] = new SelectItem("", "---");
            i++;
        }
        for (Object x : entities) {
            items[i++] = new SelectItem(x, x.toString());
        }
        return items;
    }

    该标签使用实体的 toString() 方法来创建,并且在响应中呈现对象时是对象的表示。(请参见 SelectItem(java.lang.Object value, java.lang.String label) 构造函数的 Javadoc 定义。)

    既然您已在查看下拉列表中的项时,验证了实体 toString() 方法正是浏览器中所呈现的内容,那么请修改 ConsultantStatus toString() 方法。

  7. 在编辑器中打开 ConsultantStatus 实体类。修改 toString 方法以返回 statusIddescription。这些是对应于 CONSULTANT_STATUS 表的两列的实体属性。
    public String toString() {
        return statusId + ", " + description;
    }
  8. 重新运行项目。当浏览器显示欢迎页面时,单击 Show All Consultant Items 链接,然后单击 Create New Consultant

    检查 StatusId 下拉列表。将看到现在显示的是数据库的 CONSULTANT_STATUS 表中所包含的一个记录的状态 ID 和描述。

    "StatusId" 下拉列表的浏览器显示

疑难解答

根据您的配置不同,将应用程序部署到服务器可能会失败,您可能会在 "Output"(输出)窗口中看到以下消息。

GlassFish Server 4 is running.
In-place deployment at /MyDocuments/ConsultingAgency/build/web
GlassFish Server 4, deploy, null, false
/MyDocuments/ConsultingAgency/nbproject/build-impl.xml:1045: The module has not been deployed.
See the server log for details.

最常见的失败原因是,在服务器上生成 JDBC 资源时出现问题。如果是这样,您可能会在 "Output"(输出)窗口的 "server log"(服务器日志)标签中看到类似于以下内容的消息。

Severe:   Exception while preparing the app : Invalid resource : jdbc/consult__pm
com.sun.appserv.connectors.internal.api.ConnectorRuntimeException: Invalid resource : jdbc/consult__pm

如果 "server log"(服务器日志)标签未打开,您可以通过在 "Services"(服务)窗口中右键单击 "GlassFish Server" 节点并选择 "View Domain Server Log"(查看域服务器日志)来打开此标签。

此应用程序需要两个 JDBC 资源:

  • JDBC 资源或数据源。此应用程序使用 JNDI 查找来定位 JDBC 资源。如果在持久性单元 (persistence.xml) 中查找,您可以看到此应用程序的 JTA 数据源的 JNDI 名称为 jdbc/consult

    JDBC 资源标识当前由此应用程序使用的连接池。

  • JDBC 连接池。连接池指定数据库的连接详细信息,包括位置、用户名、口令。用于此应用程序的连接池为 consultPool

glassfish-resources.xml 文件中指定 JDBC 资源和连接池。通过在 "Projects"(项目)窗口中展开 "Server Resources"(服务器资源)节点并双击 glassfish-resources.xml 文件,可以在编辑器中打开此文件。此文件看起来类似于以下内容。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>
  <jdbc-connection-pool allow-non-component-callers="false" associate-with-thread="false" connection-creation-retry-attempts="0" connection-creation-retry-interval-in-seconds="10" connection-leak-reclaim="false" connection-leak-timeout-in-seconds="0" connection-validation-method="auto-commit" datasource-classname="com.mysql.jdbc.jdbc2.optional.MysqlDataSource" fail-all-connections="false" idle-timeout-in-seconds="300" is-connection-validation-required="false" is-isolation-level-guaranteed="true" lazy-connection-association="false" lazy-connection-enlistment="false" match-connections="false" max-connection-usage-count="0" max-pool-size="32" max-wait-time-in-millis="60000" name="consultPool" non-transactional-connections="false" ping="false" pool-resize-quantity="2" pooling="true" res-type="javax.sql.DataSource" statement-cache-size="0" statement-leak-reclaim="false" statement-leak-timeout-in-seconds="0" statement-timeout-in-seconds="-1" steady-pool-size="8" validate-atmost-once-period-in-seconds="0" wrap-jdbc-objects="false">
    <property name="serverName" value="localhost"/>
    <property name="portNumber" value="3306"/>
    <property name="databaseName" value="consult"/>
    <property name="User" value="root"/>
    <property name="Password" value="nb"/>
    <property name="URL" value="jdbc:mysql://localhost:3306/consult?zeroDateTimeBehavior=convertToNull"/>
    <property name="driverClass" value="com.mysql.jdbc.Driver"/>
  /<jdbc-connection-pool>
  <jdbc-resource enabled="true" jndi-name="jdbc/consult" object-type="user" pool-name="consultPool"/>
/<resources>

glassfish-resources.xml 中,您可以看到 JDBC 资源 jdbc/consultconsultPool 标识为连接池的名称。您还可以看到 consultPool 的属性。在此应用程序中,只在 glassfish-resources.xml 中定义一个数据源和一个连接池。在某些情况下,您可能需要指定其他资源,例如,用于标识仅用于开发或测试的临时数据存储。

如果在运行应用程序时未自动在服务器上生成 JDBC 资源和连接池,您可以执行以下步骤在 GlassFish 管理控制台中手动创建这些资源。

  1. 如果尚未打开 glassfish-resources.xml,请在编辑器中打开它。

    创建 JDBC 资源和连接池时,将使用在 glassfish-resources.xml 中指定的属性值。

  2. 在 "Services"(服务)窗口中右键单击 "GlassFish Server" 节点,然后在弹出式菜单中选择 "Open Domain Admin Console"(打开域管理控制台)在浏览器中打开 GlassFish 控制台。
  3. 在 GlassFish 控制台的 "Common Tasks"(常见任务)导航面板中,展开 JDBC 节点以及 JDBC Resources(JDBC 资源)和 JDBC Connection Pools(JDBC 连接池)节点。
    GlassFish 管理控制台的浏览器显示

    您可以看到当前注册到服务器的 JDBC 资源。如果在 "Common Tasks"(常见任务)导航面板中的 "JDBC" 节点下未列出 jdbc/consultconsultPool,则您将需要创建它们。在安装服务器时,默认情况下创建了一些 JDBC 资源并且这些资源显示为子节点。

  4. 单击 JDBC Connection Pools(JDBC 连接池)节点,然后在 "New JDBC Connection Pool"(新建 JDBC 连接池)窗格中单击 "New"(新建)。
    &quot;New JDBC Connection Pool&quot;(新建 JDBC 连接池)窗格的浏览器显示
  5. 键入 consultPool 作为池名称,选择 javax.sql.ConnectionPoolDataSource 作为资源类型并选择 MySql 作为数据库驱动程序供应商。单击 "Next"(下一步)。
  6. 在步骤 2 中,定位并指定 URLusernamepassword 属性的值。单击 "Finish"(完成)。
    &quot;New JDBC Connection Pool&quot;(新建 JDBC 连接池)窗格的第二个面板的浏览器显示

    可以在 glassfish-resources.xml 中查找这些属性的值。

    单击 "Finish"(完成)时,将在服务器上创建新的连接池,并在 "JDBC Connection Pools"(JDBC 连接池)节点下显示此连接池的节点。

  7. 在 "Common Tasks"(常见任务)导航面板中单击 JDBC Resources(JDBC 资源)节点并单击 "New"(新建)。
  8. 为 "JNDI Name"(JNDI 名称)键入 jdbc/consult,并在 "Pool Name"(池名称)下拉列表中选择 consultPool。单击 "OK"(确定)。
    &quot;New JDBC Resource&quot;(新建 JDBC 资源)窗格的浏览器显示

    单击 "OK"(确定)时,将在服务器上创建新的 JDBC 资源,并在 "JDBC Resources"(JDBC 资源)节点下显示此资源的节点。

    在 IDE 的 "Service"(服务)窗口中,可以在 "GlassFish Server" 下展开 "Resources"(资源)节点,您会看到 IDE 已添加新资源。您可能需要刷新视图(右键单击 "Resources"(资源)并选择 "Refresh"(刷新))来查看更改。

    IDE 中 &quot;Services&quot;(服务)窗口的屏幕快照

有关使用 MySQL 和 IDE 时的问题疑难解答的更多提示,请参见以下文档:


另请参见

有关 JSF 2.x 的详细信息,请参见以下资源。

get support for the NetBeans

Support


By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2013, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo