在 Web 应用程序中使用 Hibernate
在本教程中,您将使用 NetBeans IDE 创建和部署显示数据库中数据的 Web 应用程序。该 Web 应用程序使用 Hibernate 框架作为持久层,用于检索简单传统 Java 对象(POJO)并将其存储到关系数据库中。
Hibernate 是一个为对象关系映射 (ORM) 提供工具的框架。本教程演示如何将 Hibernate 框架支持添加到 IDE 中并创建必要的 Hibernate 文件。创建 Java 对象并将应用程序配置为使用 Hibernate 之后,向 Web 页中添加 Visual Web JSF 组件以显示数据。
开始学习本教程前,您需要先熟悉一下如何使用 Hibernate。
目录

要学习本教程,您需要具备以下软件和资源。
创建数据库
本教程使用一个名为 sakila 的 MySQL 数据库,这是一个免费的 MySQL 数据库,可从 MySQL 网站获得。安装 IDE 时并未包含 sakila 数据库,因此首先需要创建该数据库,以继续学习本教程。
要创建 sakila 数据库,可使用“插件”管理器下载并安装“Sakila 样例数据库”插件。安装该插件后,sakila 数据库即被添加到“创建 MySQL 数据库”对话框的数据库列表中。
有关配置 IDE 使用 MySQL 的更多信息,请参见连接到 MySQL 数据库教程。
- 打开“插件”管理器并安装“Sakila 样例数据库”插件。
- 安装插件后,在“服务”窗口展开“数据库”节点以启动 MySQL 数据库,右键单击“MySQL 服务器”节点并选择“启动”。
- 右键单击“MySQL 服务器”节点并选择“创建数据库”。
- 在“创建 MySQL”对话框的“新数据库名称”下拉列表中选择 Sakila 数据库。单击“确定”。
单击“确定”,“MySQL 服务器”节点下将出现一个 Sakila 节点。
- 右键单击 Sakila 节点并选择“连接”。
单击“连接”,Sakila 数据库(jdbc:mysql://localhost:3306/sakila [username on Default])的数据库连接节点将列示于“数据库”节点下方。打开连接时,可通过展开该连接节点查看数据库中数据。
创建 Web 应用程序项目
在本练习中,您将创建一个 Web 应用程序项目并为该项目添加 Hibernate 库。 创建该项目时,请在“新建项目”向导的“框架”面板中选择 Hibernate,并指定数据库。
- 选择“文件”>“新建项目”(Ctrl-Shift-N)。从 "Java Web" 类别中选择“Web 应用程序”并单击“下一步”。
- 键入 DVDStore 作为项目名称,并设置项目位置。
- 取消选中“使用专用的文件夹来存储库”选项(如果该选项处于选中状态)。
在本教程中,没理由将项目库复制到一个专用文件夹中,因为您不需要和其他用户一起共享库。
单击“下一步”。
- 将服务器设置为 Apache Tomcat 6.0.18 并将 Java EE 版本设置为 Java EE 5。 单击“下一步”。
- 选中“Hibernate 3.2.5”复选框。
- 从“数据库连接”下拉列表中选择 sakila 数据库。单击“完成”。
注意: 如果向导的“框架”面板中没有 sakila 数据库这一选项,请查看该连接是否列示于“服务”窗口的“数据库”节点下。如果此处没有该连接,则需要创建数据库连接。

单击“完成”,IDE 会创建 Web 应用程序并在编辑器中打开 hibernate.cfg.xml 文件和 index.jsp。
展开“项目”窗口中的“库”节点,可以看到 IDE 已向项目中添加了 Hibernate 库。
修改 Hibernate 配置文件
创建使用 Hibernate 框架的新项目时,IDE 自动在应用程序的上下文类路径的根路径(“文件”窗口中的 Web-INF/classes)上创建 hibernate.cfg.xml 配置文件。该文件位于“项目”窗口的“配置文件”节点下。该配置文件包含有关数据库连接、资源映射和其他连接属性的信息。可使用多视图编辑器编辑文件,或直接在 XML 编辑器中编辑 XML。
在本练习中,您将编辑 hibernate.cfg.xml 中指定的缺省属性,以启用 SQL 语句的调试日志,并启用 Hibernate 会话的上下文管理。
- 在“设计”标签中打开 hibernate.cfg.xml。可以通过展开“项目”窗口的“配置文件”节点并双击 hibernate.cfg.xml 来打开该文件。
- 在“可选属性”下,展开“配置属性”节点。
- 单击“添加”以打开“添加 Hibernate 属性”对话框。
- 在对话框中,选择 hibernate.show_sql 属性并将值设为 true。这样就启用了 SQL 语句的调试日志。

- 展开“其他属性”节点并单击“添加”。
- 在对话框,选择 属性 hibernate.current_session_context_class 并将值设为 thread 以启用 Hibernate 自动的会话上下文管理。
如果单击编辑器中的 XML 标签,则可以在 XML 视图中看到此文件。该文件应该如下所示:
<hibernate-configuration>
<session-factory name="session1">
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/sakila</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">######</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.current_session_context_class">thread</property>
</session-factory>
</hibernate-configuration>
- 保存对该文件所做的更改。
创建 HibernateUtil.java Helper 文件
要使用 Hibernate,您需要创建一个 helper 类,该类处理启动并访问 Hibernate 的 SessionFactory 以获取“会话”对象。该类调用 configure() 并加载 hibernate.cfg.xml 配置文件,然后构建 SessionFactory 以获取“会话”对象。
在本节中,使用“新建文件”向导创建 helper 类 HibernateUtil.java。
- 右键单击“源包”节点并选择“新建”>“其他”,打开“新建文件”向导。
- 从“类别”列表中选择 Hibernate,从“文件类型”列表中选择 HibernateUtil.java。单击“下一步”。
- 键入 HibernateUtil 作为类名,并键入dvdrental 作为包名。单击“完成”。

单击“完成”后,编辑器将打开 HibernateUtil.java。由于不需要编辑该文件,因此可以关闭该文件。
生成 Hibernate 映射文件和 Java 类
在本教程中,您将使用一个 POJO(简单传统 Java 对象)来表示您将要用到的数据库中的每个表中的数据。Java 类指定表的列字段,并使用简单的 setter 和 getter 方法检索数据和写数据。要将该 POJO 映射到表,可使用 Hibernate 映射文件或使用类标注。
可在“数据库”向导中使用“Hibernate 映射文件”和 POJO,创建多个 POJO 和基于选定数据库表的映射文件,或使用 IDE 向导帮助您从头开始单独地创建每个 POJO 和映射文件。
在数据库中创建 Hibernate 映射文件和 POJO
“在数据库中创建 Hibernate 映射文件和 POJO”向导生成基于数据库表的文件。使用该向导时,选择希望从中创建 POJO 和映射文件的所有表,IDE 然后根据该数据库表生成文件并将映射条目添加到 hibernate.cfg.xml。使用向导时可选择希望 IDE 生成的文件(比如,只生成 POJO)并选择代码生成选项(比如,生成使用 EJB 3 标注的代码)
- 在“项目”窗口中右键单击“源包”节点,并选择“新建”>“其他”以打开“新建文件”向导。
- 在 Hibernate 类别的数据库中选择 Hibernate 映射文件和 POJO。单击“下一步”。
- 保留“名称和位置”面板的缺省值。单击“下一步”。
- 在“配置文件”下拉列表中选择 hibernate.cfg.xml(如果尚未选定)。
- 从“可用表”中选择以下表,并单击“添加”将表添加到“选定表”。
- actor
- category
- film
- film_actor
- film_category
- language
单击“下一步”。
- 在“常规设置”选项中选择 JDK 5 语言功能。
- 确保 域代码 和 Hibernate XML 映射 选项为选定项。
- 选择 dvdrental 作为包名。单击“完成”。

单击“完成”,IDE 生成 POJO 和 Hibernate 映射文件,其字段映射到选定表的列中。IDE 也添加映射条目到 hibernate.cfg.xml 中。展开 dvdrental 包查看由向导生成的文件。
该向导也生成了一个 hibernate.reveng.xml 逆向工程文件并以编辑器中打开了该文件。可将该逆向工程文件关闭,因为无需对其进行编辑。
创建 Hibernate Helper 类
现在,您将在 dvdrental 包中创建另一个 helper 类,将用于在数据库中执行 Hibernate 查询。您将使用“Hibernate 查询语言(HQL)”编辑器来构造并测试用于检索数据的查询。测试了查询后,将在构造并运行查询的 helper 类中创建方法。随后将从 JSP 文件中调用 helper 类的方法。
创建类
这一部分中,使用“新建文件”向导在 dvdrental 包中创建 helper 类 FilmHelper.java。您将通过调用 HibernateUtil.java 中的 getSessionFactory 来创建一个 Hibernate 会话,并创建一些 helper 方法以创建查询来检索数据库中的数据。将从 JSP 页面中调用这些 helper 方法。
- 右键单击 dvdrental 源包节点,并选择“新建”>“Java 类”以打开“新建文件”向导。
- 键入 FilmHelper 作为类名。单击“完成”。
- 添加以下代码(粗体),创建一个 Hibernate 会话。
public class FilmHelper {
Session session = null;
public FilmHelper() {
this.session = HibernateUtil.getSessionFactory().getCurrentSession();
}
}
- 修复导入并保存更改。
现在将修改 FilmHelper.java 以添加查询数据库的 helper 方法。
使用 HQL 查询枚举 Film 标题
在此练习中,您将创建一个 HQL 查询,该查询对数据库进行查询以检索基于 filmid 主键的记录。您将使用 Hibernate 查询语言(HQL)来查询数据库中的记录。Sakila 数据库中的 Film 表有 1000 条记录,因而我们创建的方法应能够检索基于 filmid 主键的记录。
- 在“项目”窗口中右键单击 hibernate.cfg.xml 并选择“运行 HQL 查询”以打开 HQL 查询编辑器。
- 从工具栏的下拉列表中选择 hibernate.cfg。
- 在编辑器中键入以下内容并单击工具栏中的“运行 HQL 查询”按钮(
)来测试该连接。
from Film
单击“运行 HQL 查询”可在 HQL 查询编辑器的 botton 窗口看到查询结果。
如果单击 SQL 按钮,可以看到起相同作用的 SQL 查询。
select film0_.film_id as col_0_0_ from sakila.film film0_
- 键入以下查询在 film id 为 100 到 200 的 Film 表中检索记录。
from Film as film where film.filmID between 100 and 200
结果窗口中显示了一个记录列表。测试过该查询可返回期待的结果后,可在 helper 类中使用该查询。
- 将以下方法添加到 FilmHelper.java 以检索 film,其中 film id 介于由变量 startID 和 endID 所指定的特定范围之间。
public List getFilmTitles(int startID, int endID) {
List<Film> filmList = null;
try {
org.hibernate.Transaction tx = session.beginTransaction();
Query q = session.createQuery ("from Film as film where film.filmId between '"+startID+"' and '"+endID+"'");
filmList = (List<Film>) q.list();
} catch (Exception e) {
e.printStackTrace();
}
return filmList;
}
- 修复导入并保存更改。
修复导入时,要选择 java.util.List 和 org.hibernate.Query.
枚举 Actors (使用 HQL Sub 查询)
在最后一个节中,您将创建一个简单的 HQL 查询以枚举记录。现在要使用 sub 查询查询多个表,获取参与一个特定 film 的 actor。然后要将一个方法添加到 helper 类,该类包含一个 sub 查询用于从 actor 表和 film_actor 表中获取记录。
- 在 HQL 查询编辑器中键入以下查询以测试该查询。
from Actor as actor where actor.actorID in (select actorID from FilmActor filmActor where filmActor.filmId=10
此查询检索 film 中 filmid=10 的 actor。.
- 现在可以创建一个使用 filmID 作为输入变量构造查询的方法 getActorsByID。
public List getActorsByID(int filmId){
List<Actor> actorList = null;
try {
org.hibernate.Transaction tx = session.beginTransaction();
Query q = session.createQuery ("from Actor as actor where actor.actorID in (select actorID from FilmActor filmActor where filmActor.filmID='"+filmId+"')");
actorList = (List<Actor>) q.list();
} catch (Exception e) {
e.printStackTrace();
}
return actorList;
}
添加额外的 helper 方法
现在将添加一些额外的 helper 方法,创建基于输入变量的查询。可在 HQL 查询编辑器中检查这些查询。
- 添加以下方法以根据 filmId 检索类别列表。
public Category getCategoryByID(int filmId){
List<Category> categoryList = null;
try {
org.hibernate.Transaction tx = session.beginTransaction();
Query q = session.createQuery ("from Category as category where category.categoryID in (select categoryID from FilmCategory filmCat where filmCat.filmID='"+filmId+"')");
categoryList = (List<Category>) q.list();
} catch (Exception e) {
e.printStackTrace();
}
return categoryList.get(0);
}
- 添加以下方法以根据 filmId 检索 film 列表。
public Film getFilmByID(int filmId){
Film film = null;
List<Film> filmList = null;
try {
org.hibernate.Transaction tx = session.beginTransaction();
Query q = session.createQuery ("from Film as film where film.filmID='"+filmId+"'");
filmList = (List<Film>) q.list();
film = (Film) filmList.get(0);
} catch (Exception e) {
e.printStackTrace();
}
return film;
}
- 添加以下方法以根据 langID 检索语言列表。
public String getLangByID(int langID){
String language = null;
List<Language> langList = null;
try {
org.hibernate.Transaction tx = session.beginTransaction();
Query q = session.createQuery ("from Language as lang where lang.languageID='"+langID+"'");
langList = (List<Language>) q.list();
language = ((Language) langList.get(0)).getLanguage();
} catch (Exception e) {
e.printStackTrace();
}
return language;
}
现在,您已经为应用程序创建了所有类。下一步,您将创建 JSP 页面并调用 FilmHelper.java 中的 helper 方法。
创建 Web 页面
创建类之后,可以创建用于显示和修改数据的 Web 页。将修改 index.jsp 以列示 film 并创建 browse.jsp 以显示选定 film 的详情。
修改 index.jsp
- 展开“项目”窗口的“Web 页面文件夹”并在编辑器中打开 index.jsp。
- 将以下导入标签(粗体)添加到 JSP 页面以加载所需 Java 类。
<%@page import="dvdrental.*"%>
<%@page import="java.util.List"%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
- 在 body 标签中间添加以下内容(粗体)。
<body>
<%
int startID = 1;
int endID = 10;
int prev_startID =1;
int prev_endID = 10;
int FILM_RECORD_COUNT = 1000;
boolean RECORD_START_PAGE = false;
boolean RECORD_END_PAGE = false;
if (request.getParameter("startid") != null) {
startID = Integer.parseInt(request.getParameter("startid"));
}
if (request.getParameter("endid") != null) {
endID = Integer.parseInt(request.getParameter("endid"));
}
FilmHelper helper = new FilmHelper();
List filmTitles = helper.getFilmTitles(startID,endID);
if(startID == 1){
RECORD_START_PAGE = true;
}
if(endID == FILM_RECORD_COUNT){
RECORD_END_PAGE = true;
}
prev_startID = startID-10;
prev_endID = endID-10;
startID = endID+1;
endID = endID+10;
int filmTitlesSize = filmTitles.size();
%>
</body>
- 添加以下内容(粗体)以生成表来显示检索到的条目。
int filmTitlesSize = filmTitles.size();
out.print("<table>");
if(RECORD_START_PAGE){
out.print("<tr><td class='NEXT'> </td><td class='NEXT'> </td><td class='NEXT'> </td><td class='NEXT'><a class='RENT' href=\"index.jsp?startid="+startID+"&endid="+endID+"\">Next</a></td></tr>");
}
else if(RECORD_END_PAGE){
out.print("<tr><td class='NEXT'> </td><td class='NEXT'> </td><td class='NEXT'><a class='NEXT' href=\"index.jsp?startid="+prev_startID+"&endid="+prev_endID+"\">Prev</a></td><td class='NEXT'> </td></tr>");
}else{
out.print("<tr><td class='NEXT'> </td><td class='NEXT'> </td><td class='NEXT'><a class='NEXT' href=\"index.jsp?startid="+prev_startID+"&endid="+prev_endID+"\">Prev</a></td><td class='NEXT'><a class='NEXT' href=\"index.jsp?startid="+startID+"&endid="+endID+"\">Next</a></td></tr>");
}
out.print("<tr><th>Title</th><th>Description</th><th> </th><th> </th></tr>");
for (int i = 0; i < filmTitlesSize; i++) {
Film film = (Film) filmTitles.get(i);
int filmID = film.getFilmId();
out.print("<tr>");
out.print("<td class='COL1'><a href=\"browse.jsp?id=" + filmID + "\">" + film.getTitle() + "</a></td>");
out.print("<td class='COL2'>" + film.getDescription() + "</td>");
out.print("<td class='COL2'><a href=\"browse.jsp?id=" + filmID + "\">More</a></td>");
out.print("<td class='COL2'><a href=\"rent.jsp?id=" + filmID + "\">Rent</a></td>");
out.print("</tr>");
}
out.print("</table>");
%>
</body>
- 保存所做的更改。
现在,您的 Web 页已具备了必要的组件。现在,需要将这些组件绑定到数据源。
创建 browse.jsp
现在需要创建一个 JSP 页面用来浏览详情。
- 在“项目”窗口中右键单击 DVDStore 并选择“新建 New > JSP”。
- 键入 browse 作为 JSP 文件名。
- 单击“完成”。
单击“完成”,编辑器中打开了文件 browse.jsp。
- 将导入标签(粗体)添加到 JSP 页面。
<%@page import="dvdrental.*"%>
<%@page import="java.util.List"%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
- 添加以下代码(粗体)获取标题 Id。
<body>
<%
//Get title ID
int filmID = 1;
if (request.getParameter("id") != null) {
filmID = Integer.parseInt(request.getParameter("id"));
}
%>
</body>
- 添加以下代码(粗体)调用类方法。
filmID = Integer.parseInt(request.getParameter("id"));
}
%>
<%
boolean startPage = false;
boolean endPage = false;
FilmHelper helper = new FilmHelper();
Film film = helper.getFilmByID(filmID);
String filmTitle = film.getTitle();
String filmDescription = film.getDescription();
//Get Actors
List actors = helper.getActorsByID(filmID);
StringBuffer totalCast = new StringBuffer();
//Get Category
Category category = helper.getCategoryByID(filmID);
String catName = category.getName();
for(int i=0;i<actors.size();i++){
Actor actor = (Actor)actors.get(i);
totalCast.append(actor.getFirstName());
totalCast.append(" ");
totalCast.append(actor.getLastName());
totalCast.append(" ");
}
int langID = film.getLanguageID();
String language = helper.getLangByID(langID);
int filmLength = film.getLength();
String filmRating = film.getRating();
String filmYear = film.getReleaseYear();
int rentalDuration = film.getRentalDuration().intValue();
float rentalRate = film.getRentalRate().floatValue();
String specialFeatures = film.getSpecialFeatures();
%>
</body>
- 添加以下代码(粗体)以生成显示 film 数据的表。
String specialFeatures = film.getSpecialFeatures();
out.print("<table>");
out.print("<tr><td class='RENT'> </td><td class='RENT'><a class='RENT' href=\"browse.jsp?id="+filmID+"\">Rent Out</a></td></tr>");
out.print("<tr><td class='TITLE'>Title</td><td class='TITLE'>" + filmTitle + "</td></tr>");
out.print("<tr><td class='COL1'>Description</td><td class='COL2'>" + filmDescription + "</td></tr>");
out.print("<tr><td class='COL1'> </td><td class='COL2'> </td></tr>");
out.print("<tr><td class='COL1'>Genre</td><td class='COL2'>" + catName + "</td></tr>");
out.print("<tr><td class='COL1'> </td><td class='COL2'> </td></tr>");
out.print("<tr><td class='COL1'>Cast</td><td class='COL2'>" + totalCast.toString() + "</td></tr>");
out.print("<tr><td class='COL1'> </td><td class='COL2'> </td></tr>");
out.print("<tr><td class='COL1'>Movie Length</td><td class='COL2'>" + filmLength + " mins</td></tr>");
out.print("<tr><td class='COL1'>Language</td><td class='COL2'>" + language + "</td></tr>");
out.print("<tr><td class='COL1'>Movie Rating</td><td class='COL2'>" + filmRating + "</td></tr>");
out.print("<tr><td class='COL1'>Released On</td><td class='COL2'>" + filmYear + "</td></tr>");
out.print("<tr><td class='COL1'> </td><td class='COL2'> </td></tr>");
out.print("<tr><td class='COL1'>Special Features</td><td class='SPECIAL'>" + specialFeatures + "</td></tr>");
out.print("<tr><td class='COL1'> </td><td class='COL2'> </td></tr>");
out.print("<tr><td class='COL1'>Rental Rate</td><td class='COL2'>" + rentalRate + " US$</td></tr>");
out.print("<tr><td class='COL1'>Rental Duration</td><td class='COL2'>" + rentalDuration + " days</td></tr>");
out.print("</table>");
%>
</body>
运行项目
- 在主工具栏中单击“运行主项目”或在“项目”窗口中右键单击 DVDStore 应用程序并选择“运行”。
IDE 保存所有更改过的文件,构建应用程序并将应用程序部署到服务器。 IDE 在浏览器窗口打开以下页面。
http://localhost:8080/DVDStore/
- 在浏览器中,单击 film 名旁边的“更多”以查看更多显示关于该 film 详情的浏览页面。
另请参见