`
piperzero
  • 浏览: 3456145 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

一个好用的hibernate泛型dao

 
阅读更多

以前从springside2.0上搞下来的很好用的,基本实现dao零编码只要配置xml文件就行了。

先看图:



一共4层,com.demonstration.hibernate.basedao是我加的用来进一步解耦hibernate和spring的耦合。
原来的官方解释如下:
SpringSide对Hibernate做了三层封装:

第一层:HibernateGenericDao,基于spring的HibernateDaoSupport,但加入了分页函数与各种Finder函数,并使用泛型避免了返回值强制类型转换。

第二层:HibernateEntityDao,基于HibernateGenericDao,用泛型声明Dao所管理的Entity类,默认拥有该entity的CRUD方法。

第三层:HibernateExtendDao,基于HibernateEntityDao,主要扩展各种选择性的功能。

关于三个类的详细注解请看JavaDoc,大致描述如下:

1 HibernateGenericDao
在Spring HibernateDaoSupport基础上封装的DAO,功能如下:

1.应用泛型:使得find(), get() 这些函数不再返回Object,而是返回T,不再需要强制类型转换。

2.提供各种finder的简便函数
应用了JDK5可变参数的hsql查询函数:List find(String hql, Object... values),支持find(hql),find(hql, param1); find(hql,param1,param2);find(hql,new Object[] {param1,param2}) 四种接口。

简单查询的简化函数:findBy(Class entityClass,String name,Object value) ,findUniqueBy(Class entityClass,String name, Object value),findByLike(Class entityClass,String name,Object value)

3.获得设置好的Query和Criteria:createQuery(String hql,Object... values) 和 createCriteria(Class<T> entityClass,Criterion... criterions)

Spring并没有很好的接口封装支持firstResult, maxResult, fetchsize,cache,cacheRegion 等多个查询参数,所以springside宁愿返回已设置好查询条件的Query和Criteria,让大家继续剩下的参数设置,最后再执行 list(),注意那几个参数可以连续设置的,如:

createQuery(hql,param1).setFirstResult(10).setMaxResult(20).list(); 4.分页函数:Page pagedQuery(Criteria criteria, int pageNo, int pageSize) 和Page pagedQuery(String hql, int pageNo, int pageSize, Object... args)

Page是SpringSide自行封装的一个典型Page类,pagedQuery与hibernate自身分页查询的差别是先运行一次count,获得符合条件的总记录数。

如果查询不需要总记录数,用普通的hibernate API,加上setFirstResult(),setMaxResult()就解决,不需要pagedQuery()。

5.判别对象属性在数据库中唯一的函数:isUnique(Class<T> entityClass,Object entity,String names)。

2. HibernateEntityDao
所有UserManager, ProductManager之类只管理一类对象的Manager类的基类,只需要在类定义处声明Entity类型即可

public class BookManager extends HibernateEntityDao<Book> {
} 通过<Book>的定义,避免了HibernateGenericDao类各方法中必有的Class entityClass参数。

如果需要操作其他的Entity,比如BookManager可能需要处理Category(图书目录),可以注入CategoryManager。无需担心事务的问题,JavaEE的默认事务模型已能很好处理。

如果没有对应的CategoryManager,或者各种原因不想注入的话,可以使用BookManager继承自 HibernateGenericDao的带entityClass参数的函数来操作Category的增删改,如Category category= this.get(Category.class, 1);

3. HibernateExtendDao
此类演示SpringSide 所作的一些扩展,大家可以按照自己的需要进行修改和扩展。

1. 支持对象不能被直接删除,只能设置状态列为无效。
接口UndeleteableEntityOperation,定义了要支持此功能必须实现的函数。

可以有接口(UndeletableEntity)和annotation(@Undeletable)两种形式来定义无效列,annotation列形式还可以定义标识对象已删除的状态属性的名称,用接口则必须实现setStatus()接口,在里面操作实际的状态属性。

第四层就是把HibernateEntityDao和HibernateExtendDao以属性注入的方式注入到basedao,IBasedao就全局接口程序中使用的就是它,这个接口的实现全调用HibernateEntityDao和HibernateExtendDao的方法。方便以后的更改和替换,这样IBasedao接口不变就不要修改业务层的代码了。


代码如下(从下到上):

Page.java

package com.demonstration.hibernate.dao.support;

import java.io.Serializable;
import java.util.ArrayList;
/**
* 分页对象. 包含当前页数据及分页信息如总记录数.
*
* @author springside
*
*/
@SuppressWarnings("serial")
public class Page implements Serializable {

private static int DEFAULT_PAGE_SIZE = 20;

private int pageSize = DEFAULT_PAGE_SIZE; // 每页的记录数

private long start; // 当前页第一条数据在List中的位置,从0开始

private Object data; // 当前页中存放的记录,类型一般为List

private long totalCount; // 总记录数

/**
* 构造方法,只构造空页.
*/
@SuppressWarnings("unchecked")
public Page() {
this(0, 0, DEFAULT_PAGE_SIZE, new ArrayList());
}

/**
* 默认构造方法.
*
* @param start 本页数据在数据库中的起始位置
* @param totalSize 数据库中总记录条数
* @param pageSize 本页容量
* @param data 本页包含的数据
*/
public Page(long start, long totalSize, int pageSize, Object data) {
this.pageSize = pageSize;
this.start = start;
this.totalCount = totalSize;
this.data = data;
}

/**
* 取总记录数.
*/
public long getTotalCount() {
return this.totalCount;
}

/**
* 取总页数.
*/
public long getTotalPageCount() {
if (totalCount % pageSize == 0)
return totalCount / pageSize;
else
return totalCount / pageSize + 1;
}

/**
* 取每页数据容量.
*/
public int getPageSize() {
return pageSize;
}

/**
* 取当前页中的记录.
*/
public Object getResult() {
return data;
}

/**
* 取该页当前页码,页码从1开始.
*/
public long getCurrentPageNo() {
return start / pageSize + 1;
}

/**
* 该页是否有下一页.
*/
public boolean hasNextPage() {
return this.getCurrentPageNo() < this.getTotalPageCount() - 1;
}

/**
* 该页是否有上一页.
*/
public boolean hasPreviousPage() {
return this.getCurrentPageNo() > 1;
}

/**
* 获取任一页第一条数据在数据集的位置,每页条数使用默认值.
*
* @see #getStartOfPage(int,int)
*/
protected static int getStartOfPage(int pageNo) {
return getStartOfPage(pageNo, DEFAULT_PAGE_SIZE);
}

/**
* 获取任一页第一条数据在数据集的位置.
*
* @param pageNo 从1开始的页号
* @param pageSize 每页记录条数
* @return 该页第一条数据
*/
public static int getStartOfPage(int pageNo, int pageSize) {
return (pageNo - 1) * pageSize;
}
}
GenericsUtils.java

package com.demonstration.hibernate.dao.support;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
* Generics的util类.
*
* @author springside
*
*/
public class GenericsUtils {
private static final Log log = LogFactory.getLog(GenericsUtils.class);

private GenericsUtils() {
}

/**
* 通过反射,获得定义Class时声明的父类的范型参数的类型. 如public BookManager extends GenricManager<Book>
*
* @param clazz The class to introspect
* @return the first generic declaration, or <code>Object.class</code> if cannot be determined
*/
@SuppressWarnings("unchecked")
public static Class getSuperClassGenricType(Class clazz) {
return getSuperClassGenricType(clazz, 0);
}

/**
* 通过反射,获得定义Class时声明的父类的范型参数的类型. 如public BookManager extends GenricManager<Book>
*
* @param clazz clazz The class to introspect
* @param index the Index of the generic ddeclaration,start from 0.
* @return the index generic declaration, or <code>Object.class</code> if cannot be determined
*/
@SuppressWarnings("unchecked")
public static Class getSuperClassGenricType(Class clazz, int index) {

Type genType = clazz.getGenericSuperclass();

if (!(genType instanceof ParameterizedType)) {
log.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType");
return Object.class;
}

Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

if (index >= params.length || index < 0) {
log.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
+ params.length);
return Object.class;
}
if (!(params[index] instanceof Class)) {
log.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
return Object.class;
}
return (Class) params[index];
}
}


BeanUtils.java


package com.demonstration.hibernate.dao.support;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;

/**
* 扩展Apache Commons BeanUtils, 提供一些反射方面缺失功能的封装.
* @author springside
*
*/
public class BeanUtils extends org.apache.commons.beanutils.BeanUtils {

protected static final Log logger = LogFactory.getLog(BeanUtils.class);

private BeanUtils() {
}

/**
* 循环向上转型,获取对象的DeclaredField.
*
* @throws NoSuchFieldException 如果没有该Field时抛出.
*/
public static Field getDeclaredField(Object object, String propertyName) throws NoSuchFieldException {
Assert.notNull(object);
Assert.hasText(propertyName);
return getDeclaredField(object.getClass(), propertyName);
}

/**
* 循环向上转型,获取对象的DeclaredField.
*
* @throws NoSuchFieldException 如果没有该Field时抛出.
*/
@SuppressWarnings("unchecked")
public static Field getDeclaredField(Class clazz, String propertyName) throws NoSuchFieldException {
Assert.notNull(clazz);
Assert.hasText(propertyName);
for (Class superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) {
try {
return superClass.getDeclaredField(propertyName);
} catch (NoSuchFieldException e) {
// Field不在当前类定义,继续向上转型
}
}
throw new NoSuchFieldException("No such field: " + clazz.getName() + '.' + propertyName);
}

/**
* 暴力获取对象变量值,忽略private,protected修饰符的限制.
*
* @throws NoSuchFieldException 如果没有该Field时抛出.
*/
public static Object forceGetProperty(Object object, String propertyName) throws NoSuchFieldException {
Assert.notNull(object);
Assert.hasText(propertyName);

Field field = getDeclaredField(object, propertyName);

boolean accessible = field.isAccessible();
field.setAccessible(true);

Object result = null;
try {
result = field.get(object);
} catch (IllegalAccessException e) {
logger.info("error wont' happen");
}
field.setAccessible(accessible);
return result;
}

/**
* 暴力设置对象变量值,忽略private,protected修饰符的限制.
*
* @throws NoSuchFieldException 如果没有该Field时抛出.
*/
public static void forceSetProperty(Object object, String propertyName, Object newValue)
throws NoSuchFieldException {
Assert.notNull(object);
Assert.hasText(propertyName);

Field field = getDeclaredField(object, propertyName);
boolean accessible = field.isAccessible();
field.setAccessible(true);
try {
field.set(object, newValue);
} catch (IllegalAccessException e) {
logger.info("Error won't happen");
}
field.setAccessible(accessible);
}

/**
* 暴力调用对象函数,忽略private,protected修饰符的限制.
*
* @throws NoSuchMethodException 如果没有该Method时抛出.
*/
@SuppressWarnings("unchecked")
public static Object invokePrivateMethod(Object object, String methodName, Object... params)
throws NoSuchMethodException {
Assert.notNull(object);
Assert.hasText(methodName);
Class[] types = new Class[params.length];
for (int i = 0; i < params.length; i++) {
types[i] = params[i].getClass();
}

Class clazz = object.getClass();
Method method = null;
for (Class superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) {
try {
method = superClass.getDeclaredMethod(methodName, types);
break;
} catch (NoSuchMethodException e) {
// 方法不在当前类定义,继续向上转型
}
}

if (method == null)
throw new NoSuchMethodException("No Such Method:" + clazz.getSimpleName() + methodName);

boolean accessible = method.isAccessible();
method.setAccessible(true);
Object result = null;
try {
result = method.invoke(object, params);
} catch (Exception e) {
ReflectionUtils.handleReflectionException(e);
}
method.setAccessible(accessible);
return result;
}

/**
* 按Filed的类型取得Field列表.
*/
@SuppressWarnings("unchecked")
public static List<Field> getFieldsByType(Object object, Class type) {
List<Field> list = new ArrayList<Field>();
Field[] fields = object.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.getType().isAssignableFrom(type)) {
list.add(field);
}
}
return list;
}

/**
* 按FiledName获得Field的类型.
*/
@SuppressWarnings("unchecked")
public static Class getPropertyType(Class type, String name) throws NoSuchFieldException {
return getDeclaredField(type, name).getType();
}

/**
* 获得field的getter函数名称.
*/
@SuppressWarnings("unchecked")
public static String getGetterName(Class type, String fieldName) {
Assert.notNull(type, "Type required");
Assert.hasText(fieldName, "FieldName required");

if (type.getName().equals("boolean")) {
return "is" + StringUtils.capitalize(fieldName);
} else {
return "get" + StringUtils.capitalize(fieldName);
}
}

/**
* 获得field的getter函数,如果找不到该方法,返回null.
*/
@SuppressWarnings("unchecked")
public static Method getGetterMethod(Class type, String fieldName) {
try {
return type.getMethod(getGetterName(type, fieldName));
} catch (NoSuchMethodException e) {
logger.error(e.getMessage(), e);
}
return null;
}
}


IUndeleteableEntityOperation.java


package com.demonstration.hibernate.dao.extend;

import java.util.List;

import org.hibernate.criterion.Criterion;

/**
* 定义如果支持Entity不被直接删除必须支持的Operation.
*
* @author springside
*
*/
public interface IUndeleteableEntityOperation<T> {
/*
* Undelete Entity用到的几个常量,因为要同时兼顾Interface与Annotation,所以集中放此.
*/
String UNVALID_VALUE = "-1";

String NORMAL_VALUE = "0";

String STATUS = "status";

/**
* 取得所有状态为有效的对象.
*/
List<T> getAllValid();

/**
* 删除对象,但如果是Undeleteable的entity,设置对象的状态而不是直接删除.
*/
void remove(Object entity);

/**
* 获取过滤已删除对象的hql条件语句.
*/
String getUnDeletableHQL();
/**
* 获取过滤已删除对象的Criterion条件语句.
*/
Criterion getUnDeletableCriterion();
}


IUndeletableEntity.java

package com.demonstration.hibernate.dao.extend;

/**
* 标识商业对象不能被删除,只能被设为无效的接口.
*
* @author springside
*
*/
public interface IUndeletableEntity {
void setStatus(String status);
}


IUndeletable.java

package com.demonstration.hibernate.dao.extend;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* 标识商业对象不能被删除,只能被设为无效的Annoation.
* <p/>
* 相比inferface的标示方式,annotation 方式更少侵入性,可以定义任意属性代表status,而默认为status属性.
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface IUndeletable {
String status() default IUndeleteableEntityOperation.STATUS;
}


HibernateEntityExtendDao.java

package com.demonstration.hibernate.dao.extend;

import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.PropertyUtils;
import org.hibernate.Criteria;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;

import com.demonstration.hibernate.dao.HibernateEntityDao;


/**
* 加强版的entity dao.
* <p>自动处理Undeletable Entity.<br>
* Undeletable Entity 在删除时只把状态设为无效,不会真正执行删除.<br>
* Undeletable Entity 可以通过annotation或接口两种形式来声明.<br>
* 其中annotation模式不限制状态列的属性名必须为"status",可以用注释来确定任意属性为状态属性.<br>
* </p>
*
* @author springside
*
* @see HibernateEntityDao
* @see EntityInfo
* @see IUndeleteableEntityOperation
* @see IUndeletable
* @see IUndeletableEntity
*/
@SuppressWarnings("unchecked")
public class HibernateEntityExtendDao<T> extends HibernateEntityDao<T> implements IUndeleteableEntityOperation<T> {
/**
* 保存所管理的Entity的信息.
*/
protected EntityInfo entityInfo;

/**
* 构造函数,初始化entity信息.
*/
public HibernateEntityExtendDao() {
entityInfo = new EntityInfo(entityClass);
}

/**
* 取得所有状态为有效的对象.
*
* @see IUndeleteableEntityOperation#getAllValid()
*/
public List<T> getAllValid() {
Criteria criteria = createCriteria();
if (entityInfo.isUndeletable)
criteria.add(getUnDeletableCriterion());
return criteria.list();
}

/**
* 获取过滤已删除对象的hql条件语句.
*
* @see IUndeleteableEntityOperation#getUnDeletableHQL()
*/
public String getUnDeletableHQL() {
return entityInfo.statusProperty + "<>" + UNVALID_VALUE;
}

/**
* 获取过滤已删除对象的Criterion条件语句.
*
* @see UndeleteableEntityOperation#
*/
public Criterion getUnDeletableCriterion() {
return Restrictions.not(Restrictions.eq(entityInfo.statusProperty, UNVALID_VALUE));
}

/**
* 重载保存函数,在保存前先调用onValid(T),进行书名不重复等数据库相关的校验.
*
* @see #onValid(Object)
* @see HibernateEntityDao#save(Object)
*/
@Override
public void save(Object entity) {
Assert.isInstanceOf(getEntityClass(), entity);
onValid((T) entity);
super.save(entity);
}

/**
* 删除对象,如果是Undeleteable的entity,设置对象的状态而不是直接删除.
*
* @see HibernateEntityDao#remove(Object)
*/
@Override
public void remove(Object entity) {
if (entityInfo.isUndeletable) {
try {
PropertyUtils.setProperty(entity, entityInfo.statusProperty, UNVALID_VALUE);
save(entity);
} catch (Exception e) {
ReflectionUtils.handleReflectionException(e);
}
} else
super.remove(entity);
}

/**
* 与数据库相关的校验,比如判断名字在数据库里有没有重复, 在保存时被调用,在子类重载.
*
* @see #save(Object)
*/
public void onValid(T entity) {
}

/**
* 根据Map中的条件的Criteria查询.
*
* @param map Map中仅包含条件名与条件值,默认全部相同,可重载。
*/
public List<T> find(Map map) {
Criteria criteria = createCriteria();
return find(criteria, map);
}

/**
* 根据Map中的条件的Criteria查询.
*
* @param map Map中仅包含条件名与条件值,默认全部相同,可重载.
*/
public List<T> find(Criteria criteria, Map map) {
Assert.notNull(criteria);
criteria.add(Restrictions.allEq(map));
return criteria.list();
}
}


EntityInfo.java
package com.demonstration.hibernate.dao.extend;

/**
* 装载Entity信息的内部类.
*
* @author springside
*
*/
class EntityInfo {
boolean isUndeletable = false; // entity是否undeleteable的标志

String statusProperty; // 标识状态的属性名

@SuppressWarnings("unchecked")
public EntityInfo(Class entityClass) {
init(entityClass);
}

/**
* 初始函数,判断EntityClass是否UndeletableEntity.
*/
@SuppressWarnings("unchecked")
private void init(Class entityClass) {
// 通过EntityClass的interface判断entity是否undeletable
if (IUndeletableEntity.class.isAssignableFrom(entityClass)) {
isUndeletable = true;
statusProperty = IUndeleteableEntityOperation.STATUS;
}

// 通过EntityClass的annotation判断entity是否undeletable
if (entityClass.isAnnotationPresent(IUndeletable.class)) {
isUndeletable = true;
IUndeletable anno = (IUndeletable) entityClass.getAnnotation(IUndeletable.class);
statusProperty = anno.status();
}
}
}


IEntityDao.java
package com.demonstration.hibernate.dao;

import java.io.Serializable;
import java.util.List;

/**
* 针对单个Entity对象的操作定义.不依赖于具体ORM实现方案.
*
* @author springside
*
*/
public interface IEntityDao<T> {

T get(Serializable id);

List<T> getAll();

void save(Object o);

void remove(Object o);

void removeById(Serializable id);

/**
* 获取Entity对象的主键名.
*/
@SuppressWarnings("unchecked")
String getIdName(Class clazz);
}


HibernateGenericDao.java
package com.demonstration.hibernate.dao;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.beanutils.PropertyUtils;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projection;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.impl.CriteriaImpl;
import org.hibernate.metadata.ClassMetadata;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;

import com.demonstration.hibernate.dao.support.BeanUtils;
import com.demonstration.hibernate.dao.support.Page;


/**
* Hibernate Dao的泛型基类.
* <p/>
* 继承于Spring的<code>HibernateDaoSupport</code>,提供分页函数和若干便捷查询方法,并对返回值作了泛型类型转换.
*
* @author springside
*
* @see HibernateDaoSupport
* @see HibernateEntityDao
*/
@SuppressWarnings("unchecked")
public class HibernateGenericDao extends HibernateDaoSupport {
/**
* 根据ID获取对象. 实际调用Hibernate的session.load()方法返回实体或其proxy对象. 如果对象不存在,抛出异常.
*/
public <T> T get(Class<T> entityClass, Serializable id) {
return (T) getHibernateTemplate().load(entityClass, id);
}

/**
* 获取全部对象.
*/
public <T> List<T> getAll(Class<T> entityClass) {
return getHibernateTemplate().loadAll(entityClass);
}

/**
* 获取全部对象,带排序字段与升降序参数.
*/
public <T> List<T> getAll(Class<T> entityClass, String orderBy, boolean isAsc) {
Assert.hasText(orderBy);
if (isAsc)
return getHibernateTemplate().findByCriteria(
DetachedCriteria.forClass(entityClass).addOrder(Order.asc(orderBy)));
else
return getHibernateTemplate().findByCriteria(
DetachedCriteria.forClass(entityClass).addOrder(Order.desc(orderBy)));
}

/**
* 保存对象.
*/
public void save(Object o) {
getHibernateTemplate().saveOrUpdate(o);
}

/**
* 删除对象.
*/
public void remove(Object o) {
getHibernateTemplate().delete(o);
}

/**
* 根据ID删除对象.
*/
public <T> void removeById(Class<T> entityClass, Serializable id) {
remove(get(entityClass, id));
}

public void flush() {
getHibernateTemplate().flush();
}

public void clear() {
getHibernateTemplate().clear();
}

/**
* 创建Query对象. 对于需要first,max,fetchsize,cache,cacheRegion等诸多设置的函数,可以在返回Query后自行设置.
* 留意可以连续设置,如下:
* <pre>
* dao.getQuery(hql).setMaxResult(100).setCacheable(true).list();
* </pre>
* 调用方式如下:
* <pre>
* dao.createQuery(hql)
* dao.createQuery(hql,arg0);
* dao.createQuery(hql,arg0,arg1);
* dao.createQuery(hql,new Object[arg0,arg1,arg2])
* </pre>
*
* @param values 可变参数.
*/
public Query createQuery(String hql, Object... values) {
Assert.hasText(hql);
Query query = getSession().createQuery(hql);
for (int i = 0; i < values.length; i++) {
query.setParameter(i, values[i]);
}
return query;
}

/**
* 创建Criteria对象.
*
* @param criterions 可变的Restrictions条件列表,见{@link #createQuery(String,Object...)}
*/
public <T> Criteria createCriteria(Class<T> entityClass, Criterion... criterions) {
Criteria criteria = getSession().createCriteria(entityClass);
for (Criterion c : criterions) {
criteria.add(c);
}
return criteria;
}

/**
* 创建Criteria对象,带排序字段与升降序字段.
*
* @see #createCriteria(Class,Criterion[])
*/
public <T> Criteria createCriteria(Class<T> entityClass, String orderBy, boolean isAsc, Criterion... criterions) {
Assert.hasText(orderBy);

Criteria criteria = createCriteria(entityClass, criterions);

if (isAsc)
criteria.addOrder(Order.asc(orderBy));
else
criteria.addOrder(Order.desc(orderBy));

return criteria;
}

/**
* 根据hql查询,直接使用HibernateTemplate的find函数.
*
* @param values 可变参数,见{@link #createQuery(String,Object...)}
*/
public List find(String hql, Object... values) {
Assert.hasText(hql);
return getHibernateTemplate().find(hql, values);
}

/**
* 根据属性名和属性值查询对象.
*
* @return 符合条件的对象列表
*/
public <T> List<T> findBy(Class<T> entityClass, String propertyName, Object value) {
Assert.hasText(propertyName);
return createCriteria(entityClass, Restrictions.eq(propertyName, value)).list();
}

/**
* 根据属性名和属性值查询对象,带排序参数.
*/
public <T> List<T> findBy(Class<T> entityClass, String propertyName, Object value, String orderBy, boolean isAsc) {
Assert.hasText(propertyName);
Assert.hasText(orderBy);
return createCriteria(entityClass, orderBy, isAsc, Restrictions.eq(propertyName, value)).list();
}

/**
* 根据属性名和属性值查询唯一对象.
*
* @return 符合条件的唯一对象 or null if not found.
*/
public <T> T findUniqueBy(Class<T> entityClass, String propertyName, Object value) {
Assert.hasText(propertyName);
return (T) createCriteria(entityClass, Restrictions.eq(propertyName, value)).uniqueResult();
}

/**
* 分页查询函数,使用hql.
*
* @param pageNo 页号,从1开始.
*/
public Page pagedQuery(String hql, int pageNo, int pageSize, Object... values) {
Assert.hasText(hql);
Assert.isTrue(pageNo >= 1, "pageNo should start from 1");
// Count查询
String countQueryString = " select count (*) " + removeSelect(removeOrders(hql));
List countlist = getHibernateTemplate().find(countQueryString, values);
long totalCount = (Long) countlist.get(0);

if (totalCount < 1)
return new Page();
// 实际查询返回分页对象
int startIndex = Page.getStartOfPage(pageNo, pageSize);
Query query = createQuery(hql, values);
List list = query.setFirstResult(startIndex).setMaxResults(pageSize).list();

return new Page(startIndex, totalCount, pageSize, list);
}

/**
* @author Scott.wanglei
* @since 2008-7-21
* @param hql 查询sql
* @param start 分页从哪一条数据开始
* @param pageSize 每一个页面的大小
* @param values 查询条件
* @return page对象
*/
public Page dataQuery(String hql, int start, int pageSize, Object... values){
// Count查询
String countQueryString = " select count (*) " + removeSelect(removeOrders(hql));
List countlist = getHibernateTemplate().find(countQueryString, values);
long totalCount = (Long) countlist.get(0);

if (totalCount < 1)
return new Page();
// 实际查询返回分页对象
int startIndex = start;
Query query = createQuery(hql, values);
List list = query.setFirstResult(startIndex).setMaxResults(pageSize).list();

return new Page(startIndex, totalCount, pageSize, list);
}
/**
* 分页查询函数,使用已设好查询条件与排序的<code>Criteria</code>.
*
* @param pageNo 页号,从1开始.
* @return 含总记录数和当前页数据的Page对象.
*/
public Page pagedQuery(Criteria criteria, int pageNo, int pageSize) {
Assert.notNull(criteria);
Assert.isTrue(pageNo >= 1, "pageNo should start from 1");
CriteriaImpl impl = (CriteriaImpl) criteria;

// 先把Projection和OrderBy条件取出来,清空两者来执行Count操作
Projection projection = impl.getProjection();
List<CriteriaImpl.OrderEntry> orderEntries;
try {
orderEntries = (List) BeanUtils.forceGetProperty(impl, "orderEntries");
BeanUtils.forceSetProperty(impl, "orderEntries", new ArrayList());
} catch (Exception e) {
throw new InternalError(" Runtime Exception impossibility throw ");
}

// 执行查询
int totalCount = (Integer) criteria.setProjection(Projections.rowCount()).uniqueResult();

// 将之前的Projection和OrderBy条件重新设回去
criteria.setProjection(projection);
if (projection == null) {
criteria.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
}

try {
BeanUtils.forceSetProperty(impl, "orderEntries", orderEntries);
} catch (Exception e) {
throw new InternalError(" Runtime Exception impossibility throw ");
}

// 返回分页对象
if (totalCount < 1)
return new Page();

int startIndex = Page.getStartOfPage(pageNo, pageSize);;
List list = criteria.setFirstResult(startIndex).setMaxResults(pageSize).list();
return new Page(startIndex, totalCount, pageSize, list);
}

/**
* 分页查询函数,根据entityClass和查询条件参数创建默认的<code>Criteria</code>.
*
* @param pageNo 页号,从1开始.
* @return 含总记录数和当前页数据的Page对象.
*/
public Page pagedQuery(Class entityClass, int pageNo, int pageSize, Criterion... criterions) {
Criteria criteria = createCriteria(entityClass, criterions);
return pagedQuery(criteria, pageNo, pageSize);
}

/**
* 分页查询函数,根据entityClass和查询条件参数,排序参数创建默认的<code>Criteria</code>.
*
* @param pageNo 页号,从1开始.
* @return 含总记录数和当前页数据的Page对象.
*/
public Page pagedQuery(Class entityClass, int pageNo, int pageSize, String orderBy, boolean isAsc,
Criterion... criterions) {
Criteria criteria = createCriteria(entityClass, orderBy, isAsc, criterions);
return pagedQuery(criteria, pageNo, pageSize);
}

/**
* 判断对象某些属性的值在数据库中是否唯一.
*
* @param uniquePropertyNames 在POJO里不能重复的属性列表,以逗号分割 如"name,loginid,password"
*/
public <T> boolean isUnique(Class<T> entityClass, Object entity, String uniquePropertyNames) {
Assert.hasText(uniquePropertyNames);
Criteria criteria = createCriteria(entityClass).setProjection(Projections.rowCount());
String[] nameList = uniquePropertyNames.split(",");
try {
// 循环加入唯一列
for (String name : nameList) {
criteria.add(Restrictions.eq(name, PropertyUtils.getProperty(entity, name)));
}

// 以下代码为了如果是update的情况,排除entity自身.

String idName = getIdName(entityClass);

// 取得entity的主键值
Serializable id = getId(entityClass, entity);

// 如果id!=null,说明对象已存在,该操作为update,加入排除自身的判断
if (id != null)
criteria.add(Restrictions.not(Restrictions.eq(idName, id)));
} catch (Exception e) {
ReflectionUtils.handleReflectionException(e);
}
return (Integer) criteria.uniqueResult() == 0;
}

/**
* 取得对象的主键值,辅助函数.
*/
public Serializable getId(Class entityClass, Object entity) throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
Assert.notNull(entity);
Assert.notNull(entityClass);
return (Serializable) PropertyUtils.getProperty(entity, getIdName(entityClass));
}

/**
* 取得对象的主键名,辅助函数.
*/
public String getIdName(Class clazz) {
Assert.notNull(clazz);
ClassMetadata meta = getSessionFactory().getClassMetadata(clazz);
Assert.notNull(meta, "Class " + clazz + " not define in hibernate session factory.");
String idName = meta.getIdentifierPropertyName();
Assert.hasText(idName, clazz.getSimpleName() + " has no identifier property define.");
return idName;
}

/**
* 去除hql的select 子句,未考虑union的情况,用于pagedQuery.
*
* @see #pagedQuery(String,int,int,Object[])
*/
private static String removeSelect(String hql) {
Assert.hasText(hql);
int beginPos = hql.toLowerCase().indexOf("from");
Assert.isTrue(beginPos != -1, " hql : " + hql + " must has a keyword 'from'");
return hql.substring(beginPos);
}

/**
* 去除hql的orderby 子句,用于pagedQuery.
*
* @see #pagedQuery(String,int,int,Object[])
*/
private static String removeOrders(String hql) {
Assert.hasText(hql);
Pattern p = Pattern.compile("order//s*by[//w|//W|//s|//S]*", Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(hql);
StringBuffer sb = new StringBuffer();
while (m.find()) {
m.appendReplacement(sb, "");
}
m.appendTail(sb);
return sb.toString();
}

}
HibernateEntityDao.java
package com.demonstration.hibernate.dao;

import java.io.Serializable;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.criterion.Criterion;

import com.demonstration.hibernate.dao.support.GenericsUtils;

/**
* 负责为单个Entity对象提供CRUD操作的Hibernate DAO基类. <p/> 子类只要在类定义时指定所管理Entity的Class,
* 即拥有对单个Entity对象的CRUD操作.
*
* <pre>
* public class UserManager extends HibernateEntityDao<User> {
* }
* </pre>
*
* @author springside
*
* @see HibernateGenericDao
*/
@SuppressWarnings("unchecked")
public class HibernateEntityDao<T> extends HibernateGenericDao implements
IEntityDao<T> {

protected Class<T> entityClass;// DAO所管理的Entity类型.

/**
* 在构造函数中将泛型T.class赋给entityClass.
*/
public HibernateEntityDao() {
entityClass = GenericsUtils.getSuperClassGenricType(getClass());
}

/**
* 重载构造函数 让spring提供构造函数注入
*/
public HibernateEntityDao(Class<T> type) {
this.entityClass = type;
}

/**
* 取得entityClass.JDK1.4不支持泛型的子类可以抛开Class<T> entityClass,重载此函数达到相同效果。
*/
protected Class<T> getEntityClass() {
return entityClass;
}

public void setEntityClass(Class<T> type){
this.entityClass=type;
}

/**
* 根据ID获取对象.
*
* @see HibernateGenericDao#getId(Class,Object)
*/
public T get(Serializable id) {
return get(getEntityClass(), id);
}

/**
* 获取全部对象
*
* @see HibernateGenericDao#getAll(Class)
*/
public List<T> getAll() {
return getAll(getEntityClass());
}

/**
* 获取全部对象,带排序参数.
*
* @see HibernateGenericDao#getAll(Class,String,boolean)
*/
public List<T> getAll(String orderBy, boolean isAsc) {
return getAll(getEntityClass(), orderBy, isAsc);
}

/**
* 根据ID移除对象.
*
* @see HibernateGenericDao#removeById(Class,Serializable)
*/
public void removeById(Serializable id) {
removeById(getEntityClass(), id);
}

/**
* 取得Entity的Criteria.
*
* @see HibernateGenericDao#createCriteria(Class,Criterion[])
*/
public Criteria createCriteria(Criterion... criterions) {
return createCriteria(getEntityClass(), criterions);
}

/**
* 取得Entity的Criteria,带排序参数.
*
* @see HibernateGenericDao#createCriteria(Class,String,boolean,Criterion[])
*/
public Criteria createCriteria(String orderBy, boolean isAsc,
Criterion... criterions) {
return createCriteria(getEntityClass(), orderBy, isAsc, criterions);
}

/**
* 根据属性名和属性值查询对象.
*
* @return 符合条件的对象列表
* @see HibernateGenericDao#findBy(Class,String,Object)
*/
public List<T> findBy(String propertyName, Object value) {
return findBy(getEntityClass(), propertyName, value);
}

/**
* 根据属性名和属性值查询对象,带排序参数.
*
* @return 符合条件的对象列表
* @see HibernateGenericDao#findBy(Class,String,Object,String,boolean)
*/
public List<T> findBy(String propertyName, Object value, String orderBy,
boolean isAsc) {
return findBy(getEntityClass(), propertyName, value, orderBy, isAsc);
}

/**
* 根据属性名和属性值查询单个对象.
*
* @return 符合条件的唯一对象 or null
* @see HibernateGenericDao#findUniqueBy(Class,String,Object)
*/
public T findUniqueBy(String propertyName, Object value) {
return findUniqueBy(getEntityClass(), propertyName, value);
}

/**
* 判断对象某些属性的值在数据库中唯一.
*
* @param uniquePropertyNames
* 在POJO里不能重复的属性列表,以逗号分割 如"name,loginid,password"
* @see HibernateGenericDao#isUnique(Class,Object,String)
*/
public boolean isUnique(Object entity, String uniquePropertyNames) {
return isUnique(getEntityClass(), entity, uniquePropertyNames);
}

/**
* 消除与 Hibernate Session 的关联
*
* @param entity
*/
public void evit(Object entity) {
getHibernateTemplate().evict(entity);
}
}


IBaseDao.java
/**
*
*/
package com.demonstration.hibernate.basedao;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.criterion.Criterion;

import com.demonstration.hibernate.dao.HibernateEntityDao;
import com.demonstration.hibernate.dao.HibernateGenericDao;
import com.demonstration.hibernate.dao.extend.IUndeleteableEntityOperation;
import com.demonstration.hibernate.dao.support.Page;


/**
* @author
*
* 提供hibernate dao的所有操作,
* 实现类由spring注入HibernateEntityDao和HibernateEntityExtendDao来实现
* 最大限度的解耦hibernate持久层的操作
*/
public interface IBaseDao<T> {

/**
* 根据ID获取对象.
*
* @see HibernateGenericDao#getId(Class,Object)
*/
public T get(Serializable id);

/**
* 获取全部对象
*
* @see HibernateGenericDao#getAll(Class)
*/
public List<T> getAll();

/**
* 获取全部对象,带排序参数.
*
* @see HibernateGenericDao#getAll(Class,String,boolean)
*/
public List<T> getAll(String orderBy, boolean isAsc);

/**
* 根据ID移除对象.
*
* @see HibernateGenericDao#removeById(Class,Serializable)
*/
public void removeById(Serializable id);

/**
* 取得Entity的Criteria.
*
* @see HibernateGenericDao#createCriteria(Class,Criterion[])
*/
public Criteria createCriteria(Criterion... criterions);

/**
* 取得Entity的Criteria,带排序参数.
*
* @see HibernateGenericDao#createCriteria(Class,String,boolean,Criterion[])
*/
public Criteria createCriteria(String orderBy, boolean isAsc,
Criterion... criterions);

/**
* 根据属性名和属性值查询对象.
*
* @return 符合条件的对象列表
* @see HibernateGenericDao#findBy(Class,String,Object)
*/
public List<T> findBy(String propertyName, Object value);

/**
* 根据属性名和属性值查询对象,带排序参数.
*
* @return 符合条件的对象列表
* @see HibernateGenericDao#findBy(Class,String,Object,String,boolean)
*/
public List<T> findBy(String propertyName, Object value, String orderBy,
boolean isAsc);

/**
* 根据属性名和属性值查询单个对象.
*
* @return 符合条件的唯一对象 or null
* @see HibernateGenericDao#findUniqueBy(Class,String,Object)
*/
public T findUniqueBy(String propertyName, Object value);

/**
* 判断对象某些属性的值在数据库中唯一.
*
* @param uniquePropertyNames
* 在POJO里不能重复的属性列表,以逗号分割 如"name,loginid,password"
* @see HibernateGenericDao#isUnique(Class,Object,String)
*/
public boolean isUnique(Object entity, String uniquePropertyNames);

/**
* 消除与 Hibernate Session 的关联
*
* @param entity
*/
public void evit(Object entity);

/*******************************************************************************************/

/**
* 取得所有状态为有效的对象.
*
* @see IUndeleteableEntityOperation#getAllValid()
*/
public List<T> getAllValid();

/**
* 获取过滤已删除对象的hql条件语句.
*
* @see IUndeleteableEntityOperation#getUnDeletableHQL()
*/
public String getUnDeletableHQL();

/**
* 获取过滤已删除对象的Criterion条件语句.
*
* @see UndeleteableEntityOperation#
*/
public Criterion getUnDeletableCriterion();

/**
* 重载保存函数,在保存前先调用onValid(T),进行书名不重复等数据库相关的校验.
*
* @see #onValid(Object)
* @see HibernateEntityDao#save(Object)
*/
public void saveOnValid(Object entity);

/**
* 删除对象,如果是Undeleteable的entity,设置对象的状态而不是直接删除.
*
* @see HibernateEntityDao#remove(Object)
*/
public void removeUndeleteable(Object entity);

/**
* 与数据库相关的校验,比如判断名字在数据库里有没有重复, 在保存时被调用,在子类重载.
*
* @see #save(Object)
*/
public void onValid(T entity);

/**
* 根据Map中的条件的Criteria查询.
*
* @param map Map中仅包含条件名与条件值,默认全部相同,可重载。
*/
@SuppressWarnings("unchecked")
public List<T> find(Map map);

/**
* 根据Map中的条件的Criteria查询.
*
* @param map Map中仅包含条件名与条件值,默认全部相同,可重载.
*/
@SuppressWarnings("unchecked")
public List<T> find(Criteria criteria, Map map);

/*******************************************************************************************/

/**
* 根据ID获取对象. 实际调用Hibernate的session.load()方法返回实体或其proxy对象. 如果对象不存在,抛出异常.
*/
public T get(Class<T> entityClass, Serializable id);

/**
* 获取全部对象.
*/
public List<T> getAll(Class<T> entityClass);

/**
* 获取全部对象,带排序字段与升降序参数.
*/
public List<T> getAll(Class<T> entityClass, String orderBy, boolean isAsc);

/**
* 保存对象.
*/
public void save(Object o);

/**
* 删除对象.
*/
public void remove(Object o);

public void flush();

public void clear();

/**
* 创建Query对象. 对于需要first,max,fetchsize,cache,cacheRegion等诸多设置的函数,可以在返回Query后自行设置.
* 留意可以连续设置,如下:
* <pre>
* dao.getQuery(hql).setMaxResult(100).setCacheable(true).list();
* </pre>
* 调用方式如下:
* <pre>
* dao.createQuery(hql)
* dao.createQuery(hql,arg0);
* dao.createQuery(hql,arg0,arg1);
* dao.createQuery(hql,new Object[arg0,arg1,arg2])
* </pre>
*
* @param values 可变参数.
*/
public Query createQuery(String hql, Object... values);

/**
* 创建Criteria对象.
*
* @param criterions 可变的Restrictions条件列表,见{@link #createQuery(String,Object...)}
*/
public Criteria createCriteria(Class<T> entityClass, Criterion... criterions);

/**
* 创建Criteria对象,带排序字段与升降序字段.
*
* @see #createCriteria(Class,Criterion[])
*/
public Criteria createCriteria(Class<T> entityClass, String orderBy, boolean isAsc, Criterion... criterions);

/**
* 根据hql查询,直接使用HibernateTemplate的find函数.
*
* @param values 可变参数,见{@link #createQuery(String,Object...)}
*/
@SuppressWarnings("unchecked")
public List find(String hql, Object... values);

/**
* 根据属性名和属性值查询对象.
*
* @return 符合条件的对象列表
*/
public List<T> findBy(Class<T> entityClass, String propertyName, Object value);

/**
* 根据属性名和属性值查询对象,带排序参数.
*/
public List<T> findBy(Class<T> entityClass, String propertyName, Object value, String orderBy, boolean isAsc);

/**
* 根据属性名和属性值查询唯一对象.
*
* @return 符合条件的唯一对象 or null if not found.
*/
public T findUniqueBy(Class<T> entityClass, String propertyName, Object value);

/**
* 分页查询函数,使用hql.
*
* @param pageNo 页号,从1开始.
*/
public Page pagedQuery(String hql, int pageNo, int pageSize, Object... values);

/**
* @author Scott.wanglei
* @since 2008-7-21
* @param hql 查询sql
* @param start 分页从哪一条数据开始
* @param pageSize 每一个页面的大小
* @param values 查询条件
* @return page对象
*/
public Page dataQuery(String hql, int start, int pageSize, Object... values);

/**
* 分页查询函数,使用已设好查询条件与排序的<code>Criteria</code>.
*
* @param pageNo 页号,从1开始.
* @return 含总记录数和当前页数据的Page对象.
*/
public Page pagedQuery(Criteria criteria, int pageNo, int pageSize);

/**
* 分页查询函数,根据entityClass和查询条件参数创建默认的<code>Criteria</code>.
*
* @param pageNo 页号,从1开始.
* @return 含总记录数和当前页数据的Page对象.
*/
@SuppressWarnings("unchecked")
public Page pagedQuery(Class entityClass, int pageNo, int pageSize, Criterion... criterions);

/**
* 分页查询函数,根据entityClass和查询条件参数,排序参数创建默认的<code>Criteria</code>.
*
* @param pageNo 页号,从1开始.
* @return 含总记录数和当前页数据的Page对象.
*/
@SuppressWarnings("unchecked")
public Page pagedQuery(Class entityClass, int pageNo, int pageSize, String orderBy, boolean isAsc,
Criterion... criterions);

/**
* 判断对象某些属性的值在数据库中是否唯一.
*
* @param uniquePropertyNames 在POJO里不能重复的属性列表,以逗号分割 如"name,loginid,password"
*/
public boolean isUnique(Class<T> entityClass, Object entity, String uniquePropertyNames);

/**
* 取得对象的主键值,辅助函数.
*/
@SuppressWarnings("unchecked")
public Serializable getId(Class entityClass, Object entity) throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException ;

/**
* 取得对象的主键名,辅助函数.
*/
@SuppressWarnings("unchecked")
public String getIdName(Class clazz);
}


BaseDao.java
/**
*
*/
package com.demonstration.hibernate.basedao;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.criterion.Criterion;

import com.demonstration.hibernate.dao.HibernateEntityDao;
import com.demonstration.hibernate.dao.HibernateGenericDao;
import com.demonstration.hibernate.dao.extend.HibernateEntityExtendDao;
import com.demonstration.hibernate.dao.extend.IUndeleteableEntityOperation;
import com.demonstration.hibernate.dao.support.Page;

/**
* @author
*
* IBaseDao的实现类通过spring注入HibernateEntityDao和HibernateEntityExtendDao来实现
*/
public class BaseDao<T> implements IBaseDao<T> {

protected Class<T> entityClass;// DAO所管理的Entity类型.
private HibernateEntityDao<T> hedao;
private HibernateEntityExtendDao<T> hexdao;


public void setHedao(HibernateEntityDao<T> hedao) {
hedao.setEntityClass(entityClass);
this.hedao=hedao;
}

public void setHexdao(HibernateEntityExtendDao<T> hexdao) {
hexdao.setEntityClass(entityClass);
this.hexdao=hexdao;
}

/**
*让spring提供构造函数注入
*/
public BaseDao(Class<T> type) {
this.entityClass = type;
}

public BaseDao(){}
/**
* 根据ID获取对象.
*
* @see HibernateGenericDao#getId(Class,Object)
*/
public T get(Serializable id) {
return hedao.get(id);
}

/**
* 获取全部对象
*
* @see HibernateGenericDao#getAll(Class)
*/
public List<T> getAll() {
return hedao.getAll();
}


/**
* 获取全部对象,带排序参数.
*
* @see HibernateGenericDao#getAll(Class,String,boolean)
*/
public List<T> getAll(String orderBy, boolean isAsc) {
return hedao.getAll(orderBy, isAsc);
}

/**
* 根据ID移除对象.
*
* @see HibernateGenericDao#removeById(Class,Serializable)
*/
public void removeById(Serializable id) {
hedao.removeById(id);
}

/**
* 取得Entity的Criteria.
*
* @see HibernateGenericDao#createCriteria(Class,Criterion[])
*/
public Criteria createCriteria(Criterion... criterions) {
return hedao.createCriteria(criterions);
}

/**
* 取得Entity的Criteria,带排序参数.
*
* @see HibernateGenericDao#createCriteria(Class,String,boolean,Criterion[])
*/
public Criteria createCriteria(String orderBy, boolean isAsc,
Criterion... criterions) {
return hedao.createCriteria(orderBy, isAsc, criterions);
}

/**
* 根据属性名和属性值查询对象.
*
* @return 符合条件的对象列表
* @see HibernateGenericDao#findBy(Class,String,Object)
*/
public List<T> findBy(String propertyName, Object value) {
return hedao.findBy(propertyName, value);
}

/**
* 根据属性名和属性值查询对象,带排序参数.
*
* @return 符合条件的对象列表
* @see HibernateGenericDao#findBy(Class,String,Object,String,boolean)
*/
public List<T> findBy(String propertyName, Object value, String orderBy,
boolean isAsc) {
return hedao.findBy(propertyName, value, orderBy, isAsc);
}

/**
* 根据属性名和属性值查询单个对象.
*
* @return 符合条件的唯一对象 or null
* @see HibernateGenericDao#findUniqueBy(Class,String,Object)
*/
public T findUniqueBy(String propertyName, Object value) {
return hedao.findUniqueBy(propertyName, value);
}

/**
* 判断对象某些属性的值在数据库中唯一.
*
* @param uniquePropertyNames
* 在POJO里不能重复的属性列表,以逗号分割 如"name,loginid,password"
* @see HibernateGenericDao#isUnique(Class,Object,String)
*/
public boolean isUnique(Object entity, String uniquePropertyNames) {
return hedao.isUnique(entity, uniquePropertyNames);
}

/**
* 消除与 Hibernate Session 的关联
*
* @param entity
*/
public void evit(Object entity) {
hedao.evit(entity);
}

/**
* 取得所有状态为有效的对象.
*
* @see IUndeleteableEntityOperation#getAllValid()
*/
public List<T> getAllValid() {
return hexdao.getAllValid();
}

/**
* 获取过滤已删除对象的hql条件语句.
*
* @see IUndeleteableEntityOperation#getUnDeletableHQL()
*/
public String getUnDeletableHQL() {
return hexdao.getUnDeletableHQL();
}

/**
* 获取过滤已删除对象的Criterion条件语句.
*
* @see UndeleteableEntityOperation#
*/
public Criterion getUnDeletableCriterion() {
return hexdao.getUnDeletableCriterion();
}

/**
* 重载保存函数,在保存前先调用onValid(T),进行书名不重复等数据库相关的校验.
*
* @see #onValid(Object)
* @see HibernateEntityDao#save(Object)
*/
public void saveOnValid(Object entity) {
hexdao.save(entity);
}

/**
* 删除对象,如果是Undeleteable的entity,设置对象的状态而不是直接删除.
*
* @see HibernateEntityDao#remove(Object)
*/
public void removeUndeleteable(Object entity) {
hexdao.remove(entity);
}

/**
* 与数据库相关的校验,比如判断名字在数据库里有没有重复, 在保存时被调用,在此可重写.
*
* @see #save(Object)
*/
public void onValid(T entity) {

}

/**
* 根据Map中的条件的Criteria查询.
*
* @param map Map中仅包含条件名与条件值,默认全部相同,可重载。
*/
@SuppressWarnings("unchecked")
public List<T> find(Map map) {
return hexdao.find(map);
}

/**
* 根据Map中的条件的Criteria查询.
*
* @param map Map中仅包含条件名与条件值,默认全部相同,可重载.
*/
@SuppressWarnings("unchecked")
public List<T> find(Criteria criteria, Map map) {
return hexdao.find(criteria, map);
}

/**
* 根据ID获取对象. 实际调用Hibernate的session.load()方法返回实体或其proxy对象. 如果对象不存在,抛出异常.
*/
public T get(Class<T> entityClass, Serializable id) {
return hedao.get(entityClass, id);
}

/**
* 获取全部对象.
*/
public List<T> getAll(Class<T> entityClass) {
return hedao.getAll(entityClass);
}

/**
* 获取全部对象,带排序字段与升降序参数.
*/
public List<T> getAll(Class<T> entityClass, String orderBy, boolean isAsc) {
return hedao.getAll(entityClass, orderBy, isAsc);
}

/**
* 保存对象.
*/
public void save(Object o) {
hedao.save(o);
}

/**
* 删除对象.
*/
public void remove(Object o) {
hedao.remove(o);
}

public void flush(){
hedao.flush();
}

public void clear(){
hedao.clear();
}

/**
* 创建Query对象. 对于需要first,max,fetchsize,cache,cacheRegion等诸多设置的函数,可以在返回Query后自行设置.
* 留意可以连续设置,如下:
* <pre>
* dao.getQuery(hql).setMaxResult(100).setCacheable(true).list();
* </pre>
* 调用方式如下:
* <pre>
* dao.createQuery(hql)
* dao.createQuery(hql,arg0);
* dao.createQuery(hql,arg0,arg1);
* dao.createQuery(hql,new Object[arg0,arg1,arg2])
* </pre>
*
* @param values 可变参数.
*/
public Query createQuery(String hql, Object... values) {

return hedao.createQuery(hql, values);
}

/**
* 创建Criteria对象.
*
* @param criterions 可变的Restrictions条件列表,见{@link #createQuery(String,Object...)}
*/
public Criteria createCriteria(Class<T> entityClass,
Criterion... criterions) {

return hedao.createCriteria(entityClass, criterions);
}

/**
* 创建Criteria对象,带排序字段与升降序字段.
*
* @see #createCriteria(Class,Criterion[])
*/
public Criteria createCriteria(Class<T> entityClass, String orderBy,
boolean isAsc, Criterion... criterions) {
return hedao.createCriteria(entityClass, orderBy, isAsc, criterions);
}

/**
* 根据hql查询,直接使用HibernateTemplate的find函数.
*
* @param values 可变参数,见{@link #createQuery(String,Object...)}
*/
@SuppressWarnings("unchecked")
public List find(String hql, Object... values) {
return hedao.find(hql, values);
}

/**
* 根据属性名和属性值查询对象.
*
* @return 符合条件的对象列表
*/
public List<T> findBy(Class<T> entityClass, String propertyName,
Object value) {

return hedao.findBy(entityClass, propertyName, value);
}

/**
* 根据属性名和属性值查询对象,带排序参数.
*/
public List<T> findBy(Class<T> entityClass, String propertyName,
Object value, String orderBy, boolean isAsc) {
return hedao.findBy(entityClass, propertyName, value, orderBy, isAsc);
}

/**
* 根据属性名和属性值查询唯一对象.
*
* @return 符合条件的唯一对象 or null if not found.
*/
public T findUniqueBy(Class<T> entityClass, String propertyName,
Object value) {
return hedao.findUniqueBy(propertyName, value);
}

/**
* 分页查询函数,使用hql.
*
* @param pageNo 页号,从1开始.
*/
public Page pagedQuery(String hql, int pageNo, int pageSize,
Object... values) {
return hedao.pagedQuery(hql, pageNo, pageSize, values);
}

/**
* @author Scott.wanglei
* @since 2008-7-21
* @param hql 查询sql
* @param start 分页从哪一条数据开始
* @param pageSize 每一个页面的大小
* @param values 查询条件
* @return page对象
*/
public Page dataQuery(String hql, int start, int pageSize, Object... values) {
return hedao.dataQuery(hql, start, pageSize, values);
}

/**
* 分页查询函数,使用已设好查询条件与排序的<code>Criteria</code>.
*
* @param pageNo 页号,从1开始.
* @return 含总记录数和当前页数据的Page对象.
*/
public Page pagedQuery(Criteria criteria, int pageNo, int pageSize) {
return hedao.pagedQuery(criteria, pageNo, pageSize);
}

/**
* 分页查询函数,根据entityClass和查询条件参数创建默认的<code>Criteria</code>.
*
* @param pageNo 页号,从1开始.
* @return 含总记录数和当前页数据的Page对象.
*/
@SuppressWarnings("unchecked")
public Page pagedQuery(Class entityClass, int pageNo, int pageSize,
Criterion... criterions) {
return hedao.pagedQuery(entityClass, pageNo, pageSize, criterions);
}

@SuppressWarnings("unchecked")
public Page pagedQuery(Class entityClass, int pageNo, int pageSize,
String orderBy, boolean isAsc, Criterion... criterions) {
return hedao.pagedQuery(entityClass, pageNo, pageSize, orderBy, isAsc, criterions);
}

/**
* 判断对象某些属性的值在数据库中是否唯一.
*
* @param uniquePropertyNames 在POJO里不能重复的属性列表,以逗号分割 如"name,loginid,password"
*/
public boolean isUnique(Class<T> entityClass, Object entity,
String uniquePropertyNames) {
return hedao.isUnique(entity, uniquePropertyNames);
}

/**
* 取得对象的主键值,辅助函数.
*/
@SuppressWarnings("unchecked")
public Serializable getId(Class entityClass, Object entity)
throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
return hedao.getId(entityClass, entity);
}

/**
* 取得对象的主键名,辅助函数.
*/
@SuppressWarnings("unchecked")
public String getIdName(Class clazz) {
return hedao.getIdName(clazz);
}

}


使用时候的xml配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="hedao"
class="com.demonstration.hibernate.dao.HibernateEntityDao" scope="prototype">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>

<bean id="hexdao"
class="com.demonstration.hibernate.dao.extend.HibernateEntityExtendDao" scope="prototype">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>


<!--使用泛型DAO作为抽象基类-->
<bean id="baseDao" class="com.demonstration.hibernate.basedao.BaseDao"
abstract="true" depends-on="hedao,hexdao">
<property name="hedao">
<ref bean="hedao" />
</property>
<property name="hexdao">
<ref bean="hexdao" />
</property>
</bean>

<!--下面这个dao没有写任何java代码完全有spring搞定 -->
<!-- 配置实体类的DAO -->
<bean id="demoDao" parent="baseDao">
<constructor-arg>
<!--根据这个生成某一个实体的dao -->
<value>com.demonstration.entityclass.Demodata</value>
</constructor-arg>
</bean>

</beans>

以前从springside2.0上搞下来的很好用的,基本实现dao零编码只要配置xml文件就行了。

先看图:



一共4层,com.demonstration.hibernate.basedao是我加的用来进一步解耦hibernate和spring的耦合。
原来的官方解释如下:
SpringSide对Hibernate做了三层封装:

第一层:HibernateGenericDao,基于spring的HibernateDaoSupport,但加入了分页函数与各种Finder函数,并使用泛型避免了返回值强制类型转换。

第二层:HibernateEntityDao,基于HibernateGenericDao,用泛型声明Dao所管理的Entity类,默认拥有该entity的CRUD方法。

第三层:HibernateExtendDao,基于HibernateEntityDao,主要扩展各种选择性的功能。

关于三个类的详细注解请看JavaDoc,大致描述如下:

1 HibernateGenericDao
在Spring HibernateDaoSupport基础上封装的DAO,功能如下:

1.应用泛型:使得find(), get() 这些函数不再返回Object,而是返回T,不再需要强制类型转换。

2.提供各种finder的简便函数
应用了JDK5可变参数的hsql查询函数:List find(String hql, Object... values),支持find(hql),find(hql, param1); find(hql,param1,param2);find(hql,new Object[] {param1,param2}) 四种接口。

简单查询的简化函数:findBy(Class entityClass,String name,Object value) ,findUniqueBy(Class entityClass,String name, Object value),findByLike(Class entityClass,String name,Object value)

3.获得设置好的Query和Criteria:createQuery(String hql,Object... values) 和 createCriteria(Class<T> entityClass,Criterion... criterions)

Spring并没有很好的接口封装支持firstResult, maxResult, fetchsize,cache,cacheRegion 等多个查询参数,所以springside宁愿返回已设置好查询条件的Query和Criteria,让大家继续剩下的参数设置,最后再执行 list(),注意那几个参数可以连续设置的,如:

createQuery(hql,param1).setFirstResult(10).setMaxResult(20).list(); 4.分页函数:Page pagedQuery(Criteria criteria, int pageNo, int pageSize) 和Page pagedQuery(String hql, int pageNo, int pageSize, Object... args)

Page是SpringSide自行封装的一个典型Page类,pagedQuery与hibernate自身分页查询的差别是先运行一次count,获得符合条件的总记录数。

如果查询不需要总记录数,用普通的hibernate API,加上setFirstResult(),setMaxResult()就解决,不需要pagedQuery()。

5.判别对象属性在数据库中唯一的函数:isUnique(Class<T> entityClass,Object entity,String names)。

2. HibernateEntityDao
所有UserManager, ProductManager之类只管理一类对象的Manager类的基类,只需要在类定义处声明Entity类型即可

public class BookManager extends HibernateEntityDao<Book> {
} 通过<Book>的定义,避免了HibernateGenericDao类各方法中必有的Class entityClass参数。

如果需要操作其他的Entity,比如BookManager可能需要处理Category(图书目录),可以注入CategoryManager。无需担心事务的问题,JavaEE的默认事务模型已能很好处理。

如果没有对应的CategoryManager,或者各种原因不想注入的话,可以使用BookManager继承自 HibernateGenericDao的带entityClass参数的函数来操作Category的增删改,如Category category= this.get(Category.class, 1);

3. HibernateExtendDao
此类演示SpringSide 所作的一些扩展,大家可以按照自己的需要进行修改和扩展。

1. 支持对象不能被直接删除,只能设置状态列为无效。
接口UndeleteableEntityOperation,定义了要支持此功能必须实现的函数。

可以有接口(UndeletableEntity)和annotation(@Undeletable)两种形式来定义无效列,annotation列形式还可以定义标识对象已删除的状态属性的名称,用接口则必须实现setStatus()接口,在里面操作实际的状态属性。

第四层就是把HibernateEntityDao和HibernateExtendDao以属性注入的方式注入到basedao,IBasedao就全局接口程序中使用的就是它,这个接口的实现全调用HibernateEntityDao和HibernateExtendDao的方法。方便以后的更改和替换,这样IBasedao接口不变就不要修改业务层的代码了。


代码如下(从下到上):

Page.java

package com.demonstration.hibernate.dao.support;

import java.io.Serializable;
import java.util.ArrayList;
/**
* 分页对象. 包含当前页数据及分页信息如总记录数.
*
* @author springside
*
*/
@SuppressWarnings("serial")
public class Page implements Serializable {

private static int DEFAULT_PAGE_SIZE = 20;

private int pageSize = DEFAULT_PAGE_SIZE; // 每页的记录数

private long start; // 当前页第一条数据在List中的位置,从0开始

private Object data; // 当前页中存放的记录,类型一般为List

private long totalCount; // 总记录数

/**
* 构造方法,只构造空页.
*/
@SuppressWarnings("unchecked")
public Page() {
this(0, 0, DEFAULT_PAGE_SIZE, new ArrayList());
}

/**
* 默认构造方法.
*
* @param start 本页数据在数据库中的起始位置
* @param totalSize 数据库中总记录条数
* @param pageSize 本页容量
* @param data 本页包含的数据
*/
public Page(long start, long totalSize, int pageSize, Object data) {
this.pageSize = pageSize;
this.start = start;
this.totalCount = totalSize;
this.data = data;
}

/**
* 取总记录数.
*/
public long getTotalCount() {
return this.totalCount;
}

/**
* 取总页数.
*/
public long getTotalPageCount() {
if (totalCount % pageSize == 0)
return totalCount / pageSize;
else
return totalCount / pageSize + 1;
}

/**
* 取每页数据容量.
*/
public int getPageSize() {
return pageSize;
}

/**
* 取当前页中的记录.
*/
public Object getResult() {
return data;
}

/**
* 取该页当前页码,页码从1开始.
*/
public long getCurrentPageNo() {
return start / pageSize + 1;
}

/**
* 该页是否有下一页.
*/
public boolean hasNextPage() {
return this.getCurrentPageNo() < this.getTotalPageCount() - 1;
}

/**
* 该页是否有上一页.
*/
public boolean hasPreviousPage() {
return this.getCurrentPageNo() > 1;
}

/**
* 获取任一页第一条数据在数据集的位置,每页条数使用默认值.
*
* @see #getStartOfPage(int,int)
*/
protected static int getStartOfPage(int pageNo) {
return getStartOfPage(pageNo, DEFAULT_PAGE_SIZE);
}

/**
* 获取任一页第一条数据在数据集的位置.
*
* @param pageNo 从1开始的页号
* @param pageSize 每页记录条数
* @return 该页第一条数据
*/
public static int getStartOfPage(int pageNo, int pageSize) {
return (pageNo - 1) * pageSize;
}
}
GenericsUtils.java

package com.demonstration.hibernate.dao.support;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
* Generics的util类.
*
* @author springside
*
*/
public class GenericsUtils {
private static final Log log = LogFactory.getLog(GenericsUtils.class);

private GenericsUtils() {
}

/**
* 通过反射,获得定义Class时声明的父类的范型参数的类型. 如public BookManager extends GenricManager<Book>
*
* @param clazz The class to introspect
* @return the first generic declaration, or <code>Object.class</code> if cannot be determined
*/
@SuppressWarnings("unchecked")
public static Class getSuperClassGenricType(Class clazz) {
return getSuperClassGenricType(clazz, 0);
}

/**
* 通过反射,获得定义Class时声明的父类的范型参数的类型. 如public BookManager extends GenricManager<Book>
*
* @param clazz clazz The class to introspect
* @param index the Index of the generic ddeclaration,start from 0.
* @return the index generic declaration, or <code>Object.class</code> if cannot be determined
*/
@SuppressWarnings("unchecked")
public static Class getSuperClassGenricType(Class clazz, int index) {

Type genType = clazz.getGenericSuperclass();

if (!(genType instanceof ParameterizedType)) {
log.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType");
return Object.class;
}

Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

if (index >= params.length || index < 0) {
log.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
+ params.length);
return Object.class;
}
if (!(params[index] instanceof Class)) {
log.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
return Object.class;
}
return (Class) params[index];
}
}


BeanUtils.java


package com.demonstration.hibernate.dao.support;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;

/**
* 扩展Apache Commons BeanUtils, 提供一些反射方面缺失功能的封装.
* @author springside
*
*/
public class BeanUtils extends org.apache.commons.beanutils.BeanUtils {

protected static final Log logger = LogFactory.getLog(BeanUtils.class);

private BeanUtils() {
}

/**
* 循环向上转型,获取对象的DeclaredField.
*
* @throws NoSuchFieldException 如果没有该Field时抛出.
*/
public static Field getDeclaredField(Object object, String propertyName) throws NoSuchFieldException {
Assert.notNull(object);
Assert.hasText(propertyName);
return getDeclaredField(object.getClass(), propertyName);
}

/**
* 循环向上转型,获取对象的DeclaredField.
*
* @throws NoSuchFieldException 如果没有该Field时抛出.
*/
@SuppressWarnings("unchecked")
public static Field getDeclaredField(Class clazz, String propertyName) throws NoSuchFieldException {
Assert.notNull(clazz);
Assert.hasText(propertyName);
for (Class superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) {
try {
return superClass.getDeclaredField(propertyName);
} catch (NoSuchFieldException e) {
// Field不在当前类定义,继续向上转型
}
}
throw new NoSuchFieldException("No such field: " + clazz.getName() + '.' + propertyName);
}

/**
* 暴力获取对象变量值,忽略private,protected修饰符的限制.
*
* @throws NoSuchFieldException 如果没有该Field时抛出.
*/
public static Object forceGetProperty(Object object, String propertyName) throws NoSuchFieldException {
Assert.notNull(object);
Assert.hasText(propertyName);

Field field = getDeclaredField(object, propertyName);

boolean accessible = field.isAccessible();
field.setAccessible(true);

Object result = null;
try {
result = field.get(object);
} catch (IllegalAccessException e) {
logger.info("error wont' happen");
}
field.setAccessible(accessible);
return result;
}

/**
* 暴力设置对象变量值,忽略private,protected修饰符的限制.
*
* @throws NoSuchFieldException 如果没有该Field时抛出.
*/
public static void forceSetProperty(Object object, String propertyName, Object newValue)
throws NoSuchFieldException {
Assert.notNull(object);
Assert.hasText(propertyName);

Field field = getDeclaredField(object, propertyName);
boolean accessible = field.isAccessible();
field.setAccessible(true);
try {
field.set(object, newValue);
} catch (IllegalAccessException e) {
logger.info("Error won't happen");
}
field.setAccessible(accessible);
}

/**
* 暴力调用对象函数,忽略private,protected修饰符的限制.
*
* @throws NoSuchMethodException 如果没有该Method时抛出.
*/
@SuppressWarnings("unchecked")
public static Object invokePrivateMethod(Object object, String methodName, Object... params)
throws NoSuchMethodException {
Assert.notNull(object);
Assert.hasText(methodName);
Class[] types = new Class[params.length];
for (int i = 0; i < params.length; i++) {
types[i] = params[i].getClass();
}

Class clazz = object.getClass();
Method method = null;
for (Class superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) {
try {
method = superClass.getDeclaredMethod(methodName, types);
break;
} catch (NoSuchMethodException e) {
// 方法不在当前类定义,继续向上转型
}
}

if (method == null)
throw new NoSuchMethodException("No Such Method:" + clazz.getSimpleName() + methodName);

boolean accessible = method.isAccessible();
method.setAccessible(true);
Object result = null;
try {
result = method.invoke(object, params);
} catch (Exception e) {
ReflectionUtils.handleReflectionException(e);
}
method.setAccessible(accessible);
return result;
}

/**
* 按Filed的类型取得Field列表.
*/
@SuppressWarnings("unchecked")
public static List<Field> getFieldsByType(Object object, Class type) {
List<Field> list = new ArrayList<Field>();
Field[] fields = object.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.getType().isAssignableFrom(type)) {
list.add(field);
}
}
return list;
}

/**
* 按FiledName获得Field的类型.
*/
@SuppressWarnings("unchecked")
public static Class getPropertyType(Class type, String name) throws NoSuchFieldException {
return getDeclaredField(type, name).getType();
}

/**
* 获得field的getter函数名称.
*/
@SuppressWarnings("unchecked")
public static String getGetterName(Class type, String fieldName) {
Assert.notNull(type, "Type required");
Assert.hasText(fieldName, "FieldName required");

if (type.getName().equals("boolean")) {
return "is" + StringUtils.capitalize(fieldName);
} else {
return "get" + StringUtils.capitalize(fieldName);
}
}

/**
* 获得field的getter函数,如果找不到该方法,返回null.
*/
@SuppressWarnings("unchecked")
public static Method getGetterMethod(Class type, String fieldName) {
try {
return type.getMethod(getGetterName(type, fieldName));
} catch (NoSuchMethodException e) {
logger.error(e.getMessage(), e);
}
return null;
}
}


IUndeleteableEntityOperation.java


package com.demonstration.hibernate.dao.extend;

import java.util.List;

import org.hibernate.criterion.Criterion;

/**
* 定义如果支持Entity不被直接删除必须支持的Operation.
*
* @author springside
*
*/
public interface IUndeleteableEntityOperation<T> {
/*
* Undelete Entity用到的几个常量,因为要同时兼顾Interface与Annotation,所以集中放此.
*/
String UNVALID_VALUE = "-1";

String NORMAL_VALUE = "0";

String STATUS = "status";

/**
* 取得所有状态为有效的对象.
*/
List<T> getAllValid();

/**
* 删除对象,但如果是Undeleteable的entity,设置对象的状态而不是直接删除.
*/
void remove(Object entity);

/**
* 获取过滤已删除对象的hql条件语句.
*/
String getUnDeletableHQL();
/**
* 获取过滤已删除对象的Criterion条件语句.
*/
Criterion getUnDeletableCriterion();
}


IUndeletableEntity.java

package com.demonstration.hibernate.dao.extend;

/**
* 标识商业对象不能被删除,只能被设为无效的接口.
*
* @author springside
*
*/
public interface IUndeletableEntity {
void setStatus(String status);
}


IUndeletable.java

package com.demonstration.hibernate.dao.extend;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* 标识商业对象不能被删除,只能被设为无效的Annoation.
* <p/>
* 相比inferface的标示方式,annotation 方式更少侵入性,可以定义任意属性代表status,而默认为status属性.
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface IUndeletable {
String status() default IUndeleteableEntityOperation.STATUS;
}


HibernateEntityExtendDao.java

package com.demonstration.hibernate.dao.extend;

import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.PropertyUtils;
import org.hibernate.Criteria;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;

import com.demonstration.hibernate.dao.HibernateEntityDao;


/**
* 加强版的entity dao.
* <p>自动处理Undeletable Entity.<br>
* Undeletable Entity 在删除时只把状态设为无效,不会真正执行删除.<br>
* Undeletable Entity 可以通过annotation或接口两种形式来声明.<br>
* 其中annotation模式不限制状态列的属性名必须为"status",可以用注释来确定任意属性为状态属性.<br>
* </p>
*
* @author springside
*
* @see HibernateEntityDao
* @see EntityInfo
* @see IUndeleteableEntityOperation
* @see IUndeletable
* @see IUndeletableEntity
*/
@SuppressWarnings("unchecked")
public class HibernateEntityExtendDao<T> extends HibernateEntityDao<T> implements IUndeleteableEntityOperation<T> {
/**
* 保存所管理的Entity的信息.
*/
protected EntityInfo entityInfo;

/**
* 构造函数,初始化entity信息.
*/
public HibernateEntityExtendDao() {
entityInfo = new EntityInfo(entityClass);
}

/**
* 取得所有状态为有效的对象.
*
* @see IUndeleteableEntityOperation#getAllValid()
*/
public List<T> getAllValid() {
Criteria criteria = createCriteria();
if (entityInfo.isUndeletable)
criteria.add(getUnDeletableCriterion());
return criteria.list();
}

/**
* 获取过滤已删除对象的hql条件语句.
*
* @see IUndeleteableEntityOperation#getUnDeletableHQL()
*/
public String getUnDeletableHQL() {
return entityInfo.statusProperty + "<>" + UNVALID_VALUE;
}

/**
* 获取过滤已删除对象的Criterion条件语句.
*
* @see UndeleteableEntityOperation#
*/
public Criterion getUnDeletableCriterion() {
return Restrictions.not(Restrictions.eq(entityInfo.statusProperty, UNVALID_VALUE));
}

/**
* 重载保存函数,在保存前先调用onValid(T),进行书名不重复等数据库相关的校验.
*
* @see #onValid(Object)
* @see HibernateEntityDao#save(Object)
*/
@Override
public void save(Object entity) {
Assert.isInstanceOf(getEntityClass(), entity);
onValid((T) entity);
super.save(entity);
}

/**
* 删除对象,如果是Undeleteable的entity,设置对象的状态而不是直接删除.
*
* @see HibernateEntityDao#remove(Object)
*/
@Override
public void remove(Object entity) {
if (entityInfo.isUndeletable) {
try {
PropertyUtils.setProperty(entity, entityInfo.statusProperty, UNVALID_VALUE);
save(entity);
} catch (Exception e) {
ReflectionUtils.handleReflectionException(e);
}
} else
super.remove(entity);
}

/**
* 与数据库相关的校验,比如判断名字在数据库里有没有重复, 在保存时被调用,在子类重载.
*
* @see #save(Object)
*/
public void onValid(T entity) {
}

/**
* 根据Map中的条件的Criteria查询.
*
* @param map Map中仅包含条件名与条件值,默认全部相同,可重载。
*/
public List<T> find(Map map) {
Criteria criteria = createCriteria();
return find(criteria, map);
}

/**
* 根据Map中的条件的Criteria查询.
*
* @param map Map中仅包含条件名与条件值,默认全部相同,可重载.
*/
public List<T> find(Criteria criteria, Map map) {
Assert.notNull(criteria);
criteria.add(Restrictions.allEq(map));
return criteria.list();
}
}


EntityInfo.java
package com.demonstration.hibernate.dao.extend;

/**
* 装载Entity信息的内部类.
*
* @author springside
*
*/
class EntityInfo {
boolean isUndeletable = false; // entity是否undeleteable的标志

String statusProperty; // 标识状态的属性名

@SuppressWarnings("unchecked")
public EntityInfo(Class entityClass) {
init(entityClass);
}

/**
* 初始函数,判断EntityClass是否UndeletableEntity.
*/
@SuppressWarnings("unchecked")
private void init(Class entityClass) {
// 通过EntityClass的interface判断entity是否undeletable
if (IUndeletableEntity.class.isAssignableFrom(entityClass)) {
isUndeletable = true;
statusProperty = IUndeleteableEntityOperation.STATUS;
}

// 通过EntityClass的annotation判断entity是否undeletable
if (entityClass.isAnnotationPresent(IUndeletable.class)) {
isUndeletable = true;
IUndeletable anno = (IUndeletable) entityClass.getAnnotation(IUndeletable.class);
statusProperty = anno.status();
}
}
}


IEntityDao.java
package com.demonstration.hibernate.dao;

import java.io.Serializable;
import java.util.List;

/**
* 针对单个Entity对象的操作定义.不依赖于具体ORM实现方案.
*
* @author springside
*
*/
public interface IEntityDao<T> {

T get(Serializable id);

List<T> getAll();

void save(Object o);

void remove(Object o);

void removeById(Serializable id);

/**
* 获取Entity对象的主键名.
*/
@SuppressWarnings("unchecked")
String getIdName(Class clazz);
}


HibernateGenericDao.java
package com.demonstration.hibernate.dao;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.beanutils.PropertyUtils;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projection;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.impl.CriteriaImpl;
import org.hibernate.metadata.ClassMetadata;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;

import com.demonstration.hibernate.dao.support.BeanUtils;
import com.demonstration.hibernate.dao.support.Page;


/**
* Hibernate Dao的泛型基类.
* <p/>
* 继承于Spring的<code>HibernateDaoSupport</code>,提供分页函数和若干便捷查询方法,并对返回值作了泛型类型转换.
*
* @author springside
*
* @see HibernateDaoSupport
* @see HibernateEntityDao
*/
@SuppressWarnings("unchecked")
public class HibernateGenericDao extends HibernateDaoSupport {
/**
* 根据ID获取对象. 实际调用Hibernate的session.load()方法返回实体或其proxy对象. 如果对象不存在,抛出异常.
*/
public <T> T get(Class<T> entityClass, Serializable id) {
return (T) getHibernateTemplate().load(entityClass, id);
}

/**
* 获取全部对象.
*/
public <T> List<T> getAll(Class<T> entityClass) {
return getHibernateTemplate().loadAll(entityClass);
}

/**
* 获取全部对象,带排序字段与升降序参数.
*/
public <T> List<T> getAll(Class<T> entityClass, String orderBy, boolean isAsc) {
Assert.hasText(orderBy);
if (isAsc)
return getHibernateTemplate().findByCriteria(
DetachedCriteria.forClass(entityClass).addOrder(Order.asc(orderBy)));
else
return getHibernateTemplate().findByCriteria(
DetachedCriteria.forClass(entityClass).addOrder(Order.desc(orderBy)));
}

/**
* 保存对象.
*/
public void save(Object o) {
getHibernateTemplate().saveOrUpdate(o);
}

/**
* 删除对象.
*/
public void remove(Object o) {
getHibernateTemplate().delete(o);
}

/**
* 根据ID删除对象.
*/
public <T> void removeById(Class<T> entityClass, Serializable id) {
remove(get(entityClass, id));
}

public void flush() {
getHibernateTemplate().flush();
}

public void clear() {
getHibernateTemplate().clear();
}

/**
* 创建Query对象. 对于需要first,max,fetchsize,cache,cacheRegion等诸多设置的函数,可以在返回Query后自行设置.
* 留意可以连续设置,如下:
* <pre>
* dao.getQuery(hql).setMaxResult(100).setCacheable(true).list();
* </pre>
* 调用方式如下:
* <pre>
* dao.createQuery(hql)
* dao.createQuery(hql,arg0);
* dao.createQuery(hql,arg0,arg1);
* dao.createQuery(hql,new Object[arg0,arg1,arg2])
* </pre>
*
* @param values 可变参数.
*/
public Query createQuery(String hql, Object... values) {
Assert.hasText(hql);
Query query = getSession().createQuery(hql);
for (int i = 0; i < values.length; i++) {
query.setParameter(i, values[i]);
}
return query;
}

/**
* 创建Criteria对象.
*
* @param criterions 可变的Restrictions条件列表,见{@link #createQuery(String,Object...)}
*/
public <T> Criteria createCriteria(Class<T> entityClass, Criterion... criterions) {
Criteria criteria = getSession().createCriteria(entityClass);
for (Criterion c : criterions) {
criteria.add(c);
}
return criteria;
}

/**
* 创建Criteria对象,带排序字段与升降序字段.
*
* @see #createCriteria(Class,Criterion[])
*/
public <T> Criteria createCriteria(Class<T> entityClass, String orderBy, boolean isAsc, Criterion... criterions) {
Assert.hasText(orderBy);

Criteria criteria = createCriteria(entityClass, criterions);

if (isAsc)
criteria.addOrder(Order.asc(orderBy));
else
criteria.addOrder(Order.desc(orderBy));

return criteria;
}

/**
* 根据hql查询,直接使用HibernateTemplate的find函数.
*
* @param values 可变参数,见{@link #createQuery(String,Object...)}
*/
public List find(String hql, Object... values) {
Assert.hasText(hql);
return getHibernateTemplate().find(hql, values);
}

/**
* 根据属性名和属性值查询对象.
*
* @return 符合条件的对象列表
*/
public <T> List<T> findBy(Class<T> entityClass, String propertyName, Object value) {
Assert.hasText(propertyName);
return createCriteria(entityClass, Restrictions.eq(propertyName, value)).list();
}

/**
* 根据属性名和属性值查询对象,带排序参数.
*/
public <T> List<T> findBy(Class<T> entityClass, String propertyName, Object value, String orderBy, boolean isAsc) {
Assert.hasText(propertyName);
Assert.hasText(orderBy);
return createCriteria(entityClass, orderBy, isAsc, Restrictions.eq(propertyName, value)).list();
}

/**
* 根据属性名和属性值查询唯一对象.
*
* @return 符合条件的唯一对象 or null if not found.
*/
public <T> T findUniqueBy(Class<T> entityClass, String propertyName, Object value) {
Assert.hasText(propertyName);
return (T) createCriteria(entityClass, Restrictions.eq(propertyName, value)).uniqueResult();
}

/**
* 分页查询函数,使用hql.
*
* @param pageNo 页号,从1开始.
*/
public Page pagedQuery(String hql, int pageNo, int pageSize, Object... values) {
Assert.hasText(hql);
Assert.isTrue(pageNo >= 1, "pageNo should start from 1");
// Count查询
String countQueryString = " select count (*) " + removeSelect(removeOrders(hql));
List countlist = getHibernateTemplate().find(countQueryString, values);
long totalCount = (Long) countlist.get(0);

if (totalCount < 1)
return new Page();
// 实际查询返回分页对象
int startIndex = Page.getStartOfPage(pageNo, pageSize);
Query query = createQuery(hql, values);
List list = query.setFirstResult(startIndex).setMaxResults(pageSize).list();

return new Page(startIndex, totalCount, pageSize, list);
}

/**
* @author Scott.wanglei
* @since 2008-7-21
* @param hql 查询sql
* @param start 分页从哪一条数据开始
* @param pageSize 每一个页面的大小
* @param values 查询条件
* @return page对象
*/
public Page dataQuery(String hql, int start, int pageSize, Object... values){
// Count查询
String countQueryString = " select count (*) " + removeSelect(removeOrders(hql));
List countlist = getHibernateTemplate().find(countQueryString, values);
long totalCount = (Long) countlist.get(0);

if (totalCount < 1)
return new Page();
// 实际查询返回分页对象
int startIndex = start;
Query query = createQuery(hql, values);
List list = query.setFirstResult(startIndex).setMaxResults(pageSize).list();

return new Page(startIndex, totalCount, pageSize, list);
}
/**
* 分页查询函数,使用已设好查询条件与排序的<code>Criteria</code>.
*
* @param pageNo 页号,从1开始.
* @return 含总记录数和当前页数据的Page对象.
*/
public Page pagedQuery(Criteria criteria, int pageNo, int pageSize) {
Assert.notNull(criteria);
Assert.isTrue(pageNo >= 1, "pageNo should start from 1");
CriteriaImpl impl = (CriteriaImpl) criteria;

// 先把Projection和OrderBy条件取出来,清空两者来执行Count操作
Projection projection = impl.getProjection();
List<CriteriaImpl.OrderEntry> orderEntries;
try {
orderEntries = (List) BeanUtils.forceGetProperty(impl, "orderEntries");
BeanUtils.forceSetProperty(impl, "orderEntries", new ArrayList());
} catch (Exception e) {
throw new InternalError(" Runtime Exception impossibility throw ");
}

// 执行查询
int totalCount = (Integer) criteria.setProjection(Projections.rowCount()).uniqueResult();

// 将之前的Projection和OrderBy条件重新设回去
criteria.setProjection(projection);
if (projection == null) {
criteria.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
}

try {
BeanUtils.forceSetProperty(impl, "orderEntries", orderEntries);
} catch (Exception e) {
throw new InternalError(" Runtime Exception impossibility throw ");
}

// 返回分页对象
if (totalCount < 1)
return new Page();

int startIndex = Page.getStartOfPage(pageNo, pageSize);;
List list = criteria.setFirstResult(startIndex).setMaxResults(pageSize).list();
return new Page(startIndex, totalCount, pageSize, list);
}

/**
* 分页查询函数,根据entityClass和查询条件参数创建默认的<code>Criteria</code>.
*
* @param pageNo 页号,从1开始.
* @return 含总记录数和当前页数据的Page对象.
*/
public Page pagedQuery(Class entityClass, int pageNo, int pageSize, Criterion... criterions) {
Criteria criteria = createCriteria(entityClass, criterions);
return pagedQuery(criteria, pageNo, pageSize);
}

/**
* 分页查询函数,根据entityClass和查询条件参数,排序参数创建默认的<code>Criteria</code>.
*
* @param pageNo 页号,从1开始.
* @return 含总记录数和当前页数据的Page对象.
*/
public Page pagedQuery(Class entityClass, int pageNo, int pageSize, String orderBy, boolean isAsc,
Criterion... criterions) {
Criteria criteria = createCriteria(entityClass, orderBy, isAsc, criterions);
return pagedQuery(criteria, pageNo, pageSize);
}

/**
* 判断对象某些属性的值在数据库中是否唯一.
*
* @param uniquePropertyNames 在POJO里不能重复的属性列表,以逗号分割 如"name,loginid,password"
*/
public <T> boolean isUnique(Class<T> entityClass, Object entity, String uniquePropertyNames) {
Assert.hasText(uniquePropertyNames);
Criteria criteria = createCriteria(entityClass).setProjection(Projections.rowCount());
String[] nameList = uniquePropertyNames.split(",");
try {
// 循环加入唯一列
for (String name : nameList) {
criteria.add(Restrictions.eq(name, PropertyUtils.getProperty(entity, name)));
}

// 以下代码为了如果是update的情况,排除entity自身.

String idName = getIdName(entityClass);

// 取得entity的主键值
Serializable id = getId(entityClass, entity);

// 如果id!=null,说明对象已存在,该操作为update,加入排除自身的判断
if (id != null)
criteria.add(Restrictions.not(Restrictions.eq(idName, id)));
} catch (Exception e) {
ReflectionUtils.handleReflectionException(e);
}
return (Integer) criteria.uniqueResult() == 0;
}

/**
* 取得对象的主键值,辅助函数.
*/
public Serializable getId(Class entityClass, Object entity) throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
Assert.notNull(entity);
Assert.notNull(entityClass);
return (Serializable) PropertyUtils.getProperty(entity, getIdName(entityClass));
}

/**
* 取得对象的主键名,辅助函数.
*/
public String getIdName(Class clazz) {
Assert.notNull(clazz);
ClassMetadata meta = getSessionFactory().getClassMetadata(clazz);
Assert.notNull(meta, "Class " + clazz + " not define in hibernate session factory.");
String idName = meta.getIdentifierPropertyName();
Assert.hasText(idName, clazz.getSimpleName() + " has no identifier property define.");
return idName;
}

/**
* 去除hql的select 子句,未考虑union的情况,用于pagedQuery.
*
* @see #pagedQuery(String,int,int,Object[])
*/
private static String removeSelect(String hql) {
Assert.hasText(hql);
int beginPos = hql.toLowerCase().indexOf("from");
Assert.isTrue(beginPos != -1, " hql : " + hql + " must has a keyword 'from'");
return hql.substring(beginPos);
}

/**
* 去除hql的orderby 子句,用于pagedQuery.
*
* @see #pagedQuery(String,int,int,Object[])
*/
private static String removeOrders(String hql) {
Assert.hasText(hql);
Pattern p = Pattern.compile("order//s*by[//w|//W|//s|//S]*", Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(hql);
StringBuffer sb = new StringBuffer();
while (m.find()) {
m.appendReplacement(sb, "");
}
m.appendTail(sb);
return sb.toString();
}

}
HibernateEntityDao.java
package com.demonstration.hibernate.dao;

import java.io.Serializable;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.criterion.Criterion;

import com.demonstration.hibernate.dao.support.GenericsUtils;

/**
* 负责为单个Entity对象提供CRUD操作的Hibernate DAO基类. <p/> 子类只要在类定义时指定所管理Entity的Class,
* 即拥有对单个Entity对象的CRUD操作.
*
* <pre>
* public class UserManager extends HibernateEntityDao<User> {
* }
* </pre>
*
* @author springside
*
* @see HibernateGenericDao
*/
@SuppressWarnings("unchecked")
public class HibernateEntityDao<T> extends HibernateGenericDao implements
IEntityDao<T> {

protected Class<T> entityClass;// DAO所管理的Entity类型.

/**
* 在构造函数中将泛型T.class赋给entityClass.
*/
public HibernateEntityDao() {
entityClass = GenericsUtils.getSuperClassGenricType(getClass());
}

/**
* 重载构造函数 让spring提供构造函数注入
*/
public HibernateEntityDao(Class<T> type) {
this.entityClass = type;
}

/**
* 取得entityClass.JDK1.4不支持泛型的子类可以抛开Class<T> entityClass,重载此函数达到相同效果。
*/
protected Class<T> getEntityClass() {
return entityClass;
}

public void setEntityClass(Class<T> type){
this.entityClass=type;
}

/**
* 根据ID获取对象.
*
* @see HibernateGenericDao#getId(Class,Object)
*/
public T get(Serializable id) {
return get(getEntityClass(), id);
}

/**
* 获取全部对象
*
* @see HibernateGenericDao#getAll(Class)
*/
public List<T> getAll() {
return getAll(getEntityClass());
}

/**
* 获取全部对象,带排序参数.
*
* @see HibernateGenericDao#getAll(Class,String,boolean)
*/
public List<T> getAll(String orderBy, boolean isAsc) {
return getAll(getEntityClass(), orderBy, isAsc);
}

/**
* 根据ID移除对象.
*
* @see HibernateGenericDao#removeById(Class,Serializable)
*/
public void removeById(Serializable id) {
removeById(getEntityClass(), id);
}

/**
* 取得Entity的Criteria.
*
* @see HibernateGenericDao#createCriteria(Class,Criterion[])
*/
public Criteria createCriteria(Criterion... criterions) {
return createCriteria(getEntityClass(), criterions);
}

/**
* 取得Entity的Criteria,带排序参数.
*
* @see HibernateGenericDao#createCriteria(Class,String,boolean,Criterion[])
*/
public Criteria createCriteria(String orderBy, boolean isAsc,
Criterion... criterions) {
return createCriteria(getEntityClass(), orderBy, isAsc, criterions);
}

/**
* 根据属性名和属性值查询对象.
*
* @return 符合条件的对象列表
* @see HibernateGenericDao#findBy(Class,String,Object)
*/
public List<T> findBy(String propertyName, Object value) {
return findBy(getEntityClass(), propertyName, value);
}

/**
* 根据属性名和属性值查询对象,带排序参数.
*
* @return 符合条件的对象列表
* @see HibernateGenericDao#findBy(Class,String,Object,String,boolean)
*/
public List<T> findBy(String propertyName, Object value, String orderBy,
boolean isAsc) {
return findBy(getEntityClass(), propertyName, value, orderBy, isAsc);
}

/**
* 根据属性名和属性值查询单个对象.
*
* @return 符合条件的唯一对象 or null
* @see HibernateGenericDao#findUniqueBy(Class,String,Object)
*/
public T findUniqueBy(String propertyName, Object value) {
return findUniqueBy(getEntityClass(), propertyName, value);
}

/**
* 判断对象某些属性的值在数据库中唯一.
*
* @param uniquePropertyNames
* 在POJO里不能重复的属性列表,以逗号分割 如"name,loginid,password"
* @see HibernateGenericDao#isUnique(Class,Object,String)
*/
public boolean isUnique(Object entity, String uniquePropertyNames) {
return isUnique(getEntityClass(), entity, uniquePropertyNames);
}

/**
* 消除与 Hibernate Session 的关联
*
* @param entity
*/
public void evit(Object entity) {
getHibernateTemplate().evict(entity);
}
}


IBaseDao.java
/**
*
*/
package com.demonstration.hibernate.basedao;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.criterion.Criterion;

import com.demonstration.hibernate.dao.HibernateEntityDao;
import com.demonstration.hibernate.dao.HibernateGenericDao;
import com.demonstration.hibernate.dao.extend.IUndeleteableEntityOperation;
import com.demonstration.hibernate.dao.support.Page;


/**
* @author
*
* 提供hibernate dao的所有操作,
* 实现类由spring注入HibernateEntityDao和HibernateEntityExtendDao来实现
* 最大限度的解耦hibernate持久层的操作
*/
public interface IBaseDao<T> {

/**
* 根据ID获取对象.
*
* @see HibernateGenericDao#getId(Class,Object)
*/
public T get(Serializable id);

/**
* 获取全部对象
*
* @see HibernateGenericDao#getAll(Class)
*/
public List<T> getAll();

/**
* 获取全部对象,带排序参数.
*
* @see HibernateGenericDao#getAll(Class,String,boolean)
*/
public List<T> getAll(String orderBy, boolean isAsc);

/**
* 根据ID移除对象.
*
* @see HibernateGenericDao#removeById(Class,Serializable)
*/
public void removeById(Serializable id);

/**
* 取得Entity的Criteria.
*
* @see HibernateGenericDao#createCriteria(Class,Criterion[])
*/
public Criteria createCriteria(Criterion... criterions);

/**
* 取得Entity的Criteria,带排序参数.
*
* @see HibernateGenericDao#createCriteria(Class,String,boolean,Criterion[])
*/
public Criteria createCriteria(String orderBy, boolean isAsc,
Criterion... criterions);

/**
* 根据属性名和属性值查询对象.
*
* @return 符合条件的对象列表
* @see HibernateGenericDao#findBy(Class,String,Object)
*/
public List<T> findBy(String propertyName, Object value);

/**
* 根据属性名和属性值查询对象,带排序参数.
*
* @return 符合条件的对象列表
* @see HibernateGenericDao#findBy(Class,String,Object,String,boolean)
*/
public List<T> findBy(String propertyName, Object value, String orderBy,
boolean isAsc);

/**
* 根据属性名和属性值查询单个对象.
*
* @return 符合条件的唯一对象 or null
* @see HibernateGenericDao#findUniqueBy(Class,String,Object)
*/
public T findUniqueBy(String propertyName, Object value);

/**
* 判断对象某些属性的值在数据库中唯一.
*
* @param uniquePropertyNames
* 在POJO里不能重复的属性列表,以逗号分割 如"name,loginid,password"
* @see HibernateGenericDao#isUnique(Class,Object,String)
*/
public boolean isUnique(Object entity, String uniquePropertyNames);

/**
* 消除与 Hibernate Session 的关联
*
* @param entity
*/
public void evit(Object entity);

/*******************************************************************************************/

/**
* 取得所有状态为有效的对象.
*
* @see IUndeleteableEntityOperation#getAllValid()
*/
public List<T> getAllValid();

/**
* 获取过滤已删除对象的hql条件语句.
*
* @see IUndeleteableEntityOperation#getUnDeletableHQL()
*/
public String getUnDeletableHQL();

/**
* 获取过滤已删除对象的Criterion条件语句.
*
* @see UndeleteableEntityOperation#
*/
public Criterion getUnDeletableCriterion();

/**
* 重载保存函数,在保存前先调用onValid(T),进行书名不重复等数据库相关的校验.
*
* @see #onValid(Object)
* @see HibernateEntityDao#save(Object)
*/
public void saveOnValid(Object entity);

/**
* 删除对象,如果是Undeleteable的entity,设置对象的状态而不是直接删除.
*
* @see HibernateEntityDao#remove(Object)
*/
public void removeUndeleteable(Object entity);

/**
* 与数据库相关的校验,比如判断名字在数据库里有没有重复, 在保存时被调用,在子类重载.
*
* @see #save(Object)
*/
public void onValid(T entity);

/**
* 根据Map中的条件的Criteria查询.
*
* @param map Map中仅包含条件名与条件值,默认全部相同,可重载。
*/
@SuppressWarnings("unchecked")
public List<T> find(Map map);

/**
* 根据Map中的条件的Criteria查询.
*
* @param map Map中仅包含条件名与条件值,默认全部相同,可重载.
*/
@SuppressWarnings("unchecked")
public List<T> find(Criteria criteria, Map map);

/*******************************************************************************************/

/**
* 根据ID获取对象. 实际调用Hibernate的session.load()方法返回实体或其proxy对象. 如果对象不存在,抛出异常.
*/
public T get(Class<T> entityClass, Serializable id);

/**
* 获取全部对象.
*/
public List<T> getAll(Class<T> entityClass);

/**
* 获取全部对象,带排序字段与升降序参数.
*/
public List<T> getAll(Class<T> entityClass, String orderBy, boolean isAsc);

/**
* 保存对象.
*/
public void save(Object o);

/**
* 删除对象.
*/
public void remove(Object o);

public void flush();

public void clear();

/**
* 创建Query对象. 对于需要first,max,fetchsize,cache,cacheRegion等诸多设置的函数,可以在返回Query后自行设置.
* 留意可以连续设置,如下:
* <pre>
* dao.getQuery(hql).setMaxResult(100).setCacheable(true).list();
* </pre>
* 调用方式如下:
* <pre>
* dao.createQuery(hql)
* dao.createQuery(hql,arg0);
* dao.createQuery(hql,arg0,arg1);
* dao.createQuery(hql,new Object[arg0,arg1,arg2])
* </pre>
*
* @param values 可变参数.
*/
public Query createQuery(String hql, Object... values);

/**
* 创建Criteria对象.
*
* @param criterions 可变的Restrictions条件列表,见{@link #createQuery(String,Object...)}
*/
public Criteria createCriteria(Class<T> entityClass, Criterion... criterions);

/**
* 创建Criteria对象,带排序字段与升降序字段.
*
* @see #createCriteria(Class,Criterion[])
*/
public Criteria createCriteria(Class<T> entityClass, String orderBy, boolean isAsc, Criterion... criterions);

/**
* 根据hql查询,直接使用HibernateTemplate的find函数.
*
* @param values 可变参数,见{@link #createQuery(String,Object...)}
*/
@SuppressWarnings("unchecked")
public List find(String hql, Object... values);

/**
* 根据属性名和属性值查询对象.
*
* @return 符合条件的对象列表
*/
public List<T> findBy(Class<T> entityClass, String propertyName, Object value);

/**
* 根据属性名和属性值查询对象,带排序参数.
*/
public List<T> findBy(Class<T> entityClass, String propertyName, Object value, String orderBy, boolean isAsc);

/**
* 根据属性名和属性值查询唯一对象.
*
* @return 符合条件的唯一对象 or null if not found.
*/
public T findUniqueBy(Class<T> entityClass, String propertyName, Object value);

/**
* 分页查询函数,使用hql.
*
* @param pageNo 页号,从1开始.
*/
public Page pagedQuery(String hql, int pageNo, int pageSize, Object... values);

/**
* @author Scott.wanglei
* @since 2008-7-21
* @param hql 查询sql
* @param start 分页从哪一条数据开始
* @param pageSize 每一个页面的大小
* @param values 查询条件
* @return page对象
*/
public Page dataQuery(String hql, int start, int pageSize, Object... values);

/**
* 分页查询函数,使用已设好查询条件与排序的<code>Criteria</code>.
*
* @param pageNo 页号,从1开始.
* @return 含总记录数和当前页数据的Page对象.
*/
public Page pagedQuery(Criteria criteria, int pageNo, int pageSize);

/**
* 分页查询函数,根据entityClass和查询条件参数创建默认的<code>Criteria</code>.
*
* @param pageNo 页号,从1开始.
* @return 含总记录数和当前页数据的Page对象.
*/
@SuppressWarnings("unchecked")
public Page pagedQuery(Class entityClass, int pageNo, int pageSize, Criterion... criterions);

/**
* 分页查询函数,根据entityClass和查询条件参数,排序参数创建默认的<code>Criteria</code>.
*
* @param pageNo 页号,从1开始.
* @return 含总记录数和当前页数据的Page对象.
*/
@SuppressWarnings("unchecked")
public Page pagedQuery(Class entityClass, int pageNo, int pageSize, String orderBy, boolean isAsc,
Criterion... criterions);

/**
* 判断对象某些属性的值在数据库中是否唯一.
*
* @param uniquePropertyNames 在POJO里不能重复的属性列表,以逗号分割 如"name,loginid,password"
*/
public boolean isUnique(Class<T> entityClass, Object entity, String uniquePropertyNames);

/**
* 取得对象的主键值,辅助函数.
*/
@SuppressWarnings("unchecked")
public Serializable getId(Class entityClass, Object entity) throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException ;

/**
* 取得对象的主键名,辅助函数.
*/
@SuppressWarnings("unchecked")
public String getIdName(Class clazz);
}


BaseDao.java
/**
*
*/
package com.demonstration.hibernate.basedao;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.criterion.Criterion;

import com.demonstration.hibernate.dao.HibernateEntityDao;
import com.demonstration.hibernate.dao.HibernateGenericDao;
import com.demonstration.hibernate.dao.extend.HibernateEntityExtendDao;
import com.demonstration.hibernate.dao.extend.IUndeleteableEntityOperation;
import com.demonstration.hibernate.dao.support.Page;

/**
* @author
*
* IBaseDao的实现类通过spring注入HibernateEntityDao和HibernateEntityExtendDao来实现
*/
public class BaseDao<T> implements IBaseDao<T> {

protected Class<T> entityClass;// DAO所管理的Entity类型.
private HibernateEntityDao<T> hedao;
private HibernateEntityExtendDao<T> hexdao;


public void setHedao(HibernateEntityDao<T> hedao) {
hedao.setEntityClass(entityClass);
this.hedao=hedao;
}

public void setHexdao(HibernateEntityExtendDao<T> hexdao) {
hexdao.setEntityClass(entityClass);
this.hexdao=hexdao;
}

/**
*让spring提供构造函数注入
*/
public BaseDao(Class<T> type) {
this.entityClass = type;
}

public BaseDao(){}
/**
* 根据ID获取对象.
*
* @see HibernateGenericDao#getId(Class,Object)
*/
public T get(Serializable id) {
return hedao.get(id);
}

/**
* 获取全部对象
*
* @see HibernateGenericDao#getAll(Class)
*/
public List<T> getAll() {
return hedao.getAll();
}


/**
* 获取全部对象,带排序参数.
*
* @see HibernateGenericDao#getAll(Class,String,boolean)
*/
public List<T> getAll(String orderBy, boolean isAsc) {
return hedao.getAll(orderBy, isAsc);
}

/**
* 根据ID移除对象.
*
* @see HibernateGenericDao#removeById(Class,Serializable)
*/
public void removeById(Serializable id) {
hedao.removeById(id);
}

/**
* 取得Entity的Criteria.
*
* @see HibernateGenericDao#createCriteria(Class,Criterion[])
*/
public Criteria createCriteria(Criterion... criterions) {
return hedao.createCriteria(criterions);
}

/**
* 取得Entity的Criteria,带排序参数.
*
* @see HibernateGenericDao#createCriteria(Class,String,boolean,Criterion[])
*/
public Criteria createCriteria(String orderBy, boolean isAsc,
Criterion... criterions) {
return hedao.createCriteria(orderBy, isAsc, criterions);
}

/**
* 根据属性名和属性值查询对象.
*
* @return 符合条件的对象列表
* @see HibernateGenericDao#findBy(Class,String,Object)
*/
public List<T> findBy(String propertyName, Object value) {
return hedao.findBy(propertyName, value);
}

/**
* 根据属性名和属性值查询对象,带排序参数.
*
* @return 符合条件的对象列表
* @see HibernateGenericDao#findBy(Class,String,Object,String,boolean)
*/
public List<T> findBy(String propertyName, Object value, String orderBy,
boolean isAsc) {
return hedao.findBy(propertyName, value, orderBy, isAsc);
}

/**
* 根据属性名和属性值查询单个对象.
*
* @return 符合条件的唯一对象 or null
* @see HibernateGenericDao#findUniqueBy(Class,String,Object)
*/
public T findUniqueBy(String propertyName, Object value) {
return hedao.findUniqueBy(propertyName, value);
}

/**
* 判断对象某些属性的值在数据库中唯一.
*
* @param uniquePropertyNames
* 在POJO里不能重复的属性列表,以逗号分割 如"name,loginid,password"
* @see HibernateGenericDao#isUnique(Class,Object,String)
*/
public boolean isUnique(Object entity, String uniquePropertyNames) {
return hedao.isUnique(entity, uniquePropertyNames);
}

/**
* 消除与 Hibernate Session 的关联
*
* @param entity
*/
public void evit(Object entity) {
hedao.evit(entity);
}

/**
* 取得所有状态为有效的对象.
*
* @see IUndeleteableEntityOperation#getAllValid()
*/
public List<T> getAllValid() {
return hexdao.getAllValid();
}

/**
* 获取过滤已删除对象的hql条件语句.
*
* @see IUndeleteableEntityOperation#getUnDeletableHQL()
*/
public String getUnDeletableHQL() {
return hexdao.getUnDeletableHQL();
}

/**
* 获取过滤已删除对象的Criterion条件语句.
*
* @see UndeleteableEntityOperation#
*/
public Criterion getUnDeletableCriterion() {
return hexdao.getUnDeletableCriterion();
}

/**
* 重载保存函数,在保存前先调用onValid(T),进行书名不重复等数据库相关的校验.
*
* @see #onValid(Object)
* @see HibernateEntityDao#save(Object)
*/
public void saveOnValid(Object entity) {
hexdao.save(entity);
}

/**
* 删除对象,如果是Undeleteable的entity,设置对象的状态而不是直接删除.
*
* @see HibernateEntityDao#remove(Object)
*/
public void removeUndeleteable(Object entity) {
hexdao.remove(entity);
}

/**
* 与数据库相关的校验,比如判断名字在数据库里有没有重复, 在保存时被调用,在此可重写.
*
* @see #save(Object)
*/
public void onValid(T entity) {

}

/**
* 根据Map中的条件的Criteria查询.
*
* @param map Map中仅包含条件名与条件值,默认全部相同,可重载。
*/
@SuppressWarnings("unchecked")
public List<T> find(Map map) {
return hexdao.find(map);
}

/**
* 根据Map中的条件的Criteria查询.
*
* @param map Map中仅包含条件名与条件值,默认全部相同,可重载.
*/
@SuppressWarnings("unchecked")
public List<T> find(Criteria criteria, Map map) {
return hexdao.find(criteria, map);
}

/**
* 根据ID获取对象. 实际调用Hibernate的session.load()方法返回实体或其proxy对象. 如果对象不存在,抛出异常.
*/
public T get(Class<T> entityClass, Serializable id) {
return hedao.get(entityClass, id);
}

/**
* 获取全部对象.
*/
public List<T> getAll(Class<T> entityClass) {
return hedao.getAll(entityClass);
}

/**
* 获取全部对象,带排序字段与升降序参数.
*/
public List<T> getAll(Class<T> entityClass, String orderBy, boolean isAsc) {
return hedao.getAll(entityClass, orderBy, isAsc);
}

/**
* 保存对象.
*/
public void save(Object o) {
hedao.save(o);
}

/**
* 删除对象.
*/
public void remove(Object o) {
hedao.remove(o);
}

public void flush(){
hedao.flush();
}

public void clear(){
hedao.clear();
}

/**
* 创建Query对象. 对于需要first,max,fetchsize,cache,cacheRegion等诸多设置的函数,可以在返回Query后自行设置.
* 留意可以连续设置,如下:
* <pre>
* dao.getQuery(hql).setMaxResult(100).setCacheable(true).list();
* </pre>
* 调用方式如下:
* <pre>
* dao.createQuery(hql)
* dao.createQuery(hql,arg0);
* dao.createQuery(hql,arg0,arg1);
* dao.createQuery(hql,new Object[arg0,arg1,arg2])
* </pre>
*
* @param values 可变参数.
*/
public Query createQuery(String hql, Object... values) {

return hedao.createQuery(hql, values);
}

/**
* 创建Criteria对象.
*
* @param criterions 可变的Restrictions条件列表,见{@link #createQuery(String,Object...)}
*/
public Criteria createCriteria(Class<T> entityClass,
Criterion... criterions) {

return hedao.createCriteria(entityClass, criterions);
}

/**
* 创建Criteria对象,带排序字段与升降序字段.
*
* @see #createCriteria(Class,Criterion[])
*/
public Criteria createCriteria(Class<T> entityClass, String orderBy,
boolean isAsc, Criterion... criterions) {
return hedao.createCriteria(entityClass, orderBy, isAsc, criterions);
}

/**
* 根据hql查询,直接使用HibernateTemplate的find函数.
*
* @param values 可变参数,见{@link #createQuery(String,Object...)}
*/
@SuppressWarnings("unchecked")
public List find(String hql, Object... values) {
return hedao.find(hql, values);
}

/**
* 根据属性名和属性值查询对象.
*
* @return 符合条件的对象列表
*/
public List<T> findBy(Class<T> entityClass, String propertyName,
Object value) {

return hedao.findBy(entityClass, propertyName, value);
}

/**
* 根据属性名和属性值查询对象,带排序参数.
*/
public List<T> findBy(Class<T> entityClass, String propertyName,
Object value, String orderBy, boolean isAsc) {
return hedao.findBy(entityClass, propertyName, value, orderBy, isAsc);
}

/**
* 根据属性名和属性值查询唯一对象.
*
* @return 符合条件的唯一对象 or null if not found.
*/
public T findUniqueBy(Class<T> entityClass, String propertyName,
Object value) {
return hedao.findUniqueBy(propertyName, value);
}

/**
* 分页查询函数,使用hql.
*
* @param pageNo 页号,从1开始.
*/
public Page pagedQuery(String hql, int pageNo, int pageSize,
Object... values) {
return hedao.pagedQuery(hql, pageNo, pageSize, values);
}

/**
* @author Scott.wanglei
* @since 2008-7-21
* @param hql 查询sql
* @param start 分页从哪一条数据开始
* @param pageSize 每一个页面的大小
* @param values 查询条件
* @return page对象
*/
public Page dataQuery(String hql, int start, int pageSize, Object... values) {
return hedao.dataQuery(hql, start, pageSize, values);
}

/**
* 分页查询函数,使用已设好查询条件与排序的<code>Criteria</code>.
*
* @param pageNo 页号,从1开始.
* @return 含总记录数和当前页数据的Page对象.
*/
public Page pagedQuery(Criteria criteria, int pageNo, int pageSize) {
return hedao.pagedQuery(criteria, pageNo, pageSize);
}

/**
* 分页查询函数,根据entityClass和查询条件参数创建默认的<code>Criteria</code>.
*
* @param pageNo 页号,从1开始.
* @return 含总记录数和当前页数据的Page对象.
*/
@SuppressWarnings("unchecked")
public Page pagedQuery(Class entityClass, int pageNo, int pageSize,
Criterion... criterions) {
return hedao.pagedQuery(entityClass, pageNo, pageSize, criterions);
}

@SuppressWarnings("unchecked")
public Page pagedQuery(Class entityClass, int pageNo, int pageSize,
String orderBy, boolean isAsc, Criterion... criterions) {
return hedao.pagedQuery(entityClass, pageNo, pageSize, orderBy, isAsc, criterions);
}

/**
* 判断对象某些属性的值在数据库中是否唯一.
*
* @param uniquePropertyNames 在POJO里不能重复的属性列表,以逗号分割 如"name,loginid,password"
*/
public boolean isUnique(Class<T> entityClass, Object entity,
String uniquePropertyNames) {
return hedao.isUnique(entity, uniquePropertyNames);
}

/**
* 取得对象的主键值,辅助函数.
*/
@SuppressWarnings("unchecked")
public Serializable getId(Class entityClass, Object entity)
throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
return hedao.getId(entityClass, entity);
}

/**
* 取得对象的主键名,辅助函数.
*/
@SuppressWarnings("unchecked")
public String getIdName(Class clazz) {
return hedao.getIdName(clazz);
}

}


使用时候的xml配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="hedao"
class="com.demonstration.hibernate.dao.HibernateEntityDao" scope="prototype">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>

<bean id="hexdao"
class="com.demonstration.hibernate.dao.extend.HibernateEntityExtendDao" scope="prototype">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>


<!--使用泛型DAO作为抽象基类-->
<bean id="baseDao" class="com.demonstration.hibernate.basedao.BaseDao"
abstract="true" depends-on="hedao,hexdao">
<property name="hedao">
<ref bean="hedao" />
</property>
<property name="hexdao">
<ref bean="hexdao" />
</property>
</bean>

<!--下面这个dao没有写任何java代码完全有spring搞定 -->
<!-- 配置实体类的DAO -->
<bean id="demoDao" parent="baseDao">
<constructor-arg>
<!--根据这个生成某一个实体的dao -->
<value>com.demonstration.entityclass.Demodata</value>
</constructor-arg>
</bean>

</beans>

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics