Hibernate结合JSP使用
前面几章详细的介绍了Hibernate的相关知识,这一章介绍Hibernate结合JSP和Servlet的使用,通过这一章的学习,可以加深对Hibernate的理解。
本章使用的开发工具是MyEclipse5.5,服务器是Tomcat6.0,数据库是MySQL5.1,本章所有例子源代码见光盘第14章的工程hibernate_jsp。
14.1 搭建Hibernate框架
使用Hibernate进行开发之前,需要先搭建Hibernate框架,Hibernate框架的搭建在前面已经介绍过。新建一个Web工程,工程名为hibernate_jsp。把连接MySQL数据库的jar包、Hibernate所需的jar包和JSTL标签库的jar包拷贝到该工程的WebRoot/WEB-INF/lib目录下。在MyEclipse中把工程hibernate_jsp发布到Tomcat服务器中。
14.1.1 创建数据库表
为了使例子简单易懂,创建数据库表时,表字段很少。本章的例子只需两张表,一张部门表和一张员工表。部门表的建表语句如下:
--
CREATE
)
部门表的主键设置成自动增长。部门表和员工表是一对多的关系,所以在员工表中,部门表的主键作为员工表的外键,员工表的主键设置成自动增长。员工表的建表语句如下:
--
CREATE
)
14.1.2 编写数据库表对应的实体类和映射文件
数据库表对应的实体类和实体类映射文件可以使用MyEclipse的向导来自动生成,也可以手动编写。这里使用MyEclipse的向导来自动生成。部门表对应的实体类Dept源代码如下:
package
public
//
private
private
private
//
public
}
public
this.depno
}
public
this.depno
this.depname
this.emps
}
//这里省略了sett和getter方法
}
Dept类中有3个属性depno和depname对应数据库表的字段。Set集合对应的是一对多的多方,这里是员工实体类。Dept类的对应的映射文件和实体类在同一包下,代码如下:
<?xml
<!DOCTYPE
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
-->
<hibernate-mapping>
</hibernate-mapping>
员工实体类是一对多关系中的多方,在员工表对应的实体类中要声明一方的对象(这里是Dept类对象),员工表对应的实体类Emp代码如下:
package
public
//
private
private
private
//
public
}
public
this.empno
}
public
this.empno
this.dept
this.empname
}
//这里省略了setter和getter方法
}
用个实体类中有3个成员变量,empno和empname是数据库表这段对应的属性。Dept是员工表外键对应的属性,是一对多关系映射中的一方。Emp类对应的映射文件和实体类在同一包下,代码如下:
<?xml
<!DOCTYPE
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
-->
<hibernate-mapping>
<!--
</hibernate-mapping>
14.1.3 编写Hibernate的配置文件
这个例子中使用XML文件来作为Hibernate的配置文件,文件名为hibernate.cfg.xml,在该文件中配置数据库连接和实体类映射文件,配置文件在src的跟目录下,代码如下:
<?xml
<!DOCTYPE
<!--
<hibernate-configuration>
</hibernate-configuration>
14.1.4 编写 HibernateSessionFactory类
HibernateSessionFactory类是原来初始化Hibernate的,使用Hibernate开发时,必须编写该类。在类中编写如下代码(这里省略了import的内容):
package
public
private
private
static{
try
cf
sf
}
throw
}
}
public
Session
try
if
session
session
}
throw
}
return
}
public
try
if(session!=null)
session.close();
}
throw
}
}
public
getSession();
}
}
14.2 操作员工表
部门表的主键作为员工表的外键,所以在添加员工信息时,对应的部门信息要存在,否则抛出异常。这一节将介绍对员工表的增删改查操作。
14.2.1 添加员工信息
在添加员工信息之前,首先在MySQL的控制台中或者客户端工具中,往部门表中添加几条数据。添加员工信息的页面为addEmp.jsp,代码如下(这里省略了html、head和body标签,用省略号代替):
<%@
<!DOCTYPE
……
……
上述代码中,from表单提交到AddEmpServlet中,使用post提交方式。页面中有连个文本框,员工编号是自动增长的,所以不用添加。AddEmpServlet的代码如下(这里省略了import的内容):
package
public
public
throws
response.setContentType("text/html");
PrintWriter
out.flush();
out.close();
}
public
throws
response.setContentType("text/html");
PrintWriter
String
int
Emp
Dept
dept.setDepno(depno);//把depno设置到dept对象中
emp.setEmpname(empname);//把empname设置到emp对象中
emp.setDept(dept);//把dept设置到emp对象中
EmpDao
dao.addEmp(emp);//调用实现类的的添加方法
response.sendRedirect("ShowAllEmpServlet");//重定向到显示全部的Servlet中
out.flush();
out.close();
}
}
编写好Servlet以后,需要在WebRoot/WEB-INF/web.ml文件中配置Servlet信息。上述代码中有这样一行代码:
EmpDao
其中EmpDao是一个接口,EmpDaoImp是接口实现类。这一行代码是接口实现类的对象指向接口的引用。接口类EmpDao中代码如下:
package
import
import
public
public
}
在接口实现类EmpDaoImp中实现addEmp方法。EmpDaoImp类的代码如下(这里省略了import的内容):
package
public
Session
Transaction
public
session.save(emp);//添加数据
tr.commit();//提交事务
}
}
为了防止添加到数据库中的数据出现中文乱码,需要编写一个处理中文乱码的过滤器,过滤器的代码如下:
package
import
import
public
public
//
}
public
FilterChain
request.setCharacterEncoding("gb2312");//设置request的编码方式为gb2312
response.setCharacterEncoding("gb2312");//设置response的编码方式为gb2312
chain.doFilter(request,
}
public
//
}
}
编写好这些代码以后,就可以正确的添加数据了。添加员工信息成功以后,页面跳转到ShowAllEmpServlet,所以添加数据的演示,放到显示全部员工信息部分一起演示。
14.2.2 显示全部员工信息
添加员工信息成功以后,页面跳转到ShowAllEmpServlet,该类是一个Servlet,用来显示全部员工信息,ShowAllEmpServlet的代码如下(这里省略了import的内容):
package
public
public
throws
response.setContentType("text/html");
PrintWriter
this.doPost(request,
out.flush();
out.close();
}
public
throws
response.setContentType("text/html");
PrintWriter
List<Emp>
EmpDao
list
request.setAttribute("list",
request.getRequestDispatcher("showAllEmp.jsp").forward(request,
out.flush();
out.close();
}
}
上述代码中要在doGet方法中调用doPost方法,因为当页面跳转到Servlet中没有特别说明,会进入doGet方法中。在doPost方法中调用了接口实现类EmpDaoImp的查询全部方法queryAllEmp()方法。在接口EmpDao类中添加如下一行代码:
public
在接口实现类EmpDaoImp类中实现queryAllEmp()方法,实现类EmpDaoImp中queryAllEmp()方法的代码如下:
public
List<Emp>
tr.commit();//提交事务
return
}
在ShowAllEmpServlet中把查询到的全部数据放入List集合中,再把List集合对象放入request对象中。然后转发到显示全部员工信息的页面showAllEmp.jsp,showAllEmp.jsp页面的代码如下(这里省略了html、head和body标签,用省略号代替):
<%@
<%@
<!DOCTYPE
……
<a
<a
</td>
……
在MyEclipse中启动Toncat服务器,在IE浏览器的地址横纵中输入地址:“http://localhost:8080/hibernate_jsp/addEmp.jsp”,页面效果如图14.1所示。
图14.1
在图14.1所示的页面中输入员工姓名和闭门编号以后,单击“提交”按钮,数据添加成功以后进入图14.2所示的页面。
图14.2
在图14.2所示的页面中,显示了全部员工信息,同时提供了修改和删除的操作。接下来介绍修改和删除操作。
14.2.3 修改员工信息
修改数据的流程是:在页面通过超链接跳转显示单条数据信息的页面,在显示单条数据信息的页面中修改需要修改的数据,然后提交,把修改的数据提交到数据库中。然后再次跳转到显示全部员工信息的页面。
在图14.2所示的页面中,点击“修改”插连接时,传递员工编号参数进入根据编号查询的Servlet中(这里是QueryEmpById)。QueryEmpById的代码如下(这里省略import的内容):
package
public
public
throws
response.setContentType("text/html");
PrintWriter
this.doPost(request,
out.flush();
out.close();
}
public
throws
response.setContentType("text/html");
PrintWriter
int
Emp
EmpDao
emp
request.setAttribute("emp",
//转发到现实单条记录的页面
request.getRequestDispatcher("showEmpById.jsp").forward(request,
out.flush();
out.close();
}
}
上述代码中,在doGet()方法中调用doPost()方法,Servlet默认的进入的是doGet()方法,所以要在doGet()方法中调用doPost()方法。在doPost()方法中调用了实现类EmpDaoImp中的queryEmpById()方法。所以在接口EmpDao类中添加如下一行代码:
public
在实现类EmpDaoImp中要实现queryEmpById(int
public
Emp
emp
return
}
查询出数据以后,把数据放入request对象中,页面转发到显示单条记录的页面showEmpById.jsp。showEmpById.jsp页面的代码如下(这里省略了html、head和body标签,用省略号代替):
<%@
<%@
<!DOCTYPE
……
……
上述代码中,form表单提交到UpdateEmpServlet,UpdateEmpServlet是一个修改数据的Servlet。UpdateEmpServlet的代码如下(这里省略了import的内容):
package
public
public
throws
response.setContentType("text/html");
PrintWriter
this.doPost(request,
out.flush();
out.close();
}
public
throws
response.setContentType("text/html");
PrintWriter
int
String
int
Dept
Emp
dept.setDepno(depno);//设置depno到Dept的对象中
emp.setDept(dept);//设置dept到Emp对象中
emp.setEmpname(empname);//设置empname到Emp对象中
emp.setEmpno(empno);//设置empno到Emp对象中
EmpDao
dao.updateEmp(emp);//调用实现类的修改方法
response.sendRedirect("ShowAllEmpServlet");//重定向到查询全部的Servlet
out.flush();
out.close();
}
}
该Servlet中的doGet方法调用doPost方法,修改的业务处理在doPost方法中处理。在doPost方法中,获得页面传递过来的数据以后,把数据设置到相应的对象中,调用了接口实现类EmpDaoImp中的修改方法。在接口EmpDao中添加修改方法updateEmp()方法,代码如下:
public
在接口实现类EmpDaoImp中实现修改的方法,修改数据的方法updateEmp()方法的代码如下:
public
session.update(emp);//修改
tr.commit();//提交事务
}
要修改数据,需要在显示全部数据的页面中,点击修改超链接进入修改数据页面。启动Tomcat服务器,在IE浏览器地址栏中输入地址:“http://localhost:8080/hibernate_jsp/ShowAllEmpServlet”,在显示全部数据的页面中点击一个修改超链接,进入图14.3所示的页面。
图14.3
在图14.3所示的页面中,员工编号是只读的,不能修改。员工姓名和闭门编号可以修改。输入修改后的数据,提交表单。修改成功后,页面跳转到图14.4所示的页面。
图14.4
14.2.4 删除员工信息
删除员工信息的可以通过在图14.4所示的页面中点击删除超链接,进入删除员工信息的Servlet,由Servlet调用删除的方法,实现删除员工信息的操作,删除成功后,页面跳转到显示全部员工信息的页面。
删除员工信息的Servlet——DeleteEmpById是处理删除信息的Servlet,DeleteEmpById的代码如下(这里省略了import的内容):
package
public
public
throws
response.setContentType("text/html");
PrintWriter
this.doPost(request,
out.flush();
out.close();
}
public
throws
response.setContentType("text/html");
PrintWriter
int
EmpDao
dao.deleteEmp(empno);//调用实现类中的查询方法
response.sendRedirect("ShowAllEmpServlet");//重定向到显示全部员工信息页面
out.flush();
out.close();
}
}
在DeleteEmpById类中的doGet方法中调用了doPost()方法,进入该Servlet时,默认进入的是doGet()方法,处理删除的过程在doPost()方法中实现,该方法中调用了接口实现类中的删除员工信息的方法,所以在接口EmpDao类中添加删除员工信息的方法deleteEmp()方法,代码如下:
public
在接口实现类EmpDaoImp中要实现deleteEmp()方法,deleteEmp()方法的代码如下:
public
//使用Query对象来删除
Query
query.setParameter("id",
query.executeUpdate();//删除
tr.commit();//提交事务
}
删除员工信息的代码都写好以后,可以在显示全部数据的页面中删除需要删除的员工信息,启动Tomcat服务器,在IE浏览器地址栏中输入地址:“http://localhost:8080/hibernate_jsp/ShowAllEmpServlet”,效果如图14.5所示。
图14.5
在图14.5所示的页面中删除应改变好为2的员工信息。员工编号为2的员工姓名是小张,所在部门是Java开发部。删除该条数据以后,进入图14.6所示的页面。
图14.6
在图14.6所示的页面中可以看到,员工编号为2的数据已经被删除了,这说明删除员工信息成功。这里的删除是单表删除,在下一节操作部门表中会讲到级联删除。
14.3 操作部门表
部门表的主键作为员工表的外键,所在在删除部门表信息的时候,需要级联删除员工表信息。本节中将介绍部门表信息的添加、查询和删除。修改操作和员工表的修改方法类似,这里就不再重复。
14.3.1 添加部门信息
添加部门信息时在页面中输入部门信息,提交表单后由后台处理添加业务。添加部门的页面addDept.jsp代码如下(这里省略了html、head和body标签,用省略号代替):
<%@
<!DOCTYPE
……
……
添加数据的表单提交到AddDeptServlet中,使用post方式提交表单内容。AddDeptServlet是处理添加数据层的Servlet,AddDeptServlet的代码如下(这里省略了import的内容):
package
public
public
throws
response.setContentType("text/html");
PrintWriter
this.doPost(request,
out.flush();
out.close();
}
public
throws
response.setContentType("text/html");
PrintWriter
response.setCharacterEncoding("gb2312");//设置response编码方式
request.setCharacterEncoding("gb2312");//设置request编码方式
String
Dept
dept.setDepname(depname);//把获得的页面数据设置到Dept对象中
DeptDao
deptDao.addDept(dept);//调用实现类DeptDaoImp的addDept方法
response.sendRedirect("ShowAllDeptServlet");//页面重定向到ShowAllDeptServlet中
out.flush();
out.close();
}
}
上述代码中,在doPost()方法中获得页面表单提交的数据,然后调用接口实现类DeptDaoImp中的addDept方法。首先编写接口DeptDao类,代码如下:
package
import
import
public
public
}
在接口实现类DeptDaoImp中实现addDept()方法,接口实现类DeptDaoImp的代码如下(这里省略了import的内容):
package
public
Session
Transaction
public
session.save(dept);//添加数据
tr.commit();//提交事务
}
}
在添加部门信息的Servlet中,添加数据成功以后,页面跳转到查询全部数据的Servlet中,所以添加数据的演示留到和查询全部数据一起演示。
14.3.2 查询全部部门信息
添加部门信息成功以后,页面跳转到查询全部部门信息的Servlet中,查询全部部门信息的Servlet——ShowAllDeptServlet的代码如下(这里省略了import的内容):
package
public
public
throws
response.setContentType("text/html");
PrintWriter
this.doPost(request,
out.flush();
out.close();
}
public
throws
response.setContentType("text/html");
PrintWriter
DeptDao
List<Dept>
list
request.setAttribute("list",
//转发到显示全部的页面中
request.getRequestDispatcher("showAllDept.jsp").forward(request,
out.flush();
out.close();
}
}
在ShowAllDeptServlet的doGet()方法中调用了doPost()方法,查询数据的操作的doPost()方法中处理。在doPost()方法中调用了接口实现类中的queryAllDept()方法。在接口DeptDao中添加queryAllDept()方法,代码如下:
public
在接口实现类DeptDaoImp中实现queryAllDept()方法,queryAllDept()方法代码如下:
public
//查询全部部门信息
List<Dept>
eturn
}
查询出全部的部门信息后,ShowAllDeptServlet转发到显示全部部门信息的页面showAllDept.jsp中,showAllDept.jsp的代码如下(这里省略了html、head和body标签,用省略号代替):
<%@
<%@
<!DOCTYPE
……
……
现在来演示添加部门信息和查询全部部门信息。启动Tomcat服务器,在IE浏览器地址栏中输入地址:“http://localhost:8080/hibernate_jsp/addDept.jsp”,页面效果如图14.7所示。
图14.7
在图14.7所示的页面中输入部门名称后,提交表单。添加部门信息成功后页面中显示出全部的部门信息,效果如图14.8所示。
图14.8
14.3.3 删除部门信息
部门表的主键是员工表的外键,在删除部门信息时,如果该条信息是员工表一些数据的外键时,需要把员工表的信息业删除掉。在编写删除操作之前,要在Dept.hbm.xml映射文件中设置一对多的级联操作,<set>中的代码修改成如下代码:
在显示全部部门信息的页面中,点击删除超链接时,页面进入删除部门信息的Servlet——DeleteDeptServlet,DeleteDeptServlet的代码如下(这里省略了import的内容):
package
public
public
throws
response.setContentType("text/html");
PrintWriter
this.doPost(request,
out.flush();
out.close();
}
public
throws
response.setContentType("text/html");
PrintWriter
int
DeptDao
dao.deleteDept(depno);//调用删除方法
response.sendRedirect("ShowAllDeptServlet");//页面重定向到查询全部部门信息的Servlet
out.flush();
out.close();
}
}
在DeleteDeptServlet的doGet()方法中调用了doPost()方法,doPost()方法中获得路径中传递的参数,然后调用接口实现类DeptDaoImp中的deleteDept()方法。在接口DeptDao中添加deleteDept()方法,代码如下:
public
在接口实现类DeptDaoImp中要实现deleteDept()方法,deleteDept()方法代码如下:
public
Dept
session.delete(dept);//删除数据
session.flush();
tr.commit();//提交事务
}
删除部门信息以后,该条信息对于的员工表外键数据也被删除,启动Tomcat服务器,在IE浏览器地址栏中输入地址:“http://localhost:8080/hibernate_jsp/ShowAllDeptServlet”,页面效果如图14.9所示。
图14.9
在图14.9所示的页面中删除掉部门编号为2的数据,该条数据对应的部门名称为市场部。删除成功后,页面进入图14.10所示的页面。
图14.10
再到数据中查询员工表的信息,发现外键为2的员工表信息都被删除了,这是因为在删除部门表信息时,使用了一对多的级联删除操作。
14.4 Hibernate的分页查询
当查询结果时很多数据时,一个页面无法全部显示出来,这个时候就用到了分页查询。Hibernate的页面查询方法是必须要掌握的一个知识点。这一节将介绍简单的Hibernate分页查询。为了便于理解,本节中的例子也采用分层来介绍,hql语句写在数据库访问层(即DAO层),Servlet中调用DAO层代码,在JSP页面中分页显示出来。
14.4.1 数据库访问层代码
数据库访问层也称DAO层,在DAO层中,要定义两个方法,一个方法是查询数据信息的方法,一个方法是求最大页数的方法。接口EmpPageDAO的代码如下:
package
import
import
public
public
public
}
在接口中定义的方法,要在接口实现类EmpPageDAOImp中实现这些方法,接口实现类EmpPageDAOImp的代码如下(这里省略了import的内容):
package
public
int
}
14.4.2 Servlet层的代码
在数据库访问层中声明了最大页数和查询数据信息的方法后,需要在Servlet中调用这些方法。这个例子中是在ShowEmpByPageServlet类中调用DAO层的方法,ShowEmpByPageServlet类的代码如下(这里省略了import的内容):
package
public
public
throws
response.setContentType("text/html");
PrintWriter
this.doPost(request,
out.flush();
out.close();
}
public
throws
response.setContentType("text/html");
PrintWriter
String
int
int
if(page!=null){//如果获得地址栏中的页数不为null。赋值给pageNo
pageNo
}
EmpPageDAO
List<Emp>
//调用EmpPageDAOImp的getAll方法,获得查询结果
list
int
request.setAttribute("list",
request.setAttribute("page",
request.setAttribute("maxpage",
//转发到showEmpByPage.jsp页面
request.getRequestDispatcher("showEmpByPage.jsp").forward(request,
out.flush();
out.close();
}
}
在Servlet中调用接口实现类EmpPageDAOImp中的getAll()方法来获得查询信息,调用maxPage()方法来获得最大页数。把获得的当前页数、最大页数和查询结果放入request对象中,转发到JSP页面中。在JSP页面获得这些信息。
14.4.3 JSP页面分页
在JSP页面中获得Servlet转发过来的数据信息后,分页显示出获得的数据信息。在JSP页面中使用到JSTL标签库来遍历数据。分页显示的JSP页面——showEmpByPage.jsp代码如下:
<%@
<%@
<!DOCTYPE
<html>
<a
<a
</td>
<c:if
</html>
在showEmpByPage.jsp页面中,如果当前页面是第一页,则首页和上一页变成不可点击状态,如果当前页数是最大页,则下一页和末页变成不可点击状态。启动Tomcat服务器,在IE浏览器地址栏中输入地址:“http://localhost:8080/hibernate_jsp/ShowEmpByPageServlet”,页面效果如图14.11所示。
图14.11
14.5 本章小结
本章中使用Hibernate结合Servlet和JSP对数据库表数据进行了操作。操作员工表时,添加数据涉及到部门表的信息,所以在添加员工信息时,要确保外键存在。在操作部门表时,删除部门信息需要把员工表中有外键关联的数据删除,涉及到级联删除。本章好介绍了Hibernate的分页查询。