· 配置 Tomcat5.5 站点

n 使用 Struts 实现应用程序 hiber

· 安装 Hibernate

可以从<http://www.hibernate.org>下载最新的 Hibernate 软件包，本实训使用的版本是 3.20。解压缩从 Hibernate 网站下载的 Hibernate 软件包，并把 hibernate3.jar 文件和 lib 目录下所有需要的第三方库文件拷贝到\WEB-INF\lib 目录下。Hibernate 所需的最小库文件集合：

· antlr.jar

· cglib.jar

· asm.jar

· asm-attrs.jars

· commons-collections.jar

· commons-logging.jar

· ehcache.jar

· hibernate3.jar

· jta.jar

· dom4j.jar

· log4j.jar

这些是 Hibernate 运行所需要的最小库文件集合。可能需要比这更多或少一些的库文件。请参见发布包中的 lib 目录下的_README.txt 获取更多信息（事实上，Log4j 并不是必须的库文件，但是比较流行）。

· 创建 Hibernate 配置文件

n 创建 hibernate.cfg.xml 文件。Hibernate 从配置文件中读取和数据库连接有关的信息，这个文件应该放在 classpath 目录下，一般放在 WEB-INF\classes 目录下。完整代码如下：

<!DOCTYPE hibernate-configuration PUBLIC

"-//Hibernate/Hibernate Configuration DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

<session-factory>

<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://127.0.0.1/pizza</property>

<property name="hibernate.connection.username">root</property>

<property name="hibernate.connection.password"></property>

<property name="hibernate.show_sql">true</property>

<mapping resource="jsplession/Customer.hbm.xml"/>

<mapping resource="jsplession/Order.hbm.xml"/>

</session-factory>

</hibernate-configuration>

其中：

(1) <property name="hibernate.show_sql">true</property>，在控制台输出 SQL 语句，有利于跟踪调试，默认为 false。

(2) <mapping resource="jsplession/Customer.hbm.xml"/>，指定 Hibernate 映射文件的位置。实际上，应该在创建每一个 Hibernate 映射文件后，再来修改这个文件添加一条 mapping 元素，我们这里就直接给出了。

· 创建持久化类

从 pizza 网上商店业务模型中，我们抽象出二个需要持久化的类：Customer（客户）和 Order（订单）。

n 创建 Customer.java

1. 包含三个属性 customerId、address 和 name，分别表示数据库中的主键，地址和姓名。按照 Javabean 的编写规范提供 setter 和 getter 方法。

2. 创建二个构造方法：public Customer()和 public Customer(String name, String address)，public Customer()是必须的。

package jsplession;

import java.io.Serializable;

import org.apache.commons.lang.builder.ToStringBuilder;

public class Customer implements Serializable {

private Integer customerId;

private String address;

private String name;

public Customer() {

}

public Customer(String name, String address) {

this.name = name;

this.address = address;

}

public Integer getCustomerId() {

return this.customerId;

}

public void setCustomerId(Integer customerId) {

this.customerId = customerId;

}

public String getAddress() {

return this.address;

}

public void setAddress(String address) {

this.address = address;

}

public String getName() {

return this.name;

}

public void setName(String name) {

this.name = name;

}

}

n 创建 Order.java

1. 包含五个属性 orderId、Customer、delivery、size 和 topping，分别表示数据库中的主键，订单所属客户、订单类型、尺寸和浇汁（Set 类型，存储 String 类型的数据）。按照 Javabean 的编写规范提供 setter 和 getter 方法。

2. 创建二个构造方法：public Order()和 public Order(String delivery, String size, Customer customer)，public Order()是必须的。

package jsplession;

import java.io.Serializable;

import java.util.HashSet;

import java.util.Set;

public class Order implements Serializable {

private Integer orderId;

private Customer customer;

private String delivery;

private String size;

private Set topping = new HashSet();

public Order() {

}

public Order(String delivery, String size, Customer customer) {

this.delivery = delivery;

this.size = size;

this.customer=customer;

}

public Integer getOrderId() {

return this.orderId;

}

public void setOrderId(Integer orderId) {

this.orderId = orderId;

}

public String getDelivery() {

return this.delivery;

}

public void setDelivery(String delivery) {

this.delivery = delivery;

}

public String getSize() {

return this.size;

}

public void setSize(String size) {

this.size = size;

}

public Set getTopping() {

return topping;

}

public void setTopping(Set topping) {

this.topping = topping;

}

public Customer getCustomer() {

return customer;

}

public void setCustomer(Customer customer) {

this.customer = customer;

}

}

· 创建对象-关系映射文件

n 创建 Customer.hbm.xml，实现 Customer 类和数据库中 Customer 表的映射关系，完整代码如下：

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

<class

name="jsplession.Customer"

table="customer"

lazy="false"

>

<id

name="customerId"

type="integer"

column="customer_id"

length="11"

>

<generator class="identity" />

</id>

<property

name="address"

type="string"

column="address"

not-null="true"

length="65535"

/>

<property

name="name"

type="string"

column="name"

not-null="true"

length="50"

/>

</class>

</hibernate-mapping>

其中：

· <class name="jsplession.Customer" table="customer" lazy="false">，指明是 Customer 类和 customer 表之间的映射。

· <id name="customerId" type="integer" column="customer_id" length="11"><generator class="identity" /></id>，

(1) <id>标签，指明 customerId 属性代表 customer 表的主键 customer_id，

(2) <generator class="identity" />，主键的生成方式是"identity"，即自动增长类型，本例是 Mysql 的 Auto_increment 实现的自动增长类型。

· <property name="name" type="string" column="name" not-null="true" length="50"/>，指明 name 属性和 customer 表的 name 字段相对应，且不能为空。

n 创建 Order.hbm.xml，实现 Order 类和数据库中 order 表的映射关系，完整代码如下：

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

<class

name="jsplession.Order"

table="pizza.order"

lazy="false"

>

<id

name="orderId"

type="integer"

column="order_id"

length="11"

>

<generator class="identity" />

</id>

<many-to-one name="customer" class="jsplession.Customer" column="customer_id" not-null="true"/>

<property

name="delivery"

type="string"

column="delivery"

length="13"

/>

<property

name="size"

type="string"

column="size"

length="6"

/>

<set name="topping" table="topping" cascade="save-update">

<key>

<column name="order_id"/>

</key>

<element column="topping" type="string"/>

</set>

</class>

</hibernate-mapping>

其中：

· <many-to-one name="customer" class="jsplession.Customer" column="customer_id" not-null="true"/>：

(1) 建立 Order 类和 Customer 类之间多对一的关系（域对象之间的关系）。

(2) column="customer_id"，表明这种多对一的关系是通过 Order 表的外键 customer_id 指向 Customer 表的主键来实现的。

· <set name="topping" table="topping" cascade="save-update"><key><column name="order_id"/></key><element column="topping" type="string"/></set>：

(1) <set name="topping">标签，表示 Order 类的 topping 属性是一个集合元素 Set，

(2) table="topping"，指明集合中的元素存储在表 topping 中。

(3) cascade="save-update"，表示存储或修改 Order 数据时，级联存储或修改集合 topping 中的元素。

(4) <key><column name="order_id"/></key>，表明集合关系通过 order_id 字段指向 Order 表的主键来实现。

(5) <element column="topping" type="string"/>，集合里的元素类型是值类型 string，存储在 topping 字段。

· 通过 Hibernate API 实现持久化

n 创建 public class HibernateUtil，我们通过这个类来创建 Hibernate 编程需要的 SessionFactory 对象。使用了 Singleton（单态）模式。

package jsplession;

import org.hibernate.*;

import org.hibernate.cfg.*;

public class HibernateUtil {

private static final SessionFactory sessionFactory;

static {

try {

sessionFactory = new Configuration().configure()

.buildSessionFactory();

} catch (Throwable ex) {

System.err.println("Initial SessionFactory creation failed." + ex);

throw new ExceptionInInitializerError(ex);

}

}

public static SessionFactory getSessionFactory() {

return sessionFactory;

}

}

n 创建 public final class ProcessActionHibernate extends Action，一个 Struts 的 action 类，使用 Hibernate 技术持久化客户和订单数据。

package actions;

import java.sql.SQLException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;

import jsplession.Customer;

import jsplession.HibernateUtil;

import jsplession.Order;

import org.apache.struts.action.Action;

import org.apache.struts.action.ActionForm;

import org.apache.struts.action.ActionForward;

import org.apache.struts.action.ActionMapping;

import org.apache.struts.validator.DynaValidatorForm;

import org.hibernate.Session;

public final class ProcessActionHibernate extends Action {

public ActionForward execute(ActionMapping mapping, ActionForm form,

HttpServletRequest request, HttpServletResponse response)

throws SQLException {

DynaValidatorForm dynaForm = (DynaValidatorForm) form;

String name = (String) dynaForm.get("name");

String address = (String) dynaForm.get("address");

String purchaseType = (String) dynaForm.get("purchaseType");

String size = (String) dynaForm.get("size");

String[] topping = (String[]) dynaForm.get("topping");

HttpSession httpSession = request.getSession();

Session hibernateSession=null;

try {

hibernateSession = HibernateUtil.getSessionFactory()

.openSession();

hibernateSession.beginTransaction();

Customer customer = new Customer(name, address);

hibernateSession.save(customer);

Order order = new Order(purchaseType, size, customer);

for (int i = 0; i < topping.length; i++)

order.getTopping().add(topping[i]);

hibernateSession.save(order);

hibernateSession.getTransaction().commit();

} catch (Exception sqle) {

System.out.println("Error dealing with database");

System.out.println("Reason: " + sqle.getMessage());

hibernateSession.getTransaction().rollback();

} finally {

HibernateUtil.getSessionFactory().close();

}

// Add the details to the session so we can show the user

httpSession.setAttribute("name", name);

httpSession.setAttribute("address", address);

httpSession.setAttribute("purchaseType", purchaseType);

httpSession.setAttribute("size", size);

httpSession.setAttribute("topping", topping);

// Remove the obsolete form bean

if (mapping.getAttribute() != null) {

if ("request".equals(mapping.getScope())) {

request.removeAttribute(mapping.getAttribute());

} else {

httpSession.removeAttribute(mapping.getAttribute());

}

}

// Forward control to the specified success URI

return (mapping.findForward("success"));

}

}

加粗部分的代码解释如下：

(1) 定义 Session hibernateSession=null，我们通过 hibernateSession 完成数据的保存工作。

(2) 获得 hibernateSession 的实例，即 hibernateSession = HibernateUtil.getSessionFactory().openSession();

(3) hibernateSession.beginTransaction()，事务开始

(4) 创建 Customer customer = new Customer(name, address);

(5) 把 customer 对象包含的数据保存到数据库中，即 hibernateSession.save(customer)，经过这一步 customer 对象的 customerId 属性不再是 null，而是数据库中相应的主键值。

(6) 然后利用存储后的 customer 对象（customerId 属性不为 null），创建 Order order = new Order(purchaseType, size, customer);

(7) 把 topping[]数组中的数据填充到 order 对象的集合 topping 中，

for (int i = 0; i < topping.length; i++)

order.getTopping().add(topping[i]);

(8) hibernateSession.save(order)。把 order 中的数据保存到数据库中。因为在 Order.hbm.xml 文件中，我们在<set>标签中配置了 cascade="save-update"，因此集合 topping 中的数据也被保存到表 topping 中，不再需要额外的代码，省时省力。

(9) hibernateSession.getTransaction().commit()，提交事务

(10) hibernateSession.getTransaction().rollback()，出现异常则回滚事务

(11) HibernateUtil.getSessionFactory().close()，工作结束关闭 sessionFactory

(12) 补充一下，hibernateSession 和 httpSession 没有任何关系。

n 修改 struts-config.xml，把 ProcessActionHibernate 配置成 Struts 的 Action。

<action-mappings>

<!-- The action mappings -->

<action path="/process" type="actions.ProcessActionHibernate"

name="pizzaForm" scope="session" input="/pizzaStruts.jsp"

validate="true">

</action>

</action-mappings>

· 部署运行

n 部署文件

相对于上个实训的 Struts 应用程序，本次实训增加的文件目录结构如下(lib 目录里 Hibernate 需要的 jar 文件省略)。

\WEB-INF\classes\hibernate.cfg.xml

\WEB-INF\classes\jsplession\Order.class

\WEB-INF\classes\jsplession\Order.hbm.xml

\WEB-INF\classes\jsplession\Customer.class

\WEB-INF\classes\jsplession\Customer.hbm.xml

\WEB-INF\classes\jsplession\HibernateUtil.class

\WEB-INF\classes\action\ProcessActionHibernate.class

n 启动 Tomcat，启动 Mysql

n 在 IE 浏览器的地址栏中输入：<http://localhost:8080/hiber/pizzaStruts.jsp>

n 查看 Tomcat 控制台中 Hibernate 输出的 SQL 语句。