第二十部分_Hibernate原理、API与设计详解、Struts2.1整合Hibernate

具体操作步骤:

新建一个WebProject,命名为hibernate,在tomcat安装目录下的conf目录下的server.xml文件中引入其context path(在</host>之前):<Context path="/hibernate" docBase="D:\JavaWeb\hibernate\WebRoot" 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,不会出现重复注册的现象了。 

posted @ 2015-09-23 21:12  Code_Rush  阅读(211)  评论(0编辑  收藏  举报