JSF 和 Java Persistence API(JPA)

Sang Shin, sang.shin@sun.com, Sun Microsystems, www.javapassion.cn



Java Platform Enterprise Edition 5(Java EE 5)专注于简化开发,同时保留了 J2EE 1.4 平台中的丰富特性。Java EE 5 提供了各种最新的功能,如 Enterprise JavaBeans(EJB)技术 3.0、JavaServer Faces(JSF)技术和最新的 Web 服务 API,它使编码工作更加简单和直观,并且其强大的功能使它成为了 Web 服务和企业级应用程序开发的主要平台。

本动手实验室介绍 Java EE 5 的基本功能。其目标是让您了解 Java EE 5 平台的关键功能。本实验室将介绍的功能包括


预计时间:120 分钟


软件需求

开始之前,需要在您的计算机中安装以下软件。


变更记录


实验室练习


练习 1:使用 JPA 和 JavaServer Faces 构建并运行 CRUD 应用程序


在本练习中,您将了解如何在现有数据库表中创建实体。也将使用 JavaServer Faces(JSF)页面通过这些实体对数据库表执行基于 web 的 CRUD(创建、读取、更新和删除)操作。
  1. 创建 CD 和 LOCATION 数据库表
  2. 创建一个新的 NetBeans 项目
  3. 创建 Persistence Unit(persistence.xml)
  4. 在现有数据库表中创建实体
  5. 在实体中创建 JSF 页面
  6. 编译和运行应用程序


(1.1)创建 CD 和 LOCATION 数据库表

在本步骤中,首先将在示例数据库中创建 CD LOCATION 表。 稍后,将在这些表中创建实体。

1. 启动 Sun Java System App Server 附带的 Java DB(Derby)数据库服务器


图 1.10:连接到示例数据库

图 1.11:输入 app 的密码

2. 创建 CDLOCATION 表并向其添加数据行。

图 1.12:对数据库执行命令

DROP TABLE CD;
DROP TABLE LOCATION;

create table "LOCATION"
(
    "LOCATION_ID" INTEGER NOT NULL PRIMARY KEY,
    "LOCATION" VARCHAR(40)
);


create table "CD"
(
    "CD_ID" INTEGER NOT NULL PRIMARY KEY,
    "TITLE" VARCHAR(40),
    "AUTHOR" VARCHAR(40),
    "YEAR_CREATED" INTEGER,
    "LOCATION" INTEGER,
    "RATING" INTEGER,
    CONSTRAINT FK_CD_LOCATION FOREIGN KEY (LOCATION) REFERENCES LOCATION(LOCATION_ID)
);



INSERT INTO LOCATION VALUES (0,'Cha Cha Cha bar');
INSERT INTO LOCATION VALUES (1,'Limon Restaurant');
INSERT INTO LOCATION VALUES (2,'Taqueria el Balazo');
INSERT INTO LOCATION VALUES (3,'Office');
INSERT INTO LOCATION VALUES (4,'Home');


INSERT INTO CD VALUES (
0,    'Rock and Roll Aint Noise Pollution',    'AC/DC',    1980,    0,    9);

INSERT INTO CD VALUES (
1,    'Shake a Leg',    'AC/DC',    1980,    2,    6);

INSERT INTO CD VALUES (
2,    'Have a Drink on Me',    'AC/DC',    1980,    2,    5);

INSERT INTO CD VALUES (
3,    'You Shook Me All Night Long',    'AC/DC',    1980,    1,    8);

INSERT INTO CD VALUES (
4,    'Back in Black',    'AC/DC',    1980,    4,    9);

INSERT INTO CD VALUES (
5,    'Let Me Put My Love into You',    'AC/DC',    1980,    4,    9);

INSERT INTO CD VALUES (
6,    'Givin the Dog a Bone',    'AC/DC',    1980,    2,    6);

INSERT INTO CD VALUES (
7,    'What Do You Do for Money Honey',    'AC/DC',    1980,    3,    5);

INSERT INTO CD VALUES (
8,    'Shoot to Thrill',    'AC/DC',    1980,    1,    8);

INSERT INTO CD VALUES (
9,    'Battery',    'Metalica',    1986,    0,    9);
INSERT INTO CD VALUES (
10,    'Master of Puppets',    'Metalica',    1986,    0,    9);
INSERT INTO CD VALUES (
11,    'The Thing That Should Not Be',    'Metalica',    1986,    4,    9);
INSERT INTO CD VALUES (
12,    'Welcome Home (Sanitarium)',    'Metalica',    1986,    3,    9);
INSERT INTO CD VALUES (
13,    'Disposable Heroes',    'Metalica',    1986,    1,    9);
INSERT INTO CD VALUES (
14,    'Leper Messiah',    'Metalica',    1986,    4,    9);
INSERT INTO CD VALUES (
15,    'Orion [Instrumental]',    'Metalica',    1986,    3,    9);
INSERT INTO CD VALUES (
16,    'Damage, Inc.',    'Metalica',    1986,    2,    9);
代码 1.13:CD.sql

图 1.14:运行 SQL 命令

图 1.15:刷新数据库表的显示

图 1.16:查看 CD 表的数据

图 1.17:显示出 CD 表的行
                                                                                                                    返回练习顶部

(1.2)创建一个名称为 "CDLibrary" 的新 NetBeans 项目


1. 创建一个新 Web 应用程序 NetBeans 项目。 

图 1.20:名称和位置

2. 选择 JavaServer Faces(JSF)框架

图 1.21:选择 JavaServer Faces 框架

                                                                                                                    返回练习顶部

(1.3)创建持久性单元


在本步骤中,您将创建一个 持久性单元,由项目的 persistence.xml 文件所表示。persistence.xml 文件包含一个或几个 persistence-unit 元素。每个 persistence-unit 定义持久性上下文名称、数据源设置和提供商特定属性。

1. 创建持久性单元

图 1.31:创建持久性单元

图 1.32:选择数据源和持久性提供器

2. 观察 persistence.xml 文件

图 1.33:persistence.xml

                                                                                                                    返回练习顶部


(1.4)通过现有的数据库表创建实体


在本步骤中,您将通过现有的数据库表 CDLOCATION 表中创建实体。

1. 通过 CD LOCATION 表创建实体。

图 1.41:通过数据库生成实体类
2. 选择数据源和数据库表

图 1.42:输入密码

图 1.43:选择数据库表

3. 指定实体类

图 1.44:提供包名
4. 学习 Cd.javaLocation.java
package mypackage;

import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

/**
 * Entity class Cd
 *
 * @author sang
 */
@Entity
@Table(name = "CD")
@NamedQueries( {
        @NamedQuery(name = "Cd.findByCdId", query = "SELECT c FROM Cd c WHERE c.cdId = :cdId"),
        @NamedQuery(name = "Cd.findByTitle", query = "SELECT c FROM Cd c WHERE c.title = :title"),
        @NamedQuery(name = "Cd.findByAuthor", query = "SELECT c FROM Cd c WHERE c.author = :author"),
        @NamedQuery(name = "Cd.findByYearCreated", query = "SELECT c FROM Cd c WHERE c.yearCreated = :yearCreated"),
        @NamedQuery(name = "Cd.findByRating", query = "SELECT c FROM Cd c WHERE c.rating = :rating")
    })
public class Cd implements Serializable {

    @Id
    @Column(name = "CD_ID", nullable = false)
    private Integer cdId;

    @Column(name = "TITLE")
    private String title;

    @Column(name = "AUTHOR")
    private String author;

    @Column(name = "YEAR_CREATED")
    private Integer yearCreated;

    @Column(name = "RATING")
    private Integer rating;

    @JoinColumn(name = "LOCATION", referencedColumnName = "LOCATION_ID")
    @ManyToOne
    private Location location;
   
    /** Creates a new instance of Cd */
    public Cd() {
    }

    /**
     * Creates a new instance of Cd with the specified values.
     * @param cdId the cdId of the Cd
     */
    public Cd(Integer cdId) {
        this.cdId = cdId;
    }

    /**
     * Gets the cdId of this Cd.
     * @return the cdId
     */
    public Integer getCdId() {
        return this.cdId;
    }

    /**
     * Sets the cdId of this Cd to the specified value.
     * @param cdId the new cdId
     */
    public void setCdId(Integer cdId) {
        this.cdId = cdId;
    }

    /**
     * Gets the title of this Cd.
     * @return the title
     */
    public String getTitle() {
        return this.title;
    }

    /**
     * Sets the title of this Cd to the specified value.
     * @param title the new title
     */
    public void setTitle(String title) {
        this.title = title;
    }

    /**
     * Gets the author of this Cd.
     * @return the author
     */
    public String getAuthor() {
        return this.author;
    }

    /**
     * Sets the author of this Cd to the specified value.
     * @param author the new author
     */
    public void setAuthor(String author) {
        this.author = author;
    }

    /**
     * Gets the yearCreated of this Cd.
     * @return the yearCreated
     */
    public Integer getYearCreated() {
        return this.yearCreated;
    }

    /**
     * Sets the yearCreated of this Cd to the specified value.
     * @param yearCreated the new yearCreated
     */
    public void setYearCreated(Integer yearCreated) {
        this.yearCreated = yearCreated;
    }

    /**
     * Gets the rating of this Cd.
     * @return the rating
     */
    public Integer getRating() {
        return this.rating;
    }

    /**
     * Sets the rating of this Cd to the specified value.
     * @param rating the new rating
     */
    public void setRating(Integer rating) {
        this.rating = rating;
    }

    /**
     * Gets the location of this Cd.
     * @return the location
     */
    public Location getLocation() {
        return this.location;
    }

    /**
     * Sets the location of this Cd to the specified value.
     * @param location the new location
     */
    public void setLocation(Location location) {
        this.location = location;
    }

    /**
     * Returns a hash code value for the object.  This implementation computes
     * a hash code value based on the id fields in this object.
     * @return a hash code value for this object.
     */
    @Override
    public int hashCode() {
        int hash = 0;
        hash += (this.cdId != null ? this.cdId.hashCode() : 0);
        return hash;
    }

    /**
     * Determines whether another object is equal to this Cd.  The result is
     * <code>true</code> if and only if the argument is not null and is a Cd object that
     * has the same id field values as this object.
     * @param object the reference object with which to compare
     * @return <code>true</code> if this object is the same as the argument;
     * <code>false</code> otherwise.
     */
    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Cd)) {
            return false;
        }
        Cd other = (Cd)object;
        if (this.cdId != other.cdId && (this.cdId == null || !this.cdId.equals(other.cdId))) return false;
        return true;
    }

    /**
     * Returns a string representation of the object.  This implementation constructs
     * that representation based on the id fields.
     * @return a string representation of the object.
     */
    @Override
    public String toString() {
        return "mypackage.Cd[cdId=" + cdId + "]";
    }
   
}
代码 1.45:Cd.java
package mypackage;

import java.io.Serializable;
import java.util.Collection;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;

/**
 * Entity class Location
 *
 * @author sang
 */
@Entity
@Table(name = "LOCATION")
@NamedQueries( {
        @NamedQuery(name = "Location.findByLocationId", query = "SELECT l FROM Location l WHERE l.locationId = :locationId"),
        @NamedQuery(name = "Location.findByLocation", query = "SELECT l FROM Location l WHERE l.location = :location")
    })
public class Location implements Serializable {

    @Id
    @Column(name = "LOCATION_ID", nullable = false)
    private Integer locationId;

    @Column(name = "LOCATION")
    private String location;

    @OneToMany(mappedBy = "location")
    private Collection<Cd> cdCollection;
   
    /** Creates a new instance of Location */
    public Location() {
    }

    /**
     * Creates a new instance of Location with the specified values.
     * @param locationId the locationId of the Location
     */
    public Location(Integer locationId) {
        this.locationId = locationId;
    }

    /**
     * Gets the locationId of this Location.
     * @return the locationId
     */
    public Integer getLocationId() {
        return this.locationId;
    }

    /**
     * Sets the locationId of this Location to the specified value.
     * @param locationId the new locationId
     */
    public void setLocationId(Integer locationId) {
        this.locationId = locationId;
    }

    /**
     * Gets the location of this Location.
     * @return the location
     */
    public String getLocation() {
        return this.location;
    }

    /**
     * Sets the location of this Location to the specified value.
     * @param location the new location
     */
    public void setLocation(String location) {
        this.location = location;
    }

    /**
     * Gets the cdCollection of this Location.
     * @return the cdCollection
     */
    public Collection<Cd> getCdCollection() {
        return this.cdCollection;
    }

    /**
     * Sets the cdCollection of this Location to the specified value.
     * @param cdCollection the new cdCollection
     */
    public void setCdCollection(Collection<Cd> cdCollection) {
        this.cdCollection = cdCollection;
    }

    /**
     * Returns a hash code value for the object.  This implementation computes
     * a hash code value based on the id fields in this object.
     * @return a hash code value for this object.
     */
    @Override
    public int hashCode() {
        int hash = 0;
        hash += (this.locationId != null ? this.locationId.hashCode() : 0);
        return hash;
    }

    /**
     * Determines whether another object is equal to this Location.  The result is
     * <code>true</code> if and only if the argument is not null and is a Location object that
     * has the same id field values as this object.
     * @param object the reference object with which to compare
     * @return <code>true</code> if this object is the same as the argument;
     * <code>false</code> otherwise.
     */
    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Location)) {
            return false;
        }
        Location other = (Location)object;
        if (this.locationId != other.locationId && (this.locationId == null || !this.locationId.equals(other.locationId))) return false;
        return true;
    }

    /**
     * Returns a string representation of the object.  This implementation constructs
     * that representation based on the id fields.
     * @return a string representation of the object.
     */
    @Override
    public String toString() {
        return "mypackage.Location[locationId=" + locationId + "]";
    }
   
}
代码 1.46:Location.java

                                                                                                                    返回练习顶部

(1.5)通过实体创建 JavaServer Faces(JSF)页面


在本步骤中,您将通过实体类创建 JSF 页面。这样做将使您能够通过实体对数据库表进行 CRUD(创建、读取、更新和删除)操作。

1. 通过实体类创建 JSF 页面

图 1.50:通过实体类创建 JSF 页面


图 1.51:选择 JSF 从中生成的实体类

图 1.52:生成的 JSF 页面和类

图 1.53:由 NetBeans IDE 生成的文件

2. 学习由 NetBeans IDE 生成的文件
<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>List Cd</title>
    </head>
    <body>
        <f:view>
            <h:messages errorStyle="color: red" infoStyle="color: green" layout="table"/>
            <h1>Listing Cds</h1>
            <h:form>
                <h:commandLink action="#{cd.createSetup}" value="New Cd"/>
                <br>
                <a href="/CDLibrary/index.jsp">Back to index</a>
                <br>
                <h:outputText value="Item #{cd.firstItem + 1}..#{cd.lastItem} of #{cd.itemCount}"/> 
                <h:commandLink action="#{cd.prev}" value="Previous #{cd.batchSize}" rendered="#{cd.firstItem >= cd.batchSize}"/> 
                <h:commandLink action="#{cd.next}" value="Next #{cd.batchSize}" rendered="#{cd.lastItem + cd.batchSize <= cd.itemCount}"/> 
                <h:commandLink action="#{cd.next}" value="Remaining #{cd.itemCount - cd.lastItem}"
                               rendered="#{cd.lastItem < cd.itemCount && cd.lastItem + cd.batchSize > cd.itemCount}"/>
                <h:dataTable value='#{cd.cds}' var='item' border="1" cellpadding="2" cellspacing="0">
                    <h:column>
                        <f:facet name="header">
                            <h:outputText value="CdId"/>
                        </f:facet>
                        <h:commandLink action="#{cd.detailSetup}" value="#{item.cdId}"/>
                    </h:column>
                    <h:column>
                        <f:facet name="header">
                            <h:outputText value="Title"/>
                        </f:facet>
                        <h:outputText value="#{item.title}"/>
                    </h:column>
                    <h:column>
                        <f:facet name="header">
                            <h:outputText value="Author"/>
                        </f:facet>
                        <h:outputText value="#{item.author}"/>
                    </h:column>
                    <h:column>
                        <f:facet name="header">
                            <h:outputText value="YearCreated"/>
                        </f:facet>
                        <h:outputText value="#{item.yearCreated}"/>
                    </h:column>
                    <h:column>
                        <f:facet name="header">
                            <h:outputText value="Rating"/>
                        </f:facet>
                        <h:outputText value="#{item.rating}"/>
                    </h:column>
                    <h:column>
                        <f:facet name="header">
                            <h:outputText value="Location"/>
                        </f:facet>
                        <h:outputText value="#{item.location}"/>
                    </h:column>
                    <h:column>
                        <h:commandLink value="Destroy" action="#{cd.destroy}">
                            <f:param name="cdId" value="#{item.cdId}"/>
                        </h:commandLink>
                        <h:outputText value=" "/>
                        <h:commandLink value="Edit" action="#{cd.editSetup}">
                            <f:param name="cdId" value="#{item.cdId}"/>
                        </h:commandLink>
                    </h:column>
                </h:dataTable>
            </h:form>
        </f:view>
    </body>
</html>
代码 1.54:List.jsp

                                                                                                                    返回练习顶部

(1.6) 生成和运行应用程序


1. 右键单击 CDLibrary 并选择 运行项目
2. 注意到出现了浏览器。
3. 单击 List of Cd 链接


图 1.60:单击 List of Cd.

4. 注意到显示出 Listing Cds 。(如下图 1.61 所示)
5. 单击 New Cd


图 1.61:Listing Cds

6. 注意到显示出 New Cd 页面。
7. 向文本字段中输入 new Cd 的值并单击 Create。 (如下图 1.62 所示)


图 1.62:创建一个 new cd

8. 注意到 Listing Cds 中现在包含了新创建的 Cd。(如图 1.63 所示)


图 1.63:新 Cd 将出现在清单中

9. 在 NetBeans 中选择 运行时选项卡,右键单击 下的 CD 并选择 查看数据
10. 注意到新行添加了进来。(如图 1.64 所示)


图 1.64:显示数据库表

                                                                                                                    返回练习顶部

解决方案


针对此练习的解决方案作为可运行的 NetBeans 项目包含在动手实验室的压缩文件中。您可以打开并运行它。 如果您在进行此练习时遇到了一个不显发现的问题,请打开并运行 CDLibrary 项目一探究竟。   在运行该项目前,您仍要启动并填充该数据库表,如以下步骤 3.1 所述。

结束语


在本练习中,您了解了如何使用 NetBeans 通过现有的数据库表创建实体。您了解了如何通过实体使用 JavaServer Faces(JSF)页面对数据库表执行基于 web 的 CRUD(创建、读取、更新和删除)操作。


                                                                                                                    返回顶部



练习 2:练习 JPA 的继承 O/R 映射


在此练习中,您将练习两个继承策略 SINGLE_TABLEJOINED。 在 SINGLE_TABLE 策略中,每个类层次创建一个表。 在 JOINED 策略中,指定给子类的字段被映射到一个单独的表而不是和父类通用的字段,并执行了一个 join 操作用来将子类实例化。

我们将使用的示例场景是 Person 类,它含有 name 属性和 Student 类,而 Student 类含有 schoolgrade 属性。Student 类是 Person 类的子类。
  1. 隐式使用 "SINGLE_TABLE" 继承策略(缺省)
  2. 显式使用 "SINGLE_TABLE" 继承策略(通过使用标注)
  3. 使用 "JOINED" 继承策略

(2.1)隐式使用 "SINGLE_TABLE" 继承策略(缺省)


在本步骤中,您将使用 SINGLE_TABLE 作为缺省继承策略。 SINGLE_TABLE 策略是缺省策略,意味着在缺少继承策略标注时将使用 SINGLE_TABLE。

1. 创建一个 NetBeans 项目。

1.创建 NetBeans 项目

图 2.10:创建一个新的 NetBeans 项目
2. 为项目创建一个持久性单元。

图 2.13:提供器和数据库

3. 编写 Person 实体类。

图 2.14:名称和位置

4. 向 Person 实体类添加 name 字段
package mypackage;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

/**
 * Entity class Person
 *
 * @author sang
 */
@Entity
public class Person implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    // Add a name field to the Person class
    private String name;
   
    /** Creates a new instance of Person */
    public Person() {
    }

    /**
     * Gets the id of this Person.
     * @return the id
     */
    public Long getId() {
        return this.id;
    }

    /**
     * Sets the id of this Person to the specified value.
     * @param id the new id
     */
    public void setId(Long id) {
        this.id = id;
    }

    /**
     * Returns a hash code value for the object.  This implementation computes
     * a hash code value based on the id fields in this object.
     * @return a hash code value for this object.
     */
    @Override
    public int hashCode() {
        int hash = 0;
        hash += (this.id != null ? this.id.hashCode() : 0);
        return hash;
    }

    /**
     * Determines whether another object is equal to this Person.  The result is
     * <code>true</code> if and only if the argument is not null and is a Person object that
     * has the same id field values as this object.
     * @param object the reference object with which to compare
     * @return <code>true</code> if this object is the same as the argument;
     * <code>false</code> otherwise.
     */
    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Person)) {
            return false;
        }
        Person other = (Person)object;
        if (this.id != other.id && (this.id == null || !this.id.equals(other.id))) return false;
        return true;
    }

    /**
     * Returns a string representation of the object.  This implementation constructs
     * that representation based on the id fields.
     * @return a string representation of the object.
     */
    @Override
    public String toString() {
        return "mypackage.Person[id=" + id + "]";
    }
   
}
代码 2.15:经过修改的 Person.java

5. 创建 name 字段的 getter 和 setter(访问器)方法。

图 2.16:封装字段重构

图 2.17:确认重构
6. 通过扩展 Person 实体类编写 Student 实体类。

图 2.18:Student Java 类
package mypackage;

/**
 *
 * @author sang
 */
@Entity
public class Student extends Person{
   
    /** Creates a new instance of Student */
    public Student() {
    }
   
}
代码 2.19:经过修改的 Student.java

7. 对 Student.java 完成 "修复导入"。(如果按 CTRL+空格键启用了代码完成功能,则不需要执行此步骤,因为 NetBeans 将自动添加导入。)
图 2.20:修复导入

图 2.21:修复导入

8. 向 Student.java 中添加 schoolgrade 字段
package mypackage;

import javax.persistence.Entity;

/**
 *
 * @author sang
 */
@Entity
public class Student extends Person{

    String school;
    double grade;
   
    /** Creates a new instance of Student */
    public Student() {
    }
   
}
代码 2.22:向 Student.java 中添加字段

9. 创建 school 和 grade 字段的 getter 和 setter 方法

图 2.23:封装 school 和 grade 字段
10. 通过实体类生成 JavaServer Faces(JSF)页面

图 2.24:为生成 JSF 页面选择实体类

图 2.25:生成的 JSF 页和类

11. 生成和运行应用程序

图 2.26:要显示的首页


故障排除 解决方案:如果出现以下错误条件,请右键单击 ORInheritanceSINGLE_TABLE 项目节点并选择 消除和编译项目,然后选择 运行项目



故障排除 解决方案:如果出现以下错误条件,请右键单击 ORInheritanceSINGLE_TABLE 项目节点并选择 消除和编译项目,然后选择 运行项目





12. 创建 Person 持久性实例。

图 2.27:单击 New Person

图 2.28:创建一个新 Person

图 2.29:创建了一个 person 实例

13. 创建 Student 持久性

图 2.30:单击 List of Student。

图 2.31:创建新 Student。

图 2.32:创建一个 student

图 2.33:Listing Students。

图 2.34:创建第二个 student

图 2.35:Listing Students

10. 验证创建的数据库表

在此步骤中,您将验证创建的数据库表。由于缺省策略是 SINGLE_TABLE,PERSON 数据库表应为唯一生成的表并且它应包含 Person 和 Student 实体类的所有字段 —— name、school 和 grade。

图 2.37:PERSON 数据库表
                                                                                                                        返回练习顶部

(2.2)显式使用 SINGLE_TABLE 作为继承策略


在本步骤中,您将通过显式指定 SINGLE_TABLE 策略来使用它。  运行该应用程序应和您在练习 4.1 中看到的一样,因为 SINGLE_TABLE 策略是缺省设置。

1. 根据代码 2.20 修改 Person.java 显式指定 SINGLE_TABLE 策略。 需要添加的代码段突出显示为 蓝色粗 体。 这样做是为了显式指定 SINGLE_TABLE 作为继承策略。

package mypackage;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

/**
 * Entity class Person
 *
 * @author sang
 */
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public class Person implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
   
    // Add a name field to the Person class
    private String name;
   
    /** Creates a new instance of Person */
    public Person() {
    }

    /**
     * Gets the id of this Person.
     * @return the id
     */
    public Long getId() {
        return this.id;
    }

    /**
     * Sets the id of this Person to the specified value.
     * @param id the new id
     */
    public void setId(Long id) {
        this.id = id;
    }

    /**
     * Returns a hash code value for the object.  This implementation computes
     * a hash code value based on the id fields in this object.
     * @return a hash code value for this object.
     */
    @Override
    public int hashCode() {
        int hash = 0;
        hash += (this.id != null ? this.id.hashCode() : 0);
        return hash;
    }

    /**
     * Determines whether another object is equal to this Person.  The result is
     * <code>true</code> if and only if the argument is not null and is a Person object that
     * has the same id field values as this object.
     * @param object the reference object with which to compare
     * @return <code>true</code> if this object is the same as the argument;
     * <code>false</code> otherwise.
     */
    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Person)) {
            return false;
        }
        Person other = (Person)object;
        if (this.id != other.id && (this.id == null || !this.id.equals(other.id))) return false;
        return true;
    }

    /**
     * Returns a string representation of the object.  This implementation constructs
     * that representation based on the id fields.
     * @return a string representation of the object.
     */
    @Override
    public String toString() {
        return "mypackage.Person[id=" + id + "]";
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
   
}
代码 2.20:显式使用 SINGLE_TABLE 策略


<NetBeans Tip>您也许想要利用 NetBeans IDE 在标注上的代码补全功能。

图 2.21:@Inheritance 上的代码补全

图 2.22:strategy= 上的代码实例

图 2.23:SINGLE_TABLE 上的代码补全


2. 右键单击新添加的行并选择 修复导入。(如果按 CTRL+空格键启用了代码完成功能,则不需要执行此步骤,因为 NetBeans 将自动添加导入。) 3. 查看 SINGLE_TABLE 继承策略的 JavaDoc。

图 2.25:显示 Javadoc

图 2.26:SINGLE_TABLE 和 JOINED 的 Javadoc

4. 运行应用程序
4. 验证创建的数据库表。
6. 右键单击 PERSON 数据库表并选择 删除。 (这样做是为了接下来的练习。)

                                                                                                                        返回练习顶部


(2.3)显式使用 JOINED 继承策略


在本步骤中,您将使用 JOINED 继承策略。 您将遵循与以上步骤 4.2 相似的步骤。 仅仅是为了避免混淆,我们将这两个类命名为 Person2 和 Student2。

在 JOINED 策略中,指定给子类的字段被映射到一个单独的表中而不是与其父类通用的字段中,并且执行 join 操作来将子类实例化。

1. 创建一个 NetBeans 项目。(与上面的步骤 4.2 相同) 2. 为项目创建一个持久性单元。(与上面的步骤 4.2 相同) 3. 编写 Person2 实体类。(与上面的步骤 4.2 相同) 4. 将 name 添加到 Person2 实体类中。(与上面的步骤 4.2 相同) 5. 通过扩展 Person2 实体类编写 Student2 实体类。
package mypacakge;

/**
 *
 * @author sang
 */
@Entity
public class Student2 extends Person2 {
   
    /** Creates a new instance of Student2 */
    public Student2() {
    }
   
}
代码 2.62:经过修改的 Student2.java

6. 对 Student2.java 运行 "修复导入"。 (如果按 CTRL+空格键启用了代码完成功能,则不需要执行此步骤,因为 NetBeans 将自动添加导入。)
7. 将 schoolgrade 字段添加到 Student2.java
package mypacakge;

import javax.persistence.Entity;

/**
 *
 * @author sang
 */
@Entity
public class Student2 extends Person2 {
   
    String school;
    double grade;
   
    /** Creates a new instance of Student2 */
    public Student2() {
    }
   
}
代码 2.63:经过修改的 Student2.java
8. 使用 JOINED 继承策略。
package mypacakge;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

/**
 * Entity class Person2
 *
 * @author sang
 */
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public class Person2 implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
   
    private String name;
   
    /** Creates a new instance of Person2 */
    public Person2() {
    }

    /**
     * Gets the id of this Person2.
     * @return the id
     */
    public Long getId() {
        return this.id;
    }

    /**
     * Sets the id of this Person2 to the specified value.
     * @param id the new id
     */
    public void setId(Long id) {
        this.id = id;
    }

    /**
     * Returns a hash code value for the object.  This implementation computes
     * a hash code value based on the id fields in this object.
     * @return a hash code value for this object.
     */
    @Override
    public int hashCode() {
        int hash = 0;
        hash += (this.id != null ? this.id.hashCode() : 0);
        return hash;
    }

    /**
     * Determines whether another object is equal to this Person2.  The result is
     * <code>true</code> if and only if the argument is not null and is a Person2 object that
     * has the same id field values as this object.
     * @param object the reference object with which to compare
     * @return <code>true</code> if this object is the same as the argument;
     * <code>false</code> otherwise.
     */
    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Person2)) {
            return false;
        }
        Person2 other = (Person2)object;
        if (this.id != other.id && (this.id == null || !this.id.equals(other.id))) return false;
        return true;
    }

    /**
     * Returns a string representation of the object.  This implementation constructs
     * that representation based on the id fields.
     * @return a string representation of the object.
     */
    @Override
    public String toString() {
        return "mypacakge.Person2[id=" + id + "]";
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
   
}
代码 2.64:使用 JOINED 继承策略

9. 通过实体类创建 JavaServer Faces(JSF)页面
10. 运行应用程序
11. 验证创建的数据库表。

在本步骤中,您将验证创建的数据库表。在 JOINED 策略中,应有两张表,PERSON 表用于维护继承中的通用数据字段,而 STUDENT 表则只用于维护指定给 Student 实体的字段。

图 2.65:PERSON2 表

图 2.66:SCHOOL2 表

                                                                                                          返回练习顶部

解决方案


此练习的解决方案被作为一个现成的 NetBeans 项目提供于动手实验室的压缩文件中。
                                                                                                                     

结束语


在本练习中,您了解了如何使用继承策略以及数据库表是如何被相应创建的。您了解到在 SINGLE_TABLE 策略中,单个表是为类层次而创建。 

                                                                                                                    返回顶部


课外练习(针对 Sang Shin“Java EE 编程在线课程”的学习者)


1. 课外练习是要按以下描述修改 ORInheritanceJOINED 项目。  (可以通过复制 ORInheritanceJOINED 项目来创建一个新项目。 您可以以任意形式为课外练习项目命名,但此处我将称其为 MyORInheritanceJOINED。)

2. 将以下文件 J2EEHomework-javaee5basics
作为 发送主题 发送至 j2eehomeworks@sun.com



原文链接: http://www.javapassion.com/handsonlabs/jsfjpa/