hibernate 结合servlet及 jsp 的使用

时间:2024-01-02 23:36:02

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所示。

hibernate 结合servlet及 jsp 的使用

图14.1 添加员工页面

在图14.1所示的页面中输入员工姓名和闭门编号以后,单击“提交”按钮,数据添加成功以后进入图14.2所示的页面。

hibernate 结合servlet及 jsp 的使用

图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所示的页面。

hibernate 结合servlet及 jsp 的使用

图14.3 修改数据页面

在图14.3所示的页面中,员工编号是只读的,不能修改。员工姓名和闭门编号可以修改。输入修改后的数据,提交表单。修改成功后,页面跳转到图14.4所示的页面。

hibernate 结合servlet及 jsp 的使用

图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所示。

hibernate 结合servlet及 jsp 的使用

图14.5 删除员工信息之前的页面

在图14.5所示的页面中删除应改变好为2的员工信息。员工编号为2的员工姓名是小张,所在部门是Java开发部。删除该条数据以后,进入图14.6所示的页面。

hibernate 结合servlet及 jsp 的使用

图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所示。

hibernate 结合servlet及 jsp 的使用

图14.7 添加部门信息页面

在图14.7所示的页面中输入部门名称后,提交表单。添加部门信息成功后页面中显示出全部的部门信息,效果如图14.8所示。

hibernate 结合servlet及 jsp 的使用

图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所示。

hibernate 结合servlet及 jsp 的使用

图14.9 删除部门信息之前的页面

在图14.9所示的页面中删除掉部门编号为2的数据,该条数据对应的部门名称为市场部。删除成功后,页面进入图14.10所示的页面。

hibernate 结合servlet及 jsp 的使用

图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所示。

hibernate 结合servlet及 jsp 的使用

图14.11 分页显示的首页

14.5 本章小结

本章中使用Hibernate结合Servlet和JSP对数据库表数据进行了操作。操作员工表时,添加数据涉及到部门表的信息,所以在添加员工信息时,要确保外键存在。在操作部门表时,删除部门信息需要把员工表中有外键关联的数据删除,涉及到级联删除。本章好介绍了Hibernate的分页查询。