SSH实战OA 03:设计BaseDAo

上一节已经把项目的框架环境搭建起来了。并且做了简单的测试,这一节我们主要来设计Dao共用类的。在做这项工作之前我们先来看一个问题:在开发的过程中,我们发现DAO层的主要作用就是对数据库进行增删改查。例如有用户管理、部门管理、角色管理、文章管理这四个模块:

实体 Dao接口 实现类
User UserDao UserDaoImpl
Role RoleDao RoleDaoImpl
Department DepartmentDao DepartmentDaoImpl
Article ArticleDao ArticleDaoImpl

他们各自具有方法如下:

实体 Dao 方法
User UserDao save(User user), update(), delete(), find()
Role RoleDao save(Role role), update(), delete(), find()
Student StudentDao save(Student student), update(), delete(), find()

这四个Dao类的主要作用是对数据中相对应的表进行增删改查操作,这时候为了避免重复操作,可以将他们的基本操作方法提取出来作为一个基础类的共有方法。

方法
BaseDao save(T t), update(), delete(), find()

类的模型如图:
这里写图片描述
基于Java的单继承多现实原理,我们可以设计一个通用的BaseDao接口,他包含了save(),delete(),updae(),getById(),getByIds(),findAll()等共用的方法,这个Dao有一个基本的实现类BaseDaoImpl,对这个共用接口所有的方法实现。User对应的dao实现类可以继承BaseDaoImpl也同时实现了UserDao接口,Role对应的Dao实现类可以也可以继承BaseDaoImpl同时可以实现了RoleDao的接口。共用的方法放在BaseDao接口里面,实体对应的个体的独特方法放在自己的接口里面,这样便减少重复工作量!

BaseDao:

import java.util.List;

/**
 * 泛型接口
 * @author shizongger
 * @param <T>
 */
public interface BaseDao<T> {

    public void add(T entity);

    public void delete(Long id);

    public void update(T entity);

    public T selectById(Long id);

    public List<T> selectAll();
}

BaseDaoImpl:

import java.lang.reflect.ParameterizedType;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.shizongger.oa.domain.User;

/**
 * @author shizongger
 * @param <T> 实际操作的daomain实体
 */
public abstract class BaseDaoImpl<T> implements BaseDao<T> {

    private Log log = LogFactory.getLog(this.getClass());   

    /**
     * sessionFactory工厂
     */
    @Autowired
    private SessionFactory sessionFactory;

    private Class<T> clazz;

    @SuppressWarnings("unchecked")
    public BaseDaoImpl() {
        // 使用反射技术得到T的真实类型
        ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass(); // 获取当前new的对象的 泛型的父类 类型
        this.clazz = (Class<T>) pt.getActualTypeArguments()[0]; // 获取第一个类型参数的真实类型
    }

    /**
     * 增加
     */
    @Override
    public void add(T entity) {
        log.info("add:" + entity.toString());

        getSession().save(entity);
    }

    /**
     * 删除
     */
    @Override
    public void delete(Long id) {
        Object object = selectById(id);
        if(object != null) {
            getSession().delete(object);
        }
    }

    /**
     * 修改
     */
    @Override
    public void update(T entity) {
        getSession().update(entity);
    }

    /**
     * 根据id查询
     */
    @Override
    public T selectById(Long id) {
        return (T) getSession().get(this.clazz, id);
    }

    /**
     * 根据id数组查询
     */
    @Override
    public List<T> selectAll() {
        List<T> list = getSession().createQuery("FROM " + this.clazz.getSimpleName()).list();

        return list;
    }

    protected Session getSession() {
        return sessionFactory.getCurrentSession();
    }
}

由于共有类无法判断具体的实体,只能使用泛型,在调用过程中具体传递进来的实体类型是什么类型需要用java反射机制来实现。关键代码在我们的构造方法中的这两行代码:

// 使用反射技术得到T的真实类型
ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass(); // 获取当前new的对象的 泛型的父类 类型
this.clazz = (Class<T>) pt.getActualTypeArguments()[0]; // 获取第一个类型参数的真实类型

本类中多次用到hibernate的session,所以直接把获取session做成一个protected级别的方法。为了更好的给子类继承使用该方法,不宜写为private私有级别。

    protected Session getSession() {
        return sessionFactory.getCurrentSession();
    }

这里需要注意的是:基础实现类不能new,只能new他的子类,所以这里要写abstract抽象类型。

如此便可以在不同模块的Dao调用这个公共类了。
用户增删改查对应的UserDao接口

import com.shizongger.oa.base.BaseDao;
import com.shizongger.oa.domain.User;

public interface UserDao extends BaseDao<User> {

    public User getUserByNamdAndPasswd(String username, String password);
}

userDaoImpl实现类

扫描二维码关注公众号,回复: 194194 查看本文章
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.shizongger.oa.base.BaseDaoImpl;
import com.shizongger.oa.dao.UserDao;
import com.shizongger.oa.domain.User;

@Repository
public class UserDaoImpl extends BaseDaoImpl<User> implements UserDao {

    private Log log = LogFactory.getLog(this.getClass());   

    /**
     * sessionFactory工厂
     */
    @Autowired
    private SessionFactory sessionFactory;

    /**
     * 检测用户的合法性
     */
    @Override
    public User getUserByNamdAndPasswd(String username, String password) {
        Session session = sessionFactory.getCurrentSession();
        String hql = "FROM User WHERE loginName = ? AND password = ?";
        User user = (User) session.createQuery(hql).setString(0, username)
                            .setString(1, password).uniqueResult();

        return user;
    }
}

部门管理增删改查对应的接口DepartmentDao

import java.util.List;

import com.shizongger.oa.base.BaseDao;
import com.shizongger.oa.domain.Department;

public interface DepartmentDao extends BaseDao<Department> {

    List<Department> findTopDept();

    List<Department> findChildren(String parentId);

}

DepartmentDaoImpl实现类

import java.util.List;

import com.shizongger.oa.base.BaseDao;
import com.shizongger.oa.domain.Department;

public interface DepartmentDao extends BaseDao<Department> {

    List<Department> findTopDept();

    List<Department> findChildren(String parentId);

}

下面我们来进行junit测试:
BaseJunitTest

import org.junit.runner.RunWith;  
import org.springframework.test.context.ContextConfiguration;  
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  
@RunWith(SpringJUnit4ClassRunner.class)    
@ContextConfiguration(locations = {"classpath*:*.xml"})    
public class BaseJunitTest {  

}  

UserDaoImplTest

import static org.junit.Assert.*;

import java.util.List;

import org.junit.Ignore;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.transaction.annotation.Transactional;

import com.shizongger.oa.base.BaseJunitTest;
import com.shizongger.oa.dao.UserDao;
import com.shizongger.oa.domain.User;

public class UserDaoImplTest extends BaseJunitTest {

    @Autowired
    private UserDao userDao;

    @Test
    @Ignore
    public void testGetUserByNamdAndPasswd() throws Exception {
        //TODO
    }

    @Transactional
    @Test
    @Rollback(false)
    public void testAddUser() throws Exception {
        User user = new User();
        user.setName("shizongger");

        userDao.add(user);
    }

    @Transactional
    @Test
    @Rollback(false)
    public void testDelete() throws Exception {
        userDao.delete(6L);
    }

    @Transactional
    @Test
    @Rollback(false)
    public void testUpdate() throws Exception {
        User user = (User) userDao.selectById(7L);
        if(user != null) {
            user.setName("admin");
            userDao.update(user);
        }
    }

    @Transactional
    @Test
    public void testSelectAll() throws Exception {
        List<User> list = userDao.selectAll();
        for(final User user : list) {
            System.out.println("id:" + user.getId() + ", name:" + user.getName());
        }
    }
}

我们发现调用到BaseDaoImpl的构造方法是,正确的输出了我们传递过去的javaBean类型。

项目代码托管到了GitHub,OA

猜你喜欢

转载自blog.csdn.net/zhang5476499/article/details/70478106