建立实用且规范的DAO 操作类
J2EE中倡导的应该是面向接口,而不是面向类来编程,因为只有面向接口,才能真正做到层与层之间的解耦。面向接口编程最重要的价值在于隐藏实现,将抽象的实现细节封装起来不对外开放。
在大多数情况下,还需要对抽象类提取必要的接口,简单来做就是,把抽象DAO 类中的方法,全部抽取出来形成一个单独的接口。假如所有 DAO 的操作方法都一样,这样做没问题。但是实际上各个 DAO 类之间,尽管有大量相同的方法,但也总是存在一些不一致的方法,这样一来,问题就来了。我们总不能把接口做的很大吧 ....
接口隔离原则(ISP ):使用多个专门的接口比使用单一的总接口好!
实现这个原则的通常的方式有两种:
(1 )使用委托分离接口
(2 )使用多重继承分离接口
具体到抽象DAO 类,我们应该为所有具体的 DAO 类的共性方法抽取到抽象 DAO 类中,并将这些方法抽象为接口,之后再为每个具体的 DAO 类定义接口,在此接口中定义不再抽象 DAO 类中的方法,最后具体的 DAO 类应该继承抽象 DAO 类,同时实现本 DAO 类所对应的接口。通过这样的方式,就可以做到接口的隔离和防止大接口形成的污染了。
具体步骤如下:
1、 先建立一个HibernateSessionFactory 类来实现 Session 的创建与回收。
主要代码见下:
........
public class HibernateSessionFactory {
private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
private static Configuration configuration = new Configuration();
private static org.hibernate.SessionFactory sessionFactory;
private static String configFile = CONFIG_FILE_LOCATION;
static {
try {
configuration.configure(configFile);
sessionFactory = configuration.buildSessionFactory();
} catch (Exception e) {
System.err
.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
public static Session getSession() throws HibernateException {
Session session = (Session) threadLocal.get();
if (session == null || !session.isOpen()) {
if (sessionFactory == null) {
rebuildSessionFactory();
}
session = (sessionFactory != null) ? sessionFactory.openSession(): null;
threadLocal.set(session);
}
return session;
}
public static void closeSession() throws HibernateException {
Session session = (Session) threadLocal.get();
threadLocal.set(null);
if (session != null) {
session.close();
}
}
............
}
2、 定义一个IBaseHibernateDAO 接口,用来定义每个实体 DAO 类的公共方法,如 getSession() , save() , delete() 等,然后再建一个 BaseHibernate 类来实现该接口。
public interface IBaseHibernateDAO {
public Session getSession();
public void save(Object transientInstance);
public void delete(Object transientInstance);
}
public class BaseHibernateDAO implements IBaseHibernateDAO {
public Session getSession() {
return HibernateSessionFactory. getSession ();
}
public void delete(Object transientInstance) throws RuntimeException {
getSession().delete(transientInstance);
}
public void save(Object transientInstance) throws RuntimeException {
getSession().save(transientInstance);
}
}
3、 设计每个实体DAO 类的时候,先为其定义一个接口,定义其 特有的操作方法 ,如:
public interface IClientDAO extends IBaseHibernateDAO {
public Client findById(java.lang.String id);
public List findByExample(Client instance);
public List findByProperty(String propertyName, Object value) ;
public List findByCEmail(Object CEmail) ;
public List findByCPhone(Object CPhone) ;
public List findByCName(Object CName);
public List findByCSex(Object CSex) ;
public List findAll();
public Client merge(Client detachedInstance);
public void attachDirty(Client instance);
public void attachClean(Client instance);
}
public class ClientDAO extends BaseHibernateDAO implements IClientDAO{
private static final Log log = LogFactory.getLog(ClientDAO.class);
// property constants
public static final String _CEMAIL = "CEmail";
public static final String _CPHONE = "CPhone";
public static final String _CNAME = "CName";
public static final String _CSEX = "CSex";
public void save(Client transientInstance) {
log.debug("saving Client instance");
try {
super.save(transientInstance);
log.debug("save successful");
} catch (RuntimeException re) {
log.error("save failed", re);
throw re;
}
}
public void delete(Client persistentInstance) {
log.debug("deleting Client instance");
try {
super.delete(persistentInstance);
log.debug("delete successful");
} catch (RuntimeException re) {
log.error("delete failed", re);
throw re;
}
}
public Client findById(java.lang.String id) {
log.debug("getting Client instance with id: " + id);
try {
Client instance = (Client) getSession().get("com.DB.Entity.Client", id);
return instance;
} catch (RuntimeException re) {
log.error("get failed", re);
throw re;
}
}
public List findByExample(Client instance) {
log.debug("finding Client instance by example");
try {
List results = getSession().createCriteria("com.DB.Entity.Client").add(
Example.create(instance)).list();
log.debug("find by example successful, result size: "
+ results.size());
return results;
} catch (RuntimeException re) {
log.error("find by example failed", re);
throw re;
}
}
public List findByProperty(String propertyName, Object value) {
log.debug("finding Client instance with property: " + propertyName
+ ", value: " + value);
try {
String queryString = "from Client as model where model."
+ propertyName + "= ?";
Query queryObject = getSession().createQuery(queryString);
queryObject.setParameter(0, value);
return queryObject.list();
} catch (RuntimeException re) {
log.error("find by property name failed", re);
throw re;
}
}
public List findByCEmail(Object CEmail) {
return findByProperty(_CEMAIL, CEmail);
}
public List findByCPhone(Object CPhone) {
return findByProperty(_CPHONE, CPhone);
}
public List findByCName(Object CName) {
return findByProperty(_CNAME, CName);
}
public List findByCSex(Object CSex) {
return findByProperty(_CSEX, CSex);
}
public List findAll() {
log.debug("finding all Client instances");
try {
String queryString = "from Client";
Query queryObject = getSession().createQuery(queryString);
return queryObject.list();
} catch (RuntimeException re) {
log.error("find all failed", re);
throw re;
}
}
}
4、建立一个工厂类来对DAO进行统一的管理,该工厂类采用xml文件配置方式来反射生成DAO实例
/*
* DAO工厂类,根据配置文件自动生成 DAO 类,并提供具体方法来调用
* */
public class DAOFactory {
//建立一个 DAO 实例的缓冲池
private Map<String,Object> daoMap = new HashMap<String,Object>();
//建立 DAO 工厂实例
private static DAOFactory df ;
//初始化 DAO 工厂
public DAOFactory() throws Exception{
Document doc = new SAXReader().read( new File( " . /DAOContext.xml" ));
Element root = doc.getRootElement(); //由 document 获得 xml 文件的根元素
List list = root.elements(); //由根元素得到所有元素
for ( Iterator it = list.iterator();it.hasNext();){
Element em = (Element) it.next();
String id = em.attributeValue( "id" );
String dao = em.attributeValue( "class" ); //得到 class 表示字符串
Class daoClass = Class. forName (dao); //把该字符串变成一个具体的类
Object odj = daoClass.newInstance(); //生成该类的对象
daoMap .put(id, odj); //把该对象放到 DAO 缓冲池里
}
}
//提供一个普通的入口方法,用以返回一个 DAOFactory 的实例
public static DAOFactory instance(String path) throws Exception{
if ( df == null ){
df = new DAOFactory();
}
return df ;
}
//获得具体的 DAO 实例
public Object getDAO(String id){
return daoMap .get(id);
}
protected Session getCurrentSession(){
return com.DAO.HibernateSessionFactory. getSession ();
}
}
6、 Junit测试实例:
public class TestDAOFactory {
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
@Test
public void DAOFactoryTest(){
DAOFactory df;
try {
df = new DAOFactory();
IClientDAO clientDAO = (IClientDAO) df.getDAO( "ClientDAO" );
HibernateSessionFactory. getSession ().beginTransaction();
Client client = new Client();
client.setCVip( "0001" );
client.setCName( "zhiwei" );
client.setCSex( "m" );
client.setCPhone( "110" );
clientDAO.save(client);
HibernateSessionFactory. getSession ().getTransaction().commit();
System. out .println(clientDAO.findByCName( "zhiwei" ).toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}