首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

9.3  DAO组件层

业务逻辑层组件依赖于持久层组件,而持久层组件则提供数据表的基本CRUD操作。通过持久层组件,使业务逻辑层组件的实现与特定数据库访问分离,从而提高系统的解耦。

9.3.1  DAO组件的结构

通过第8章关于DAO模式的介绍可知,DAO模式需要为每个DAO组件编写DAO接口,同时至少提供一个实现类,根据不同需要,可能有多个实现类。

为了让逻辑组件与具体的DAO组件分离,还必须有一个DAO工厂。

图9.2是本系统的DAO组件接口的类图。图9.3是本系统系统DAO组件实现类的类图。此处的实现类都是基于Hibernate的实现。

图9.2  DAO组件接口的类图

+getNewsReview:NewsReview

 

图9.3  DAO组件实现类的类图

9.3.2  编写DAO接口

DAO接口包类里有5个DAO,其中DAO是一个具有一般性的DAO接口,其他DAO接口都继承这个DAO。这里选择DAO与NewsDAO作为示例。

DAO接口的代码如下:

public interface DAO

{

    //返回全部的物品

    public List getObjects(Class class);

    //根据id返回某个持久化类

     public Object getObject(Class class, Serializable id);

    //保存持久化类

    public void saveObject(Object o);

    //删除某个持久化类

    public void removeObject(Class class, Serializable id);

}

下面对各个方法进行简要说明。

—  getObject是获取所有该类型对象的方法。输入参数是某个类的类型,相当于取出一个表所有行的sql语句。

—  getObject封装的是读取单条记录的操作。

—  saveObject封装的是插入或更新单条记录的操作。插入或更新取决于该对象是否已被持久化过。

—  removeObject封装的是删除单条记录的操作。

由此可见,DAO的实质就是对数据表的CRUD原子操作。

一般的DAO的实现要求用到Java的反射机制,因此对于初学者不容易实现。但实现之后可以通过实现类对任何PO进行操作。通常,我们用每个类各自的DAO对该类进行CRUD操作。

NewsDAO接口的代码如下:

public interface NewsDAO extends DAO

{

    //根据id返回News持久化类

    public News getNews(Long newsId);

    //保存消息

    public void saveNews(News news);

    //删除消息

    public void removeNews(Long newsId);

}

可以看到NewsDAO里并没有封装取出所有News的操作,其实封不封装该操作取决于业务需求。在这个系统里面没有取出所有News的需求,因此可以不封装。如果要考虑扩展系统的话,也可以先封装,在扩展的时候使用。

注意:接口的使用在这里起了很重要的作用。接口就是定义与实现的分离,在一个面向对象的系统中,其功能是由很多对象协作完成。各个对象是如何实现的,对系统设计人员来讲是透明的;而各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都要着重考虑,这也是系统设计的主要工作内容。然而通过多态引入接口可以降低对象之间的依赖,解除耦合。很多经典的设计模式都离不开接口,因此,更深层次理解接口是提高技术水平的必不可少的步骤,有兴趣的读者可以参考相关设计模式方面的书籍。

下面依次是UserDAO、CategoryDAO及NewsReviewDAO的源代码:

UserDAO的源代码:

public interface UserDAO extends DAO {

    /**

     * 根据用户名获取User

     * @param username 需要访问的用户名

     * @return 用户名对应的用户

     */

    public User getUser(String username);

    /**

     * 保存用户

     * @param 需要保存的用户

     */

    public void saveUser(User user);

    /**

     * 根据用户名,删除用户,

     * @param username 需要删除用户的用户名

     */

    public void removeUser(String username);

CategoryDAO的源代码:

public interface CategoryDAO extends DAO {

    /**

     * 根据id获取种类

     * @parameter categoryId 需要加载的种类id

     * @return 种类id对应的种类

     */

    public Category getCategory(Long categoryId);

    /**

     * 保存消息分类

     * @parameter category需要保存的消息分类

     */

    public void saveCategory(Category category);

    /**

     * 根据消息id删除消息分类

     * @ categoryId 需要删除的消息分类id

     */

    public void removeCategory(Long categoryId);

    /**

     * 获取全部消息分类

     * @return 返回数据库中全部消息分类

     */

    public List getCategories();

}

NewsReviewDAO的源代码:

public interface NewsReviewDAO extends DAO{

    /**

     * 根据回复id获取消息回复

     * @return id对应的消息回复

     */

    public NewsReview getNewsReview(Long newsReviewId);

    /**

     * 保存特定的消息回复

     * @parameter newsReview需要保存的消息回复。

     */

    public void saveNewsReview(NewsReview newsReview);

    /**

     * 根据回复id删除消息回复

     * @parameter newsReviewId需删除的消息回复id

     */

    public void removeNewsReview(Long newsReviewId);

}

9.3.3  编写DAO的具体实现

编写DAO的具体实现在这里也很简单,下面是NewsDAO接口的Hibernate实现的源代码:

NewsDAOHibernate继承BaseDAOHibernate,实现了NewsDAO

public class NewsDAOHibernate extends BaseDAOHibernate

implements NewsDAO

{

    //根据主键查找News持久化对象

    public News getNews(Long id)

    {

          News news = (News) getHibernateTemplate().get(News.class, id);

        //如果不能加载该持久化对象,抛出异常

          if (news == null)

        {

             throw new ObjectRetrievalFailureException(News.class, id);

         }

          return news;

    }

    //保存消息

    public void saveNews(News news)

    {

          getHibernateTemplate().saveOrUpdate(news);

    }

    //根据主键删除消息

    public void removeNews(Long id)

    {

          getHibernateTemplate().delete(getNews(id));

    }

}

NewsDAO的Hibernate实现继承了BaseDAOHibernate,下面是BaseDAOHibernate的源代码:

public class BaseDAOHibernate extends HibernateDaoSupport

implements DAO

{

    //提供日志功能

    protected final Log log = LogFactory.getLog(getClass());

    //保存对象

    public void saveObject(Object o)

    {

          getHibernateTemplate().saveOrUpdate(o);

    }

    //根据持久化类的类,主键获取对象

    public Object getObject(Class clazz, Serializable id)

    {

          Object o = getHibernateTemplate().get(clazz, id);

        //如果没有获得该对象

          if (o == null)

        {

               throw new ObjectRetrievalFailureException(clazz, id);

          }

        return o;

    }

    //查找某个持久化类的全部实例,查找到数据库对应表的全部记录

    public List getObjects(Class clazz)

    {

        return getHibernateTemplate().loadAll(clazz);

    }

    //根据主键,删除某个持久化类的特定实例,对应删除数据库的特定记录

    public void removeObject(Class clazz, Serializable id)

    {

          getHibernateTemplate().delete(getObject(clazz, id));

    }

}

BaseDAOHibernate就是前面所说的一般DAO接口的实现,里面附加了日志(log)功能,增强了系统的可维护性和可管理性。这里的DAO实现都很简洁,只需要简单的一行代码就分别实现CRUD操作。这得益于Spring的强大功能:Spring提供了HibernateDaoSupport工具类以及HibernateTemplate,其中HibernateTemplate允许以模板化方式的操作访问数据库。

注意:前面提到DAO需要封装数据源,而在这个DAO里面我们感觉不到数据源的存在,这也得益于Spring和Hibernate的封装,对数据源的访问放在配置文件里管理。

下面依次是UserDAO、CategoryDAO和NewsReviewDAO实现类的源代码。这些实现类都基于Spring的Hibernate支持,因此非常简单。

UserDAOHibernate的源代码如下:

public class UserDAOHibernate extends BaseDAOHibernate

implements UserDAO

{

    /**

     * 根据用户名获取User

     * @param username 需要访问的用户名

     * @return 用户名对应的用户

     */

    public User getUser(String username) {

        User user = (User) getHibernateTemplate().get(User.class, username);

        if(user == null){

          log.warn("user '" + username + "' not found...");

        }

        return user;

    }

    /**

     * 保存用户

     * @param 需要保存的用户

     */

    public void saveUser(final User user) {

        if (log.isDebugEnabled()) {

            log.debug("user's id: " + user.getUsername());

        }       

       getHibernateTemplate().saveOrUpdate(user);

        // necessary to throw a DataIntegrityViolation and catch it in UserManager

        getHibernateTemplate().flush();

    }

    /**

     * 根据用户名,删除用户,

     * @param username 需要删除用户的用户名

     */

    public void removeUser(String username) {

        getHibernateTemplate().delete(getUser(username));

    }

}

CategoryDAOHibernate的源代码如下:

public class CategoryDAOHibernate extends BaseDAOHibernate

implements

         CategoryDAO

{

    /**

     * 根据id获取种类

     * @parameter categoryId 需要加载的种类id

     * @return 种类id对应的种类

     */

    public Category getCategory(Long id) {

        Category category = (Category) getHibernateTemplate().get(

                Category.class, id);

        if (category == null) {

            throw new ObjectRetrievalFailureException(Category.class, id);

        }

        return category;

    }

    /**

     * 保存消息分类

     * @parameter category需要保存的消息分类

     */

    public void saveCategory(Category category) {

        getHibernateTemplate().saveOrUpdate(category);

    }

    /**

     * 根据消息id删除消息分类

     * @ categoryId 需要删除的消息分类id

     */

    public void removeCategory(Long id) {

        getHibernateTemplate().delete(getCategory(id));

    }

    /**

     * 获取全部消息分类

     * @return 返回数据库中全部消息分类

     */

    public List getCategories() {

        return getHibernateTemplate().find("from Category");

    }

}

NewsReviewDAOHibernate的源代码如下:

public class NewsReviewDAOHibernate extends BaseDAOHibernate

implements

         NewsReviewDAO

{

    /**

     * 根据回复id获取消息回复

     * @return id对应的消息回复

     */

    public NewsReview getNewsReview(Long id) {

        NewsReview newsReview = (NewsReview) getHibernateTemplate().get(

                NewsReview.class, id);

        if (newsReview == null) {

             throw new ObjectRetrievalFailureException(NewsReview.class, id);

        }

        return newsReview;

    }

    /**

     * 保存特定的消息回复

     * @parameter newsReview需要保存的消息回复。

     */

    public void saveNewsReview(NewsReview newsReview) {

        getHibernateTemplate().saveOrUpdate(newsReview);

    }

    /**

     * 根据回复id删除消息回复

     * @parameter newsReviewId需删除的消息回复id

     */

    public void removeNewsReview(Long id) {

        getHibernateTemplate().delete(getNewsReview(id));

    }

}

9.3.4  用Spring容器代替DAO工厂

通常情况下,引入接口就不可避免需要引入工厂来负责DAO组件的生成。但根据第5章的介绍可知,Spring实现了两种基本模式:单态模式和工厂模式。而使用Spring可以完全避免使用工厂模式,因为Spring就是个功能非常强大的工厂。因此,完全可以让Spring充当DAO工厂。

由Spring充当DAO工厂时,无须程序员自己实现工厂模式,只需要将DAO组件配置在Spring容器中,由ApplicationContext负责管理DAO组件的创建即可。借助于Spring提供的依赖注入,其他组件甚至不用访问工厂,一样可以直接使用DAO实例。

正如在工厂模式里必须要提供接口的实现类一样。此处的配置必须提供实现类,而不能仅提供接口,下面的配置代码是在applicationContext.xml里面配置了DAO组件。

<!--  配置DAO组件,必须提供DAO的实现类-->

<bean id="dao" class="org.yeeku.dao.hibernate.BaseDAOHibernate">

        <property name="sessionFactory" ref="sessionFactory"/>

</bean>

<!--  配置DAO组件,必须提供DAO的实现类-->

<bean id="newsDAO" class="org.yeeku.dao.hibernate.NewsDAOHibernate">

        <property name="sessionFactory" ref="sessionFactory"/>

</bean>

在上面配置的property子元素里,引用了Hibernate的SessionFactory。其中,SessionFactory负责产生Hibernate Session。Hibernate的持久化操作必须在Session管理下完成。NewsDAOHibernate实现类并没有提供 setSessionFactory方法,该方法由其父类HibernateDaoSupport提供,用于为DAO组件依赖注入SessionFactory。

依此类推,编写其他几个PO的DAO接口和Hibernate实现,将它们配置在Spring的容器中。

通常建议将DAO组件以单独的配置文件配置,下面是daoContext.xml文件的源代码,该文件负责配置所有的DAO组件,并使用了继承简化DAO组件的配置:

<?xml version="1.0" encoding="GBK"?>

<!--  Spring配置文件的文件头,包含DTD等信息-->

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"

    "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

    <!--  DAO模板,用于被其他的DAO组件继承 -->

    <bean id="daoTemplate" abstract="true" lazy-init="true">

        <property name="sessionFactory" ref="sessionFactory"/>

    </bean>

    <!-- Generic DAO - can be used when doing standard CRUD -->

    <bean id="dao" class="org.yeeku.dao.hibernate.BaseDAOHibernate"

        parent="daoTemplate"/>

    <!--  配置普通的DAO组件:UserDAO:  -->

    <bean id="userDAO" class="org.yeeku.dao.hibernate.UserDAOHibernate"

        parent="daoTemplate"/>

    <!--  配置普通的DAO组件:NewsDAO -->

    <bean id="newsDAO" class="org.yeeku.dao.hibernate.NewsDAOHibernate"

        parent="daoTemplate"/>

    <!--  配置普通的DAO组件:NewsReviewDAO-->

    <bean id="newsReviewDAO" class="org.yeeku.dao.hibernate.

NewsReviewDAOHibernate"

        parent="daoTemplate"/>

    <!--  配置普通的DAO组件:CategoryDAO -->

    <bean id="categoryDAO" class="org.yeeku.dao.hibernate.CategoryDAOHibernate"

        parent="daoTemplate"/>

</beans>

至此,我们已经完成了Spring与Hibernate的整合。

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论