hibernate 结合servlet及 jsp 的使用
1、搭建Hibernate框架
搭建Hibernate框架,大家都不陌生,我这里也不再重复。新建一个项目ServletHibernate,把连接MySQL数据库的jar包、Hibernate所需的jar包和JSTL标签库的jar包拷贝到该工程的WebContent/WEB-INF/lib目录下.
2、创建数据库文件
为了使例子简单易懂,创建数据库表时,表字段很少。本章的例子只需两张表,一张部门表和一张员工表。部门表的主键设置成自动增长。部门表和员工表是一对多的关系,所以在员工表中,部门表的主键作为员工表的外键,员工表的主键设置成自动增长。
-- ----------------------------
-- Table structure for `dept`
-- ----------------------------
DROP TABLE IF EXISTS `dept`;
CREATE TABLE `dept` (
`depno` int(11) NOT NULL AUTO_INCREMENT,
`depname` varchar(255) DEFAULT NULL,
PRIMARY KEY (`depno`)
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for `emp`
-- ----------------------------
DROP TABLE IF EXISTS `emp`;
CREATE TABLE `emp` (
`empno` int(11) NOT NULL AUTO_INCREMENT,
`empname` varchar(255) DEFAULT NULL,
`password` 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=2 DEFAULT CHARSET=utf8;
3、编写映射文件创建实体类
部门表对应的实体:
public class Dept implements Serializable{
/**1
*
*/
private static final long serialVersionUID = 1L;
private Integer depno;
private String depname;
private Set emps = new HashSet(0);
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;
}
public Integer getDepno() {
return depno;
}
public void setDepno(Integer depno) {
this.depno = depno;
}
public String getDepname() {
return depname;
}
public void setDepname(String depname) {
this.depname = depname;
}
public Set getEmps() {
return emps;
}
public void setEmps(Set emps) {
this.emps = emps;
}
@Override
public String toString() {
return "Dept [depno=" + depno + ", depname=" + depname + ", emps=" + emps + "]";
}
}
Dept类中有3个属性depno和depname对应数据库表的字段。Set集合对应的是一对多的多方,这里是员工实体类。Dept类的对应的映射文件和实体类在同一包下,代码如下:编写Hibernate配置文件
<?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.nercl.model.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.nercl.model.Emp" /><!-- 一对多关系映射 -->
</set>
</class>
</hibernate-mapping>
员工表对应的实体:
public class Emp implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private Integer empno;
private Dept dept;//部门实体类对象
private String empname;
private String password;
public Emp() {
}
public Emp(Integer empno) {
this.empno = empno;
}
public Emp(Integer empno, Dept dept, String empname,String password) {
this.empno = empno;
this.dept = dept;
this.empname = empname;
this.password = password;
}
public Integer getEmpno() {
return empno;
}
public void setEmpno(Integer empno) {
this.empno = empno;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
public String getEmpname() {
return empname;
}
public void setEmpname(String empname) {
this.empname = empname;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "Emp [empno=" + empno + ", dept=" + dept + ", empname=" + empname + ", password=" + password + "]";
}
}
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">
<hibernate-mapping>
<class name="com.nercl.model.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.nercl.model.Dept" fetch="select">
<column name="depno" />
</many-to-one>
<property name="empname" type="java.lang.String">
<column name="empname" />
</property>
<property name="password" type="java.lang.String">
<column name="password" />
</property>
</class>
</hibernate-mapping>
4、编写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">
<hibernate-configuration>
<session-factory>
<!-- 连接数据库的配置 -->
<property name="current_session_context_class">thread</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/bank</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="show_sql">true</property>
<property name="hibernate.connection.password">root</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 实体类的映射文件 -->
<mapping resource="com/nercl/model/Dept.hbm.xml"/>
<mapping resource="com/nercl/model/Emp.hbm.xml"/>
</session-factory>
</hibernate-configuration>
5、编写HibernateSessionFactory类
HibernateSessionFactory类是原来初始化Hibernate的,使用Hibernate开发时,必须编写该类。
public class HibernateSessionFactory {
private static Configuration cf = null;
private static SessionFactory sf = null;
static {
try {
cf = new Configuration().configure();
sf = cf.buildSessionFactory();// 创建session
System.out.println("SessionFactory创建成功!");
} 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.getCurrentSession();
} 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);
}
}
}
6、登录操作
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>用户登录</title>
</head>
<body>
<form action="LoginServlet" method="post">
用户名:<input type="text" name="username">
密码:<input type="password" name="password">
<input type="submit" value="登录">
</form>
</body>
</html>
上述代码中,from表单提交到LoginServlet中,使用post提交方式
b) Servlet处理类 LoginServlet代码如下:(这里使用的servlet3.0新特性:注解,如果不采用这种方式需要在web.xml中进行配置)
/**
* Servlet implementation class LoginServlet
*/
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public LoginServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doPost(request,response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.setCharacterEncoding("utf-8");//设置response编码方式
request.setCharacterEncoding("utf-8");//设置request编码方式
//获取前台传递过来的数据
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println("username==="+username+"password====="+password);
EmpDao empDao = new EmpDaoImpl();
//判断是否存在
if(empDao.check(username,password)!=null){
request.getRequestDispatcher("index.jsp").forward(request, response);
}else{
request.getRequestDispatcher("login.jsp").forward(request, response);
}
}
}
上述代码中有这样一行代码:
EmpDao dao = new EmpDaoImp();
其中EmpDao是一个接口,EmpDaoImp是接口实现类。这一行代码是接口实现类的对象指向接口的引用。
c) 接口以及接口实现类
接口类EmpDao中代码如下:
public interface EmpDao extends BaseDao<Emp>{
public Emp check(String username, String password);
}
上述代码出现了extends关键字,这里我继承了基本的Dao操作,这个基本dao提供常用的一些数据库操作的方法。
BaseDao代码如下:
public interface BaseDao<T>{
public void save(T entity);
public void update(T entity);
public void delete(Serializable id);
public T findById(Serializable id);
public List<T> findByHQL(String hql, Object... params);
public List<T> findAll(String hql);
}
他们想对应的实现类如下:
public class EmpDaoImpl extends BaseDaoImpl<Emp> implements EmpDao {
@Override
public Emp check(String username, String password) {
// TODO Auto-generated method stub
Emp emp = null;
//这里调用父类的获取session的方法
Session session = this.getSession();
session.beginTransaction();
Query query = session.createQuery("from Emp e where e.empname = ? and e.password = ?").setParameter(0, username).setParameter(1, password);
emp = (Emp)query.uniqueResult();
return emp;
}
}
public class BaseDaoImpl<T> implements BaseDao<T>{
private Class<T> clazz;
/**
* 通过构造方法指定DAO的具体实现类
*/
@SuppressWarnings("unchecked")
public BaseDaoImpl() {
ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
clazz = (Class<T>) type.getActualTypeArguments()[0];
}
/**
* 获取当前工作的Session
*/
protected Session getSession() {
return HibernateSessionFactory.getSession();
}
@Override
public void save(T entity) {
// TODO Auto-generated method stub
System.out.println("执行保存方法 start!!");
//this.getSession.save(entity);
//直接使用这个会出现一种情况,保存后数据库没有数据。
//但是使用数据库管理工具添加数据,本来是没有记录的,插入数据之后ID竟然不是从一开始的
//出现这种的现象的原因是事务没有开启。
//hibernate成功执行sava且不报错后,数据库中没有数据的原因:hibernate 必须显示的声明提交事务
Session session = this.getSession();
session.beginTransaction();
session.save(entity);
session.beginTransaction().commit();
System.out.println("执行保存方法 end!!");
}
@Override
public void update(T entity) {
// TODO Auto-generated method stub
//参考save方法修改
this.getSession().update(entity);
}
@Override
public void delete(Serializable id) {
// TODO Auto-generated method stub
Session session = this.getSession();
session.beginTransaction();
session.delete(this.findById(id));
session.beginTransaction().commit();
}
@SuppressWarnings("unchecked")
@Override
public T findById(Serializable id) {
// TODO Auto-generated method stub
Session session = this.getSession();
session.beginTransaction();
return (T)session.get(this.clazz, id);
}
@SuppressWarnings("unchecked")
@Override
public List<T> findByHQL(String hql, Object... params) {
// TODO Auto-generated method stub
Query query = this.getSession().createQuery(hql);
for (int i = 0; params != null && i < params.length; i++) {
query.setParameter(i, params);
}
return query.list();
}
@SuppressWarnings("unchecked")
@Override
public List<T> findAll(String hql) {
// TODO Auto-generated method stub
Session session = this.getSession();
session.beginTransaction();
Query query = session.createQuery(hql);
return query.list();
}
}
编写好这些代码以后就可以实现基本的登录操作咯。登录之后可以对部门进行添加删除等操作。方法同上面就不在写了。