import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.math.BigInteger;
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.framework.commons.pagination.Page;
import com.framework.commons.utils.BeanUtils;
/**
* Hibernate Dao的泛型基 <p/> 繼承於Spring<code>HibernateDaoSupport</code>,提供分頁函數和若干便捷查詢方法,並對返回值作了泛型類型轉
*
* @author calvin
* @author tin
* @see HibernateDaoSupport
* @see HibernateEntityDao
*/
@SuppressWarnings("unchecked")
public class HibernateGenericDao extends HibernateDaoSupport {
/**
* 根據ID獲取對象. 實際調用Hibernate的session.load()方法返回實體或其proxy對象. 如果對象不存在,拋出異常.
*/
public <T> T findById(Class<T> entityClass, Serializable id) {
return (T) getHibernateTemplate().load(entityClass, id);
}
/**
* 獲取全部對象.
*/
public <T> List<T> findAll(Class<T> entityClass) {
return getHibernateTemplate().loadAll(entityClass);
}
/**
* 獲取全部對象,帶排序字段與升降序參
*/
public <T> List<T> findAll(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 Serializable create(Object o) {
return getHibernateTemplate().save(o);
}
/**
* 保存對象.
*/
public void update(Object o) {
getHibernateTemplate().update(o);
}
/**
* 刪除對象.
*/
public void delete(Object o) {
getHibernateTemplate().delete(o);
}
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;
}
/**
* 創建Query對象.防止注入
* @param hql 查詢語句
* @param values list集合
* @return
*/
public Query createQuery(String hql, List<Object> values) {
Assert.hasText(hql);
Query query = getSession().createQuery(hql);
if(values!=null)
{
for (int i = 0; i < values.size(); i++) {
query.setParameter(i, values.get(i));
}
}
return query;
}
/**
* 創建Query對象.防止注入
* @param hql 查詢語句
* @param values list集合
* @return
*/
public Query createSQLQuery(String hql, List<Object> values) {
Assert.hasText(hql);
Query query = getSession().createSQLQuery(hql);
if (values != null) {
for (int i = 0; i < values.size(); i++) {
query.setParameter(i, values.get(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
* 頁號
*/
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(pageNo, totalCount, pageSize, list);
}
/**
* 分頁查詢函數,使用已設好查詢條件與排序的<code>Criteria</code>.
*
* @param pageNo
* 頁號
* @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 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 ");
}
// 執行查詢
long totalCount = (Long) 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
* 頁號
* @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
* 頁號
* @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[])
*/
public 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[])
*/
public 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();
}