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 创建数据库表
为了使例子简单易懂,创建数据库表时,表字段很少。本章的例子只需两张表,一张部门表和一张员工表。部门表的建表语句如下:
-- Table "dept" DDL
CREATE TABLE dept (
depno int(11) NOT NULL AUTO_INCREMENT,
depname varchar(255) DEFAULT NULL,
PRIMARY KEY (depno)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=gb2312;
部门表的主键设置成自动增长。部门表和员工表是一对多的关系,所以在员工表中,部门表的主键作为员工表的外键,员工表的主键设置成自动增长。员工表的建表语句如下:
-- Table "emp" DDL
CREATE TABLE emp (
empno int(11) NOT NULL AUTO_INCREMENT,
empname varchar(255) DEFAULT NULL,
depno int(11) DEFAULT NULL,
PRIMARY KEY (empno),
KEY FK188C86CDD0E0B (depno),
CONSTRAINT FK188C86CDD0E0B FOREIGN KEY (depno) REFERENCES dept (depno)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=gb2312;
14.1.2 编写数据库表对应的实体类和映射文件
数据库表对应的实体类和实体类映射文件可以使用MyEclipse的向导来自动生成,也可以手动编写。这里使用MyEclipse的向导来自动生成。部门表对应的实体类Dept源代码如下:
package com.cn.vo;
public class Dept implements java.io.Serializable {
// Fields
private Integer depno;
private String depname;
private Set emps = new HashSet(0);//对应的员工实体类
// Constructors
public Dept() {
}
public Dept(Integer depno) {
this.depno = depno;
}
public Dept(Integer depno, String depname, Set emps) {
this.depno = depno;
this.depname = depname;
this.emps = emps;
}
//这里省略了sett和getter方法
}
Dept类中有3个属性depno和depname对应数据库表的字段。Set集合对应的是一对多的多方,这里是员工实体类。Dept类的对应的映射文件和实体类在同一包下,代码如下:
<?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">
<!--
Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
<class name="com.cn.vo.Dept" table="dept" catalog="bank">
<id name="depno" type="java.lang.Integer">
<column name="depno" />
<generator class="native" />
</id>
<property name="depname" type="java.lang.String">
<column name="depname" />
</property>
<set name="emps" inverse="true">
<key>
<column name="depno" />
</key>
<one-to-many class="com.cn.vo.Emp" /><!-- 一对多关系映射 -->
</set>
</class>
</hibernate-mapping>
员工实体类是一对多关系中的多方,在员工表对应的实体类中要声明一方的对象(这里是Dept类对象),员工表对应的实体类Emp代码如下:
package com.cn.vo;
public class Emp implements java.io.Serializable {
// Fields
private Integer empno;
private Dept dept;//部门实体类对象
private String empname;
// Constructors
public Emp() {
}
public Emp(Integer empno) {
this.empno = empno;
}
public Emp(Integer empno, Dept dept, String empname) {
this.empno = empno;
this.dept = dept;
this.empname = empname;
}
//这里省略了setter和getter方法
}
用个实体类中有3个成员变量,empno和empname是数据库表这段对应的属性。Dept是员工表外键对应的属性,是一对多关系映射中的一方。Emp类对应的映射文件和实体类在同一包下,代码如下:
<?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">
<!--
Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
<class name="com.cn.vo.Emp" table="emp" catalog="bank">
<id name="empno" type="java.lang.Integer">
<column name="empno" />
<generator class="native" />
</id>
<!-- 多对一的关系映射 -->
<many-to-one name="dept" class="com.cn.vo.Dept" fetch="select">
<column name="depno" />
</many-to-one>
<property name="empname" type="java.lang.String">
<column name="empname" />
</property>
</class>
</hibernate-mapping>
14.1.3 编写Hibernate的配置文件
这个例子中使用XML文件来作为Hibernate的配置文件,文件名为hibernate.cfg.xml,在该文件中配置数据库连接和实体类映射文件,配置文件在src的跟目录下,代码如下:
<?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="connection.username">root</property>
<property name="connection.url">jdbc:mysql://localhost:3306/bank</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="myeclipse.connection.profile">com.mysql.jdbc.Driver</property>
<property name="connection.password">root</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 实体类的映射文件 -->
<mapping resource="com/cn/vo/Dept.hbm.xml"/>
<mapping resource="com/cn/vo/Emp.hbm.xml"/>
</session-factory>
</hibernate-configuration>
14.1.4 编写HibernateSessionFactory类
HibernateSessionFactory类是原来初始化Hibernate的,使用Hibernate开发时,必须编写该类。在类中编写如下代码(这里省略了import的内容):
package com.cn.factory;
public class HibernateSessionFactory {
private static Configuration cf = null;
private static SessionFactory sf = null;
static{
try {
cf = new Configuration().configure();
sf = cf.buildSessionFactory();//创建session
} catch (HibernateException e) {
throw new RuntimeException("SessionFactory创建失败",e);
}
}
public static Session getSession(){//获得session的方法
Session session = null;
try {
if (session==null||session.isOpen()==false)
session = null;
session = sf.openSession();
} catch (HibernateException e) {
throw new RuntimeException("Session创建失败",e);
}
return session;
}
public static void closed(Session session){//关闭session的方法
try {
if(session!=null)
session.close();
} catch (HibernateException e) {
throw new RuntimeException("Session关闭失败",e);
}
}
public static void main(String[] args) {//测试方法
getSession();
}
}
14.2 操作员工表
部门表的主键作为员工表的外键,所以在添加员工信息时,对应的部门信息要存在,否则抛出异常。这一节将介绍对员工表的增删改查操作。
14.2.1 添加员工信息
在添加员工信息之前,首先在MySQL的控制台中或者客户端工具中,往部门表中添加几条数据。添加员工信息的页面为addEmp.jsp,代码如下(这里省略了html、head和body标签,用省略号代替):
<%@ page language="java" import="java.util.*" pageEncoding="gb2312"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
……
<form action="AddEmpServlet" method="post">
<table>
<tr>
<td>员工姓名</td>
<td><input type="text" name="ename"></td>
</tr>
<tr><td>部门编号</td>
<td><input type="text" name="depno"></td>
</tr>
</table>
<input type="submit" value="提交">
<input type="reset" value="重置">
</form>
……
上述代码中,from表单提交到AddEmpServlet中,使用post提交方式。页面中有连个文本框,员工编号是自动增长的,所以不用添加。AddEmpServlet的代码如下(这里省略了import的内容):
package com.cn.service;
public class AddEmpServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String empname = request.getParameter("ename");//获得页面传递过来的数据
int depno = Integer.parseInt(request.getParameter("depno"));//获得页面传递过来的数据
Emp emp = new Emp();
Dept dept = new Dept();
dept.setDepno(depno);//把depno设置到dept对象中
emp.setEmpname(empname);//把empname设置到emp对象中
emp.setDept(dept);//把dept设置到emp对象中
EmpDao dao = new EmpDaoImp();
dao.addEmp(emp);//调用实现类的的添加方法
response.sendRedirect("ShowAllEmpServlet");//重定向到显示全部的Servlet中
out.flush();
out.close();
}
}
编写好Servlet以后,需要在WebRoot/WEB-INF/web.ml文件中配置Servlet信息。上述代码中有这样一行代码:
EmpDao dao = new EmpDaoImp();
其中EmpDao是一个接口,EmpDaoImp是接口实现类。这一行代码是接口实现类的对象指向接口的引用。接口类EmpDao中代码如下:
package com.cn.dao;
import java.util.List;
import com.cn.vo.Emp;
public interface EmpDao {
public void addEmp(Emp emp);//添加数据的方法
}
在接口实现类EmpDaoImp中实现addEmp方法。EmpDaoImp类的代码如下(这里省略了import的内容):
package com.cn.dao.imp;
public class EmpDaoImp implements EmpDao {
Session session = HibernateSessionFactory.getSession();//获得session
Transaction tr = session.beginTransaction();//开启事务
public void addEmp(Emp emp) {
session.save(emp);//添加数据
tr.commit();//提交事务
}
}
为了防止添加到数据库中的数据出现中文乱码,需要编写一个处理中文乱码的过滤器,过滤器的代码如下:
package com.cn.fileter;
import java.io.IOException;
import javax.servlet.*;
public class ChinaFilter implements Filter {
public void destroy() {
// TODO Auto-generated method stub
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("gb2312");//设置request的编码方式为gb2312
response.setCharacterEncoding("gb2312");//设置response的编码方式为gb2312
chain.doFilter(request, response);//提交处理
}
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
编写好这些代码以后,就可以正确的添加数据了。添加员工信息成功以后,页面跳转到ShowAllEmpServlet,所以添加数据的演示,放到显示全部员工信息部分一起演示。
14.2.2 显示全部员工信息
添加员工信息成功以后,页面跳转到ShowAllEmpServlet,该类是一个Servlet,用来显示全部员工信息,ShowAllEmpServlet的代码如下(这里省略了import的内容):
package com.cn.service;
public class ShowAllEmpServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
this.doPost(request, response);//调用doPost方法
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
List<Emp> list = new ArrayList<Emp>();
EmpDao dao = new EmpDaoImp();
list = dao.queryAllEmp();//调用实现类的查询全部方法
request.setAttribute("list", list);//把查询结果放入request对象中
request.getRequestDispatcher("showAllEmp.jsp").forward(request, response);//转发到现实全部的页面
out.flush();
out.close();
}
}
上述代码中要在doGet方法中调用doPost方法,因为当页面跳转到Servlet中没有特别说明,会进入doGet方法中。在doPost方法中调用了接口实现类EmpDaoImp的查询全部方法queryAllEmp()方法。在接口EmpDao类中添加如下一行代码:
public List<Emp> queryAllEmp();//查询全部数据的方法
在接口实现类EmpDaoImp类中实现queryAllEmp()方法,实现类EmpDaoImp中queryAllEmp()方法的代码如下:
public List<Emp> queryAllEmp() {
List<Emp> list =session.createQuery("from Emp").list();//查询全部
tr.commit();//提交事务
return list;
}
在ShowAllEmpServlet中把查询到的全部数据放入List集合中,再把List集合对象放入request对象中。然后转发到显示全部员工信息的页面showAllEmp.jsp,showAllEmp.jsp页面的代码如下(这里省略了html、head和body标签,用省略号代替):
<%@ page language="java" import="java.util.*" pageEncoding="gb2312"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
……
<table border="1">
<tr>
<td>员工编号</td>
<td>员工姓名</td>
<td>员工所在部门</td>
<td>操作</td>
</tr>
<c:forEach var="list" items="${list}">
<tr>
<td>${list.empno }</td>
<td>${list.empname }</td>
<td>${list.dept.depname }</td>
<td>
<a href="QueryEmpById?empno=${list.empno }">修改</a>
<a href="DeleteEmpById?empno=${list.empno }">删除</a>
</td>
</tr>
</c:forEach>
</table>
……
在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 com.cn.service;
public class QueryEmpById extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
this.doPost(request, response);//调用doPost方法
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
int empno = Integer.parseInt(request.getParameter("empno"));//获得页面传递的参数
Emp emp = new Emp();
EmpDao dao = new EmpDaoImp();
emp = dao.queryEmpById(empno);//调用实现类中根据id查询的方法
request.setAttribute("emp", emp);//把获得的对象放入request对象中
//转发到现实单条记录的页面
request.getRequestDispatcher("showEmpById.jsp").forward(request, response);
out.flush();
out.close();
}
}
上述代码中,在doGet()方法中调用doPost()方法,Servlet默认的进入的是doGet()方法,所以要在doGet()方法中调用doPost()方法。在doPost()方法中调用了实现类EmpDaoImp中的queryEmpById()方法。所以在接口EmpDao类中添加如下一行代码:
public Emp queryEmpById(int id);//根据id查询的方法
在实现类EmpDaoImp中要实现queryEmpById(int id)方法,所以在EmpDaoImp中编写queryEmpById(int id)方法,queryEmpById(int id)方法代码如下:
public Emp queryEmpById(int id) {
Emp emp = new Emp();
emp = (Emp) session.load(Emp.class, id);//根据id查询
return emp;
}
查询出数据以后,把数据放入request对象中,页面转发到显示单条记录的页面showEmpById.jsp。showEmpById.jsp页面的代码如下(这里省略了html、head和body标签,用省略号代替):
<%@ page language="java" import="java.util.*" pageEncoding="gb2312"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
……
<form action="UpdateEmpServlet" method="post">
<table>
<tr>
<td>员工编号</td>
<td><input type="text" name="empno" value="${emp.empno }" readonly="readonly"></td>
</tr>
<tr>
<td>员工姓名</td>
<td><input type="text" name="ename" value="${emp.empname }"></td>
</tr>
<tr><td>部门编号</td>
<td><input type="text" name="depno" value="${emp.dept.depno }"></td>
</tr>
</table>
<input type="submit" value="提交">
<input type="reset" value="重置">
</form>
……
上述代码中,form表单提交到UpdateEmpServlet,UpdateEmpServlet是一个修改数据的Servlet。UpdateEmpServlet的代码如下(这里省略了import的内容):
package com.cn.service;
public class UpdateEmpServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
this.doPost(request, response);//调用doPost方法
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
int empno = Integer.parseInt(request.getParameter("empno"));//获得页面传递过来的参数
String empname = request.getParameter("ename");//获得页面传递过来的参数
int depno = Integer.parseInt(request.getParameter("depno"));//获得页面传递过来的参数
Dept dept = new Dept();
Emp emp = new Emp();
dept.setDepno(depno);//设置depno到Dept的对象中
emp.setDept(dept);//设置dept到Emp对象中
emp.setEmpname(empname);//设置empname到Emp对象中
emp.setEmpno(empno);//设置empno到Emp对象中
EmpDao dao = new EmpDaoImp();
dao.updateEmp(emp);//调用实现类的修改方法
response.sendRedirect("ShowAllEmpServlet");//重定向到查询全部的Servlet
out.flush();
out.close();
}
}
该Servlet中的doGet方法调用doPost方法,修改的业务处理在doPost方法中处理。在doPost方法中,获得页面传递过来的数据以后,把数据设置到相应的对象中,调用了接口实现类EmpDaoImp中的修改方法。在接口EmpDao中添加修改方法updateEmp()方法,代码如下:
public void updateEmp(Emp emp);//修改数据的方法
在接口实现类EmpDaoImp中实现修改的方法,修改数据的方法updateEmp()方法的代码如下:
public void updateEmp(Emp emp) {
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 com.cn.service;
public class DeleteEmpById extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
this.doPost(request, response);//调用doPost方法
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
int empno = Integer.parseInt(request.getParameter("empno"));//获得页面传递的empno
EmpDao dao = new EmpDaoImp();
dao.deleteEmp(empno);//调用实现类中的查询方法
response.sendRedirect("ShowAllEmpServlet");//重定向到显示全部员工信息页面
out.flush();
out.close();
}
}
在DeleteEmpById类中的doGet方法中调用了doPost()方法,进入该Servlet时,默认进入的是doGet()方法,处理删除的过程在doPost()方法中实现,该方法中调用了接口实现类中的删除员工信息的方法,所以在接口EmpDao类中添加删除员工信息的方法deleteEmp()方法,代码如下:
public void deleteEmp(int id);//删除数据的方法
在接口实现类EmpDaoImp中要实现deleteEmp()方法,deleteEmp()方法的代码如下:
public void deleteEmp(int id) {
//使用Query对象来删除
Query query = (Query) session.createQuery("delete Emp where empno=:id");
query.setParameter("id", 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标签,用省略号代替):
<%@ page language="java" pageEncoding="gb2312"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
……
<form action="AddDeptServlet" method="post">
<table>
<tr>
<td>部门名称</td>
<td><input name="deptName" type="text"></td>
</tr>
<tr>
<td><input type="submit" value="提交"></td>
<td><input type="reset" value="重置"></td>
</tr>
</table>
</form>
……
添加数据的表单提交到AddDeptServlet中,使用post方式提交表单内容。AddDeptServlet是处理添加数据层的Servlet,AddDeptServlet的代码如下(这里省略了import的内容):
package com.cn.service;
public class AddDeptServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
this.doPost(request, response);//调用doPost方法
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
response.setCharacterEncoding("gb2312");//设置response编码方式
request.setCharacterEncoding("gb2312");//设置request编码方式
String depname = request.getParameter("deptName");//获得页面传递过来的数据
Dept dept = new Dept();
dept.setDepname(depname);//把获得的页面数据设置到Dept对象中
DeptDao deptDao = new DeptDaoImp();
deptDao.addDept(dept);//调用实现类DeptDaoImp的addDept方法
response.sendRedirect("ShowAllDeptServlet");//页面重定向到ShowAllDeptServlet中
out.flush();
out.close();
}
}
上述代码中,在doPost()方法中获得页面表单提交的数据,然后调用接口实现类DeptDaoImp中的addDept方法。首先编写接口DeptDao类,代码如下:
package com.cn.dao;
import java.util.List;
import com.cn.vo.Dept;
public interface DeptDao {
public void addDept(Dept dept);//添加部门
}
在接口实现类DeptDaoImp中实现addDept()方法,接口实现类DeptDaoImp的代码如下(这里省略了import的内容):
package com.cn.dao.imp;
public class DeptDaoImp implements DeptDao {
Session session = HibernateSessionFactory.getSession();//获得session
Transaction tr = session.beginTransaction();//开启事务
public void addDept(Dept dept) {
session.save(dept);//添加数据
tr.commit();//提交事务
}
}
在添加部门信息的Servlet中,添加数据成功以后,页面跳转到查询全部数据的Servlet中,所以添加数据的演示留到和查询全部数据一起演示。
14.3.2 查询全部部门信息
添加部门信息成功以后,页面跳转到查询全部部门信息的Servlet中,查询全部部门信息的Servlet——ShowAllDeptServlet的代码如下(这里省略了import的内容):
package com.cn.service;
public class ShowAllDeptServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
this.doPost(request, response);//调用doPost方法
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
DeptDao dao = new DeptDaoImp();//接口实现类对象指向接口的引用
List<Dept> list =new ArrayList<Dept>();
list = dao.queryAllDept();//调用接口实现类中的queryAllDept方法
request.setAttribute("list", list);//把查询得到的集合放到request对象中
//转发到显示全部的页面中
request.getRequestDispatcher("showAllDept.jsp").forward(request, response);
out.flush();
out.close();
}
}
在ShowAllDeptServlet的doGet()方法中调用了doPost()方法,查询数据的操作的doPost()方法中处理。在doPost()方法中调用了接口实现类中的queryAllDept()方法。在接口DeptDao中添加queryAllDept()方法,代码如下:
public List<Dept> queryAllDept();//显示全部部门信息
在接口实现类DeptDaoImp中实现queryAllDept()方法,queryAllDept()方法代码如下:
public List<Dept> queryAllDept() {
//查询全部部门信息
List<Dept> list = session.createQuery("from Dept").list();
eturn list;
}
查询出全部的部门信息后,ShowAllDeptServlet转发到显示全部部门信息的页面showAllDept.jsp中,showAllDept.jsp的代码如下(这里省略了html、head和body标签,用省略号代替):
<%@ page language="java" import="java.util.*" pageEncoding="gb2312"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
……
<table border="1">
<tr><td>部门号</td><td>部门名称</td><td>操作</td></tr>
<c:forEach var="list" items="${list}">
<tr>
<td>${list.depno }</td>
<td>${list.depname }</td>
<td>
<a href="DeleteDeptServlet?depno=${list.depno }">删除</a>
</td>
</tr>
</c:forEach>
</table>
……
现在来演示添加部门信息和查询全部部门信息。启动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>中的代码修改成如下代码:
<set name="emps" inverse="true" lazy="false" cascade="all">
<key>
<column name="depno" />
</key>
<one-to-many class="com.cn.vo.Emp" />
</set>
在显示全部部门信息的页面中,点击删除超链接时,页面进入删除部门信息的Servlet——DeleteDeptServlet,DeleteDeptServlet的代码如下(这里省略了import的内容):
package com.cn.service;
public class DeleteDeptServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
this.doPost(request, response);//调用doPost方法
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
int depno = Integer.parseInt(request.getParameter("depno"));//获得路径中的参数
DeptDao dao = new DeptDaoImp();
dao.deleteDept(depno);//调用删除方法
response.sendRedirect("ShowAllDeptServlet");//页面重定向到查询全部部门信息的Servlet
out.flush();
out.close();
}
}
在DeleteDeptServlet的doGet()方法中调用了doPost()方法,doPost()方法中获得路径中传递的参数,然后调用接口实现类DeptDaoImp中的deleteDept()方法。在接口DeptDao中添加deleteDept()方法,代码如下:
public void deleteDept(int id);//根据id删除数据
在接口实现类DeptDaoImp中要实现deleteDept()方法,deleteDept()方法代码如下:
public void deleteDept(int id) {
Dept dept = (Dept) session.load(Dept.class, id);
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 com.cn.page;
import java.util.List;
import com.cn.vo.Emp;
public interface EmpPageDAO {
public List<Emp> getAll(int pageNo, int pageSize);// 查询数据信息的方法
public int maxPage();//求最大页数的方法
}
在接口中定义的方法,要在接口实现类EmpPageDAOImp中实现这些方法,接口实现类EmpPageDAOImp的代码如下(这里省略了import的内容):
package com.cn.page;
public class EmpPageDAOImp implements EmpPageDAO{
Session session = HibernateSessionFactory.getSession(); //获得Session
public List<Emp> getAll(int pageNo, int pageSize) {
session.beginTransaction();
List<Emp> list = new ArrayList<Emp>();
//把查询结果放入list集合中,查询结果是根据页数来显示记录数
list = session.createQuery("from Emp")
.setFirstResult((pageNo-1)*pageSize)//每页显示的起始数据,pageNo表示页数
.setMaxResults(pageSize) //每页显示的末条数据,pageSize表示每页显示的数量
.list();
session.getTransaction().commit(); //提交事务
return list;
}
public int maxPage(){//求最大页数的方法
int count =0;//声明一个count变量,用于存储记录数
int maxpage = 0;//声明一个maxpage变量,原来表示最大页数
session.beginTransaction();
//获取总记录数
count = (Integer)session.createQuery("select count(*) from Emp").uniqueResult();
maxpage =(count+4)/5;// 这里的5是每页显示的条数,4是每页显示条数减1
return maxpage;
}
}
14.4.2 Servlet层的代码
在数据库访问层中声明了最大页数和查询数据信息的方法后,需要在Servlet中调用这些方法。这个例子中是在ShowEmpByPageServlet类中调用DAO层的方法,ShowEmpByPageServlet类的代码如下(这里省略了import的内容):
package com.cn.page;
public class ShowEmpByPageServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
this.doPost(request, response);//调用doPost方法
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String page = request.getParameter("page");//获得地址栏中传递的页数
int pageNo=1;//声明pageNo表示当前页数
int pageSize=5;//声明pageSize表示每页显示的数量
if(page!=null){//如果获得地址栏中的页数不为null。赋值给pageNo
pageNo = Integer.parseInt(page);
}
EmpPageDAO empPageDAOImp = new EmpPageDAOImp();
List<Emp> list = new ArrayList<Emp>();
//调用EmpPageDAOImp的getAll方法,获得查询结果
list = (List<Emp>) empPageDAOImp.getAll(pageNo, pageSize);
int maxPage = empPageDAOImp.maxPage();//获得最大页数
request.setAttribute("list", list);
request.setAttribute("page", pageNo);
request.setAttribute("maxpage", maxPage);
//转发到showEmpByPage.jsp页面
request.getRequestDispatcher("showEmpByPage.jsp").forward(request, response);
out.flush();
out.close();
}
}
在Servlet中调用接口实现类EmpPageDAOImp中的getAll()方法来获得查询信息,调用maxPage()方法来获得最大页数。把获得的当前页数、最大页数和查询结果放入request对象中,转发到JSP页面中。在JSP页面获得这些信息。
14.4.3 JSP页面分页
在JSP页面中获得Servlet转发过来的数据信息后,分页显示出获得的数据信息。在JSP页面中使用到JSTL标签库来遍历数据。分页显示的JSP页面——showEmpByPage.jsp代码如下:
<%@ page language="java" import="java.util.*" pageEncoding="gb2312"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head><title>My JSP 'showEmpByPage.jsp' starting page</title></head>
<body>
<table border="1" align="center">
<tr>
<td>员工编号</td>
<td>员工姓名</td>
<td>员工所在部门</td>
<td>操作</td>
</tr>
<c:forEach var="list" items="${list}">
<tr>
<td>${list.empno }</td>
<td>${list.empname }</td>
<td>${list.dept.depname }</td>
<td>
<a href="QueryEmpById?empno=${list.empno }">修改</a>
<a href="DeleteEmpById?empno=${list.empno }">删除</a>
</td>
</tr>
</c:forEach>
</table>
<div align="center">
<c:if test="${page ==1}">首页</c:if>
<c:if test="${page > 1}"><a href="/hibernate_jsp/ShowEmpByPageServlet?page=1">首页</a></c:if>
<c:if test="${page ==1}">上一页</c:if>
<c:if test="${page > 1}"><a href="/hibernate_jsp/ShowEmpByPageServlet?page=${page-1 }">上一页</a></c:if>
<c:if test="${page == maxpage}">下一页</c:if>
<c:if test="${page < maxpage}"><a href="/hibernate_jsp/ShowEmpByPageServlet?page=${page+1 }">下一页</a></c:if>
<c:if test="${page == maxpage}">末页</c:if>
<c:if test="${page < maxpage}"><a href="/hibernate_jsp/ShowEmpByPageServlet?page=${maxpage }">末页</a></c:if>
</div>
</body>
</html>
在showEmpByPage.jsp页面中,如果当前页面是第一页,则首页和上一页变成不可点击状态,如果当前页数是最大页,则下一页和末页变成不可点击状态。启动Tomcat服务器,在IE浏览器地址栏中输入地址:“http://localhost:8080/hibernate_jsp/ShowEmpByPageServlet”,页面效果如图14.11所示。
图14.11 分页显示的首页
14.5 本章小结
本章中使用Hibernate结合Servlet和JSP对数据库表数据进行了操作。操作员工表时,添加数据涉及到部门表的信息,所以在添加员工信息时,要确保外键存在。在操作部门表时,删除部门信息需要把员工表中有外键关联的数据删除,涉及到级联删除。本章好介绍了Hibernate的分页查询。