
具体操作步骤:
新建一个WebProject,命名为hibernate,在tomcat安装目录下的conf目录下的server.xml文件中引入其context path(在</host>之前):<Context path="/hibernate" docBase="D:JavaWebhibernateWebRoot" reloadable="true"/> 添加struts依赖的jar包和mysql的驱动一共七个jar文件(commons-fileupload-1.2.1.jar、commons-logging-1.0.4.jar、freemarker-2.3.13.jar、ognl-2.6.11.jar、struts2-core-2.1.6.jar、xwork-core-2.1.2.jar、mysql-connector-java-5.1.34-bin.jar),粘贴到WEB-INF的lib目录下。
选中项目,点击菜单栏的MyEclipse(或右键MyEclipse),选择Project Capabilities->Add Hibernate Capabilities。JAR Library Installation选中Copy checked Library Jars to project folder and add to build-path,为了方便,这里Hibernate规范与风中叶老师的规范一致选择3.2,点击next,弹出Create Hibernate XML configuration file对话框继续next,在Specify Hibernate database connection details对话框中去掉Specify database connection details前面的√,点击next,去掉Create SessionFactory class?前面的√,点击Finish。这样我们的项目依赖的hibernate相关的jar文件就被纳入到项目下面了。
hibernate项目下的src目录下自动生成了一个文件:hibernate.cfg.xml,切换到source视图。 在<session-factory></session-factory>之间添加如下信息:
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<!-- Generated by MyEclipse Hibernate Tools. -->
<hibernate-configuration>
<session-factory>
<property name="show_sql">true</property> <!-- 属性之间没有上下关系,放在哪里都行 -->
<property name="connection.url">jdbc:mysql://localhost:3306/myhibernate</property>
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<mapping resource="Person.hbm.xml"/> <!-- 将主配置文件包含对象-关系映射文件,之所以映射是因为hibernate启动时只会加载主配置文件 -->
</session-factory>
</hibernate-configuration>
由于hibernate可以支持多种数据库,所以其dialect(方言)属性必须配置,可以在Hibernate3.2API文档中找到org.hibernate.dialect这个包下的MySqlDialect类。
接着在MySql中创建数据库Hibernate,新建表:person,字段有:id(主键,int,长度11,非空,注意:不将id设置为自动增加类型,让hibernate为我们做这些,体会hibernate的作用)、username(varchar,长度20,允许空值)、password(varchar,长度20,允许空值)、age(int,长度11,允许空值)、registerdate(datetime,长度0,允许空值)
接着对这张表创建相应的类,即POJO,新建包com.hibernate.model,在该包下建立相应的持久化类:Person.java
package com.hibernate.model;
import java.sql.Date;
public class Person
{
private Integer id; // int也没有问题,但是最好使用其包装类Integer
private String username;
private String password;
private Integer age;
private Date registerdate;
public Integer getId()
{
return id;
}
public void setId(Integer id)
{
this.id = id;
}
public String getUsername()
{
return username;
}
public void setUsername(String username)
{
this.username = username;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
public Integer getAge()
{
return age;
}
public void setAge(Integer age)
{
this.age = age;
}
public Date getRegisterdate()
{
return registerdate;
}
public void setRegisterdate(Date registerdate)
{
this.registerdate = registerdate;
}
}
然后在src目录下对Person.java文件创建一个Hibernate映射文件Person.hbm.xml(hibernate mapping),可将其选中,右键选择Open With->MyEclipse Hibernate Mapping Editor,这样写xml的时候就带提示了。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.hibernate.model.Person" table="person"> <!-- 将类与表相关联,使得类中的属性和表中的字段关联起来 --> <id name="id" column="id" type="int"> <!-- 类中id属性和映射到表中的id字段,类型为int/integer皆可 --> <generator class="increment"> <!-- 主键id的生成方式为自增 --> </generator> </id> <property name="username" column="username" type="string"></property> <!-- 如果不写字段名,则默认与类中的属性名相同 --> <property name="password" column="password" type="string"></property> <property name="age" column="age" type="int"></property> <property name="registerdate" column="registerdate" type="date"></property> </class> </hibernate-mapping>
这样一个类-一张表-一个hbm已经全部创建完成。这个hbm就起到连接类和表的作用
然后,新建包com.hibernate.util,在下面新建类:HibernateUtil.java(可以不写,但是写上的话可以方便我们对后台数据库进行操作):
package com.hibernate.util;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil
{
private static SessionFactory sessionFactory;
static
{
try
{
sessionFactory = new Configuration().configure().buildSessionFactory();
}
catch(Exception ex)
{
System.out.println("构造SessionFactory异常发生:" + ex.getMessage());
}
}
public static Session currentSession()
{
Session session = sessionFactory.openSession();
return session;
}
public static void closeSession(Session session)
{
if(null != session)
{
session.close();
}
}
}
接下来,创建com.hibernate.persister包,在该包下面创建类DBPreson.java,完成增删查改操作:
package com.hibernate.persistence;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.hibernate.model.Person;
import com.hibernate.util.HibernateUtil;
public class DBPerson
{
/**
* 创建新的用户
*/
public static void save(Person person)
{
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction(); // 开启事务
try
{
session.save(person);
tx.commit();
}
catch(Exception ex)
{
System.out.println("增加用户异常发生!");
if(null != tx)
{
tx.rollback();
}
}
finally
{
HibernateUtil.closeSession(session);
}
}
/**
* 查询出所有用户
*/
@SuppressWarnings("unchecked")
public static List<Person> listAll()
{
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction(); // 开启事务
List<Person> list = null;
try
{
Query query = session.createQuery("from Person"); // hql语句,Hibernate query language,这里Person是类名
list = (List<Person>)query.list();
tx.commit();
}
catch(Exception ex)
{
System.out.println("增加用户异常发生!");
if(null != tx)
{
tx.rollback();
}
}
finally
{
HibernateUtil.closeSession(session);
}
return list;
}
}
我们先不把DAO这块全部写完,因为现在主要关注的点是整个流程,因此我们先编写界面端,流程跑通了以后再返回来编写DAO。在WebRoot下面新建一个register.jsp:
<body>
<form action="save.action">
username:<input type="text" name="username" size="20"><br>
password:<input type="password" name="password" size="20"><br>
age:<input type="text" name="age" size="20"><br>
<input type="submit" value="submit">
</form>
</body>
JSP登录页面编写完后,紧接着会点击提交,提交后流程来到struts.xml中:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="hibernate" extends="struts-default">
<action name="save" class="com.test.action.PersonAction" method="save"> <!-- 这里关注点在hibernate,因此struts的输入校验就省略了 -->
<result name="success">/listAll.jsp</result>
</action>
</package>
</struts>
接下来创建相应的action:PersonAction.java:
package com.test.action;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.ServletActionContext;
import com.hibernate.model.Person;
import com.hibernate.persistence.DBPerson;
import com.opensymphony.xwork2.ActionSupport;
public class PersonAction extends ActionSupport
{
private int id; // 因为增删查改共用一个action,所以这里增加不需要id,但是删除、查找、修改都需要提供一个id这样的熟悉,增加的时候没有id,只是不给它赋值而已,并不会产生什么问题
private String username;
private String password;
private int age;
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public String getUsername()
{
return username;
}
public void setUsername(String username)
{
this.username = username;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
// 完成用户增加的操作
public String save() throws Exception
{
Person person = new Person();
if(username != null)
username = new String(username.getBytes("ISO-8859-1"),"utf-8"); // 解决中文乱码问题
person.setUsername(username);
person.setPassword(password);
person.setAge(age);
java.sql.Date registerDate = new java.sql.Date(new java.util.Date().getTime());
person.setRegisterdate(registerDate);
DBPerson.save(person); // 将person对象存到数据库中
List<Person> list = DBPerson.listAll();
HttpServletRequest request = ServletActionContext.getRequest();
request.setAttribute("list", list);
return SUCCESS;
}
}
接下来根据struts.xml的标识,流程应该转到listAll.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'listAll.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
<script type="text/javascript">
function del()
{
if(confirm("Are you sure?"))
return true;
return false;
}
</script>
</head>
<body>
<table width="80%" align="center" border="1">
<tr>
<th> <%--<th>:定义表格内的表头单元格。此th元素内部的文本通常会呈现为粗体。--%>
username
</th>
<th>
password
</th>
<th>
registerdate
</th>
<th>
age
</th>
<th>
update
</th>
<th>
delete
</th>
</tr>
<s:iterator value="#request.list" id="person"> <!-- 或者嵌入Java代码使用for循环的形式 -->
<tr>
<td>
<s:a href="getPerson.action?id=%{#person.id}">
<s:property value="username"/> <!-- username是action中的一个成员变量 -->
</s:a>
</td>
<td>
<s:property value="password"/>
</td>
<td>
<s:property value="registerdate"/>
</td>
<td>
<s:property value="age"/>
</td>
<td>
<s:a href="updatePPerson.action?id=%{#person.id}">
update
</s:a>
</td>
<td>
<s:a href="deletePerson.action?id=%{#person.id}" onchange="return del();">
delete
</s:a>
</td>
</tr>
</s:iterator>
</table>
</body>
</html>
最后,还需要在web.xml中配置struts的过滤器:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <filter> <filter-name>struts2</filter-name> <filter-class> org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter </filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
访问http://localhost:8080/hibernate/register.jsp,增加用户和显示所有用户信息的功能就实现了。
值得补充的一点是:session的beginTransaction()方法底层调用了java.sql.Connection类的setAutoCommit(false)方法,即所有的SQL语句执行完之后再提交,而setAutoCommit(true)的意思是一条SQL语句执行完毕立刻进行提交,相当于一条SQL语句就是一个事务。而我们在一个事务里面可能执行多个命令(SQL语句),因此通常情况下,使用JDBC的话,通常将setAutoCommit方法的参数设置为false,因为它的默认值为true。那么什么时候进行提交呢?其实session的commit方法底层就是通过调用Connection的commit方法实现提交。
下面,进一步完善,点击用户名列出用户所有信息:
在DBPerson.java中增加方法:
public static Person getPersonById(Integer id)
{
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction(); // 开启事务
Person person = null;
try
{
// Object get(Class clazz, Serializable id)
// Integer实现了Serializable接口(没有任何方法,一个标识性的接口)表示可以序列化到硬盘上也可以从硬盘或者网络恢复到内存里
person = (Person)session.get(Person.class, id);
tx.commit();
}
catch(Exception ex)
{
System.out.println("查看用户异常发生");
if(null != tx)
tx.rollback();
}
finally
{
HibernateUtil.closeSession(session);
}
return person;
}
struts.xml中配置action:
<action name="getPerson" class="com.test.action.PersonAction" method="getPerson"> <result name="success">/getPerson.jsp</result> </action>
然后在PersonAction.java中写方法getPerson():
public String getPerson() throws Exception
{
Person person = DBPerson.getPersonById(id);
HttpServletRequest request = ServletActionContext.getRequest();
request.setAttribute("person", person);
return SUCCESS;
}
然后是展示页面:getPerson.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'getPerson.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<table width="70%" align="center" border="1">
<tr>
<td>username:
</td>
<td><s:property value="#request.person.username">
</td>
</tr>
<tr>
<td>password:
</td>
<td><s:property value="#request.person.password">
</td>
</tr>
<tr>
<td>age:
</td>
<td><s:property value="#request.person.age">
</td>
</tr>
<tr>
<td>registerdate:
</td>
<td><s:property value="#request.person.registerdate">
</td>
</tr>
<tr>
<td colspan="2"> <input type="button" value="back" onclick="javascript:history.back();">
</td>
</tr>
</table>
</body>
</html>
测试,其中一个实例如下:


接下来实现删除操作:
在DBPerson中增加removePerson方法:
public static void removePerson(Integer id)
{
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction(); // 开启事务
try
{
// 从数据库中查询出主键为id的记录所对应的对象,删除对象,hibernate就知道要删除的对应的记录是哪个了
Person person = (Person)session.get(Person.class, id);
session.delete(person);
tx.commit();
}
catch(Exception ex)
{
System.out.println("删除用户异常发生");
if(null != tx)
{
tx.rollback();
}
}
finally
{
HibernateUtil.closeSession(session);
}
}
然后配置struts.xml:
<action name="deletePerson" class="com.test.action.PersonAction" method="deletePerson"> <result name="success">/listAll.jsp</result> </action>
然后是PersonAction.java中增加deletePerson方法:
public String deletePerson() throws Exception
{
DBPerson.removePerson(id);
List<Person> list = DBPerson.listAll();
HttpServletRequest request = ServletActionContext.getRequest();
request.setAttribute("list", list);
return SUCCESS;
}
重启服务器,测试通过即可。
最后,实现update操作:
在struts.xml中配置信息:
<action name="updatePPerson" class="com.test.action.PersonAction" method="getPerson"> <result name="success">/updatePerson.jsp</result> </action>
新建一个updatePerson.jsp:(引入struts标签库,页面编码UTF-8)
<body>
<form action="updatePerson.action" method="post">
username:<s:textfield name="username" value="%{#request.person.username}" readonly="true"></s:textfield> <br />
password:<s:textfield name="password" value="%{#request.person.password}" ></s:textfield> <br />
age:<s:textfield name="age" value="%{#request.person.age}"></s:textfield> <br />
registerdate:<s:textfield name="registerdate" value="%{#request.person.registerdate}" readonly="true"></s:textfield>
<s:hidden name="id" value="%{#request.person.id}"></s:hidden>
<input type="submit" value="submit" />
</form>
</body>
在DBPerson.java中增加updatePerson方法:
public static void updatePerson(Person person)
{
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction(); // 开启事务
try
{
session.update(person);
tx.commit();
}
catch(Exception ex)
{
System.out.println("修改用户信息异常发生");
if(null != tx)
tx.rollback();
}
finally
{
HibernateUtil.closeSession(session);
}
}
在struts.xml中增加action:
<action name="updatePerson" class="com.test.action.PersonAction" method="updatePerson"> <result name="success">/listAll.jsp</result> </action>
在PersonAction.java中增加updatePerson方法:
public String updatePerson() throws Exception
{
Person person = DBPerson.getPersonById(id);
person.setPassword(password);
person.setAge(age);
/*
也可以通过
Person person = new Person();
person.setId(id);
person.setUsername(username);
...
的方式,但是个类里忘记定义registerdate属性了,因此采用上面先查后该的方式
*/
DBPerson.updatePerson(person);
List<Person> list = DBPerson.listAll();
HttpServletRequest request = ServletActionContext.getRequest();
request.setAttribute("list", list);
return SUCCESS;
}
至此,增删查改各个功能全部实现。但是现在这个小应用有个很严重的问题:增加用户的时候列出所有用户的时候,刷新页面,重复的用户信息会不断的插入到数据库中同时显示到页面上。
比如注册信息列出所有用户地址栏为:http://localhost:8080/hibernate/save.action?username=%E5%93%88%E5%93%88&password=123&age=12,那么重复刷新,save操作会被不断的执行,解决方法就是采用重定向的方式而不是使用请求转发。
需要更改struts.xml中result的部分,增加一个属性:redirect
<action name="save" class="com.test.action.PersonAction" method="save"> <!-- 这里关注点在hibernate,因此struts的输入校验就省略了 --> <result name="success" type="redirect">/listAll.jsp</result> </action>
删除PersonAction中如下部分(因为是重定向的方式,是另一个request,当前request已经不起作用了):
List<Person> list = DBPerson.listAll();
HttpServletRequest request = ServletActionContext.getRequest();
request.setAttribute("list", list);
需要更改listAll.jsp如下的部分(导包和访问DBPerson的listAll方法):
<%@ page language="java" import="java.util.*, com.hibernate.model.Person, com.hibernate.persistence.DBPerson" pageEncoding="utf-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<% List<Person> list = DBPerson.listAll();
request.setAttribute("list", list);
%>
这样增加用户后跳转页面链接变成了http://localhost:8080/hibernate/listAll.jsp,不会出现重复注册的现象了。