这个项目里所有的DaoImpl没有直接继承Spring的HibernateDaoSupport,使用其中常用的方法
而是自己实现了一个带泛型的Dao支持类 ,多封装了一层以后, 具体的Dao再去继承这个支持类, 非常的nb啊.
想了一下这样设计的好处, 一是等于在底层实现了泛型 ,二是自己设计查询语句的传参(适配器) . 多一层封装还是有必要的.
不过我觉得继承方式有待改进, 项目中用的是接口+继承的菱形继承.
我想的解决方案是: 不如在定义好DaoSupport<T>类之后 ,具体的XxxDaoImpl直接继承于DaoSupport<T>再实现业务的IXxxDao接口 ,而IXxxDao接口只去定义自己需要的操作就足够了 就别再继承于最根上的Dao了(别用的着,用不着的方法都继承过来).
一:支持类
这个是菱形的顶端
public interface BaseDao<T> {
//基本数据库操作方法
public void save(Object obj);//保存数据
//saveOrUpdate...update...
public T get(Serializable entityId);//加载实体对象
public T load(Serializable entityId);//加载实体对象
public Object uniqueResult(String hql, Object[] queryParams);//使用hql语句操作
//分页操作
public long getCount();//获取总信息数
public PageModel<T> find(int pageNo, int maxResult);//普通分页操作
public PageModel<T> find(int pageNo, int maxResult,String where, Object[] queryParams);//搜索信息分页方法
public PageModel<T> find(int pageNo, int maxResult,Map<String, String> orderby);//按指定条件排序分页方法
public PageModel<T> find(String where, Object[] queryParams,
Map<String, String> orderby, int pageNo, int maxResult);//按指定条件分页和排序的分页方法
}
二:DaoSupport<T>
是默认的具体实现
1.@Transactional是Spring事务处理边界的声明, 感觉还是在xml里写明白了好一点...
2.实现了spring提供的HibernateTemplate
@Transactional
@SuppressWarnings("unchecked")
public class DaoSupport<T> implements BaseDao<T>{
// 泛型的类型
protected Class<T> entityClass = GenericsUtils.getGenericType(this.getClass());
// Hibernate模板
@Autowired
protected HibernateTemplate template;
public HibernateTemplate getTemplate() {
return template;
}
3.泛型转换工具
entityClass 属性提供了泛型的具体类型
用反射写的, 能看懂 写不出来...记录一下
public static Class getGenericType(Class clazz){
Type genType = clazz.getGenericSuperclass();//得到泛型父类
Type[] types = ((ParameterizedType) genType).getActualTypeArguments();
if (!(types[0] instanceof Class)) {
return Object.class;
}
return (Class) types[0];
}
public static String getGenericName(Class clazz){
return clazz.getSimpleName();
}
4.封装HQL
这个封装的是uniqueResult,
封装之后 第一个参数是hql语句, 第二个参数是查询条件
回调结果
@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
public Object uniqueResult(final String hql,final Object[] queryParams) {
return getTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException,
SQLException {
Query query = session.createQuery(hql);//执行查询
setQueryParams(query, queryParams);//设置查询参数
return query.uniqueResult();
}
});
}
参数一是查询条件,
参数二是参数,
三是排序的依据 ,
四五是分页的参数
这样具体业务中, 所有查询都能用一个find()搞定, 不同的用途只是传参不一样而已
@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
public PageModel<T> find(final String where, final Object[] queryParams,
final Map<String, String> orderby, final int pageNo,
final int maxResult) {
final PageModel<T> pageModel = new PageModel<T>();//实例化分页对象
pageModel.setPageNo(pageNo);//设置当前页数
pageModel.setPageSize(maxResult);//设置每页显示记录数
getTemplate().execute(new HibernateCallback() {//执行内部方法
public Object doInHibernate(Session session)
throws HibernateException, SQLException {
String hql = new StringBuffer().append("from ")//添加form字段
.append(GenericsUtils.getGenericName(entityClass))//添加对象类型
.append(" ")//添加空格
.append(where == null ? "" : where)//如果where为null就添加空格,反之添加where
.append(createOrderBy(orderby))//添加排序条件参数
.toString();//转化为字符串
Query query = session.createQuery(hql);//执行查询
setQueryParams(query,queryParams);//为参数赋值
List<T> list = null;//定义List对象
// 如果maxResult<0,则查询所有
if(maxResult < 0 && pageNo < 0){
list = query.list();//将查询结果转化为List对象
}else{
list = query.setFirstResult(getFirstResult(pageNo, maxResult))//设置分页起始位置
.setMaxResults(maxResult)//设置每页显示的记录数
.list();//将查询结果转化为List对象
//定义查询总记录数的hql语句
hql = new StringBuffer().append("select count(*) from ")//添加hql语句
.append(GenericsUtils.getGenericName(entityClass))//添加对象类型
.append(" ")//添加空格
.append(where == null ? "" : where)//如果where为null就添加空格,反之添加where
.toString();//转化为字符串
query = session.createQuery(hql);//执行查询
setQueryParams(query,queryParams);//设置hql参数
int totalRecords = ((Long) query.uniqueResult()).intValue();//类型转换
pageModel.setTotalRecords(totalRecords);//设置总记录数
}
pageModel.setList(list);//将查询的list对象放入实体对象中
return null;
}
});
return pageModel;//返回分页的实体对象
}
三:业务Dao接口
就是IXxxDao
这继承了另一个顶级的接口,为的是填充更多的抽象方法
public interface UserDao extends BaseDao<User> {
public User login(String username, String password);
public boolean isUnique(String username);
}
四:业务Dao的实现
就是XxxDaoImpl
它继承于DaoSupport<>是为了继承基本的get ,load ,find方法
实现匹配的业务Dao是要实现具体的 新的方法
public class UserDaoImpl extends DaoSupport<User> implements UserDao {
//@Override
@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
public User login(String username, String password) {
if(username != null && password != null){//如果用户名和密码不为空
String where = "where username=? and password=?";//设置查询条件
Object[] queryParams = {username,password};//设置参数对象数组
List<User> list = find(-1, -1, where, queryParams).getList();//执行查询方法
if(list != null && list.size() > 0){//如果list集合不为空
return list.get(0);//返回List中的第一个存储对象
}
}
return null;//返回空值
}