以前没有Dao设计模型之前,一般都是这样的流程:
①先设计实体对象
学生对象:
package com.itheima.domain; import java.io.Serializable; import java.util.Date; public class Student implements Serializable { private Integer id;//可以为null private String name; private Date birthday; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } @Override public String toString() { return "Student [id=" + id + ", name=" + name + ", birthday=" + birthday + "]"; } }
客户对象:
package com.itheima.domain; import java.io.Serializable; public class Customer implements Serializable { private Integer id; private String name; private String gender; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } @Override public String toString() { return "Customer [id=" + id + ", name=" + name + ", gender=" + gender + "]"; } }
②设计Dao层
学生Dao
客户Dao
③Dao实现
学生Dao实现
客户Dao实现类似
可以发现,这样Dao多起来后,有很多的重复代码,主要集中在增删改查4个方法上面.
改进
一.在Dao包中,添加一个Dao接口
package com.itheima.dao; import java.io.Serializable; public interface Dao<T> { void add(T t); void update(T t); /** * 根据主键查询一个对象 * @param id * @return */ T findOne(Serializable id); /** * 根据主键删除一个对象 * @param id */ void del(Serializable id); }
二.在DaoImpl包下新建一个简单的BaseDao类(这里是重点),实现Dao接口
package com.itheima.dao.impl; import java.io.Serializable; import org.hibernate.Session; import org.hibernate.Transaction; import com.itheima.dao.Dao; import com.itheima.util.SessionFactoryUtil; public abstract class BaseDao<T> implements Dao<T> { private Class clazz;//记住外面传递过来的实体类型 public BaseDao(Class clazz){ this.clazz = clazz; } public void add(T t) { Session session = null; try{ session = SessionFactoryUtil.getSession(); Transaction tx = session.beginTransaction(); session.save(t); tx.commit(); }catch(Exception e){ throw new RuntimeException(e); }finally{ session.close(); } } public T findOne(Serializable id) { Session session = null; try{ session = SessionFactoryUtil.getSession(); return (T)session.get(clazz, id); }catch(Exception e){ throw new RuntimeException(e); }finally{ session.close(); } } public void update(T t) { Session session = null; try{ session = SessionFactoryUtil.getSession(); Transaction tx = session.beginTransaction(); session.update(t); tx.commit(); }catch(Exception e){ throw new RuntimeException(e); }finally{ session.close(); } } public void del(Serializable id) { Session session = null; try{ session = SessionFactoryUtil.getSession(); Transaction tx = session.beginTransaction(); T bean = (T)session.get(clazz, id); session.delete(bean); tx.commit(); }catch(Exception e){ throw new RuntimeException(e); }finally{ session.close(); } } }
三.修改具体的实现类
修改客户dao实现类
package com.itheima.dao.impl; import java.util.List; import com.itheima.dao.CustomerDao; import com.itheima.domain.Customer; public class CustomerDaoImpl extends BaseDao<Customer> implements CustomerDao { public CustomerDaoImpl(Class clazz) { super(Customer.class); } public List<Customer> findPageCustomer(int startIndex, int size) { return null; } }
修改学生dao实现类
package com.itheima.dao.impl; import java.util.List; import com.itheima.dao.StudentDao; import com.itheima.domain.Student; public class StudentDaoImpl extends BaseDao<Student> implements StudentDao { //继承BaseDao,没有构造方法,需要构造方法,告诉父类,查的是那个类,上面的customer一样 public StudentDaoImpl(Class clazz) { super(Student.class); } public List<Student> findAll() { return null; } }
四.service测试
Student.cfg.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.itheima.domain"> <class name="Student" table="STUDENTS"> <id name="id" column="ID"> <!-- 根据数据库的能力管理主键 --> <generator class="native"></generator> </id> <property name="name" column="NAME"></property> <property name="birthday" column="BIRTHDAY"></property> </class> </hibernate-mapping>
Cusstomer.cfg.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.itheima.domain"> <class name="Customer" table="CUSTOMERS"> <id name="id" column="ID"> <!-- 根据数据库的能力管理主键 --> <generator class="native"></generator> </id> <property name="name" column="NAME"></property> <property name="gender" column="GENDER"></property> </class> </hibernate-mapping>
把配置文件交给hibernate管理
hibernate文件hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- 配置Hibernate:属性配置参考 Hibernate发型包projectetchibernate.properties --> <!-- JDBC的基本链接 --> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="connection.username">root</property> <property name="connection.password">sorry</property> <property name="connection.url">jdbc:mysql://localhost:3306/day22</property> <!-- 配置数据库方言 --> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <!-- 根据映射产生表结构的类型: create-drop:木有表结构创建,下次启动时删除重新创建。适合学习阶段 create:只做创建 update:探测表结构够的变化,对于数据库没有的,进行更新操作。适合学习阶段 validate:对比与数据库的结构 --> <property name="hibernate.hbm2ddl.auto">update</property> <!-- 显示sql语句及格式:开发调试阶段非常有用 --> <property name="hibernate.show_sql">true</property> <property name="hibernate.format_sql">true</property>
<--最主要的就是这个--> <!-- 告知映射文件 --> <mapping resource="com/itheima/domain/Student.hbm.xml"/> <mapping resource="com/itheima/domain/Customer.hbm.xml"/> </session-factory> </hibernate-configuration>
Dao测试
package com.itheima.test; import java.util.Date; import com.itheima.dao.CustomerDao; import com.itheima.dao.StudentDao; import com.itheima.dao.impl.CustomerDaoImpl; import com.itheima.dao.impl.StudentDaoImpl; import com.itheima.domain.Customer; import com.itheima.domain.Student; public class DaoTest { public static void main(String[] args) { CustomerDao cDao = new CustomerDaoImpl(Customer.class); StudentDao sDao = new StudentDaoImpl(Student.class); Customer c = new Customer(); c.setName("刘亚雄"); c.setGender("待定"); cDao.add(c); Student s = new Student(); s.setName("吕云雪"); s.setBirthday(new Date()); sDao.add(s); } }
结果:
customer表
student表
这就是Dao设计模型
虚线是实现接口,实线是继承类
BaseDao上有个abstract,注意:
为什么一个类里面没有抽象方法,还要定义声明为抽象类?
原因很简单:就是不让直接使用,干嘛不让?
BaseDao不让直接使用,是用来继承使用的.其实HTTPServlet就是典型,HTTPServlet是抽象类,里面有一个非抽象的方法doXXX(忘记叫什么名了)
继承后,满意的方法直接使用,不满意的方法直接覆盖掉就好了.
以上写法还不够优雅!下面来修改:
一.修改StudentDaoImpl实现类,其实就是去掉构造方法
package com.itheima.dao.impl; import java.util.List; import com.itheima.dao.StudentDao; import com.itheima.domain.Student; public class StudentDaoImpl extends BaseDao<Student> implements StudentDao { // public StudentDaoImpl(Class clazz) { // super(Student.class); // } public List<Student> findAll() { return null; } }
二.修改CustomerDaoImpl实现类,其实就是去掉构造方法
package com.itheima.dao.impl; import java.util.List; import com.itheima.dao.CustomerDao; import com.itheima.domain.Customer; public class CustomerDaoImpl extends BaseDao<Customer> implements CustomerDao { // public CustomerDaoImpl() { // super(); // } public List<Customer> findPageCustomer(int startIndex, int size) { return null; } }
三.修改BaseDao类
package com.itheima.dao.impl; import java.io.Serializable; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import org.hibernate.Session; import org.hibernate.Transaction; import com.itheima.dao.Dao; import com.itheima.util.SessionFactoryUtil; public abstract class BaseDao<T> implements Dao<T> { private Class clazz;//实体类型 public BaseDao(){ //给clazz赋值:需要知道操作的是哪个实体类,从而知道操作那张表 Type type = this.getClass().getGenericSuperclass();//得到当前实例的带有泛型类型的父类 ParameterizedType ptype = (ParameterizedType)type;//因为父类型带有泛型信息,就可以转为ParameterizedType(参数化的泛型类型) clazz = (Class)ptype.getActualTypeArguments()[0];// Customer|Student.class } public void add(T t) { Session session = null; try{ session = SessionFactoryUtil.getSession(); Transaction tx = session.beginTransaction(); session.save(t); tx.commit(); }catch(Exception e){ throw new RuntimeException(e); }finally{ session.close(); } } public T findOne(Serializable id) { Session session = null; try{ session = SessionFactoryUtil.getSession(); return (T)session.get(clazz, id); }catch(Exception e){ throw new RuntimeException(e); }finally{ session.close(); } } public void update(T t) { Session session = null; try{ session = SessionFactoryUtil.getSession(); Transaction tx = session.beginTransaction(); session.update(t); tx.commit(); }catch(Exception e){ throw new RuntimeException(e); }finally{ session.close(); } } public void del(Serializable id) { Session session = null; try{ session = SessionFactoryUtil.getSession(); Transaction tx = session.beginTransaction(); T bean = (T)session.get(clazz, id); session.delete(bean); tx.commit(); }catch(Exception e){ throw new RuntimeException(e); }finally{ session.close(); } } }
说明:
this代表当前对象,this有句话可以这么理解(对象永远都是这个对象,但是指向有可能向上转型)
其实上面主要就是添加以下几句代码:
Type type = this.getClass().getGenericSuperclass();//得到当前实例的带有泛型类型的父类----->CustomerDaoImpl的父类BaseDao<Customer>就是带有泛型类型的类
ParameterizedType ptype = (ParameterizedType)type;//因为父类型带有泛型信息,就可以转为ParameterizedType(参数化的泛型类型)
clazz = (Class)ptype.getActualTypeArguments()[0];// Customer|Student.class
以上几句其实就是泛型的反射应用
修改之后,优雅多了