package com.norteksoft.acs.base.orm.hibernate;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Criterion;
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.transform.ResultTransformer;
import org.springframework.util.Assert;
import com.norteksoft.product.orm.Page;
import com.norteksoft.product.util.BeanUtils;
import com.norteksoft.product.util.SearchUtils;
/**
* Hibernate的范型基类.
*
* 可以在service类中直接创建使用.也可以继承出DAO子类,在多个Service类中共享DAO操作.
* 参考Spring2.5自带的Petlinc例子,取消了HibernateTemplate.
* 通过Hibernate的sessionFactory.getCurrentSession()获得session,直接使用Hibernate原生API.
*
* @param <T> DAO操作的对象类型
* @param <PK> 主键类型
*
* @author huhongchun
*/
@SuppressWarnings("unchecked")
public class SimpleHibernateTemplate<T, PK extends Serializable> {
// protected Logger logger = LoggerFactory.getLogger(getClass());
protected Log log = LogFactory.getLog(getClass());
protected SessionFactory sessionFactory;
protected Class<T> entityClass;
public SimpleHibernateTemplate(SessionFactory sessionFactory, Class<T> entityClass) {
this.sessionFactory = sessionFactory;
this.entityClass = entityClass;
}
public Session getSession() {
return sessionFactory.getCurrentSession();
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void save(T entity) {
Assert.notNull(entity);
getSession().saveOrUpdate(entity);
log.debug("save entity: " + entity);
}
public void delete(T entity) {
Assert.notNull(entity);
getSession().delete(entity);
log.debug("delete entity: " + entity);
}
public void delete(PK id) {
Assert.notNull(id);
delete(get(id));
}
public List<T> findAll() {
return findByCriteria();
}
public Page<T> findAll(Page<T> page) {
return findByCriteria(page);
}
/**
* 按id获取对象.
*/
public T get(final PK id) {
return (T) getSession().load(entityClass, id);
}
/**
* 按HQL查询对象列表.
*
* @param hql hql语句
* @param values 数量可变的参数
*/
public List find(String hql, Object... values) {
return createQuery(hql, values).list();
}
public List<T> findList(String hql, Object... values){
return createQuery(hql, values).list();
}
/**
* 按HQL分页查询.
* 暂不支持自动获取总结果数,需用户另行执行查询.
*
* @param page 分页参数.包括pageSize 和firstResult.
* @param hql hql语句.
* @param values 数量可变的参数.
*
* @return 分页查询结果,附带结果列表及所有查询时的参数.
*/
public Page<T> find(Page<T> page, String hql, Object... values) {
Assert.notNull(page);
String newHql = createHqlAddOrderBy(hql, page);
Query q = createQuery(newHql, values);
if (page.isAutoCount()) {
int pageNo=page.getPageNo();
int pageSize=page.getPageSize();
long totalCount = countHqlResult(newHql, values);
long z=totalCount/pageSize;
long y=totalCount%pageSize;
long c=pageNo-z;
page.setTotalCount(totalCount);
if(y==0 && c==1){//该页没有数据转到上一页
page.setPageNo(Integer.valueOf(pageNo-1));
}
}
setPageParameter(q, page);
List result = q.list();
page.setResult(result);
return page;
}
/**
* 按HQL查询唯一对象.
*/
public Object findUnique(String hql, Object... values) {
return createQuery(hql, values).uniqueResult();
}
/**
* 按HQL查询Intger类形结果.
*/
public Integer findInt(String hql, Object... values) {
return (Integer) findUnique(hql, values);
}
/**
* 按HQL查询Long类型结果.
*/
public Long findLong(String hql, Object... values) {
return (Long) findUnique(hql, values);
}
/**
* 按Criterion查询对象列表.
* @param criterion 数量可变的Criterion.
*/
public List<T> findByCriteria(Criterion... criterion) {
return createCriteria(criterion).list();
}
/**
* 按Criterion分页查询.
* @param page 分页参数.包括pageSize、firstResult、orderBy、asc、autoCount.
* 其中firstResult可直接指定,也可以指定pageNo.
* autoCount指定是否动态获取总结果数.
*
* @param criterion 数量可变的Criterion.
* @return 分页查询结果.附带结果列表及所有查询时的参数.
*/
public Page<T> findByCriteria(Page page, Criterion... criterion) {
Assert.notNull(page);
Criteria c = createCriteria(criterion);
if (page.isAutoCount()) {
page.setTotalCount(countQueryResult(page, c));
}
if (page.isOrderBySetted()) {
if (page.getOrder().endsWith("asc")) {
c.addOrder(Order.asc(page.getOrderBy()));
} else {
c.addOrder(Order.desc(page.getOrderBy()));
}
}
//hibernate的firstResult的序号从0开始
c.setFirstResult(page.getFirst()-1);
c.setMaxResults(page.getPageSize());
page.setResult(c.list());
return page;
}
/**
* 按属性查找对象列表.
*/
public List<T> findByProperty(String propertyName, Object value) {
Assert.hasText(propertyName);
return createCriteria(Restrictions.eq(propertyName, value)).list();
}
/**
* 按属性查找唯一对象.
*/
public T findUniqueByProperty(String propertyName, Object value) {
Assert.hasText(propertyName);
return (T) createCriteria(Restrictions.eq(propertyName, value)).uniqueResult();
}
/**
* 根据查询函数与参数列表创建Query对象,后续可进行更多处理,辅助函数.
*/
public Query createQuery(String queryString, Object... values) {
Assert.hasText(queryString);
Query queryObject = getSession().createQuery(queryString);
if (values != null) {
for (int i = 0; i < values.length; i++) {
queryObject.setParameter(i, values[i]);
}
}
return queryObject;
}
/**
* 根据Criterion条件创建Criteria,后续可进行更多处理,辅助函数.
*/
public Criteria createCriteria(Criterion... criterions) {
Criteria criteria = getSession().createCriteria(entityClass);
for (Criterion c : criterions) {
criteria.add(c);
}
return criteria;
}
/**
* 判断对象的属性值在数据库内是否唯一.
*
* 在修改对象的情景下,如果属性新修改的值(value)等于属性原值(orgValue)则不作比较.
* 传回orgValue的设计侧重于从页面上发出Ajax判断请求的场景.
* 否则需要SS2里那种以对象ID作为第3个参数的isUnique函数.
*/
public boolean isPropertyUnique(String propertyName, Object newValue, Object orgValue) {
if (newValue == null || newValue.equals(orgValue))
return true;
Object object = findUniqueByProperty(propertyName, newValue);
return (object == null);
}
/**
* 通过count查询获得本次查询所能获得的对象总数.
* @return page对象中的totalCount属性将赋值.
*/
protected int countQueryResult(Page<T> page, Criteria c) {
CriteriaImpl impl = (CriteriaImpl) c;
// 先把Projection、ResultTransformer、OrderBy取出来,清空三者后再执行Count操作
Projection projection = impl.getProjection();
ResultTransformer transformer = impl.getResultTransformer();
List<CriteriaImpl.OrderEntry> orderEntries = null;
try {
orderEntries = (List) BeanUtils.getFieldValue(impl, "orderEntries");
BeanUtils.setFieldValue(impl, "orderEntries", new ArrayList());
} catch (Exception e) {
log.error("不可能抛出的异常", e);
}
// 执行Count查询
int totalCount = (Integer) c.setProjection(Projections.rowCount()).uniqueResult();
if (totalCount < 1)
return -1;
// 将之前的Projection和OrderBy条件重新设回去
c.setProjection(projection);
if (projection == null) {
c.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
}
if (transformer != null) {
c.setResultTransformer(transformer);
}
try {
BeanUtils.setFieldValue(impl, "orderEntries", orderEntries);
} catch (Exception e) {
log.error("不可能抛出的异常", e);
}
return totalCount;
}
/**
* 去除hql的select 子句,未考虑union的情况,用于pagedQuery.
*
*/
private static String removeSelect(String hql) {
int beginPos = hql.toLowerCase().indexOf("from");
return hql.substring(beginPos);
}
/**
* 去除hql的orderby 子句,用于pagedQuery.
*
*/
private static String removeOrders(String 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();
}
/**
* 原生SQL查询, 没有完善,慎用。。。
* @return List<T>
*/
public List<T> findByJdbc(String sql, Object... values){
SQLQuery sqlQuery = getSession().createSQLQuery(sql);
if(values != null){
for(int i = 0; i < values.length; i++){
sqlQuery.setString(i, values[i].toString());
}
}
List<T> results = sqlQuery.addEntity(entityClass).list();
return results;
}
/**
* 原生SQL分页查询
*/
public void findPageByJdbc(Page<T> page, String sql, Object... values){
SQLQuery sqlQuery = getSession().createSQLQuery(sql);
if(values != null){
for(int i = 0; i < values.length; i++){
sqlQuery.setString(i, values[i].toString());
}
}
page.setTotalCount(countSql(sql, values));
List<T> results = sqlQuery.addEntity(entityClass).setFirstResult(page.getFirst()-1).setMaxResults(page.getPageSize()).list();
page.setResult(results);
}
public int countSql(String sql, Object... values){
String countQueryString = " select count(*) " + removeSelect(removeOrders(sql));
SQLQuery query = getSession().createSQLQuery(countQueryString);
if(values != null){
for(int i = 0; i < values.length; i++){
query.setString(i, values[i].toString());
}
}
Number count = (Number) query.uniqueResult();
//BigDecimal count = (BigDecimal)query.uniqueResult();
return count.intValue();
}
/**
* HQL批量修改
*/
public int executeUpdate(String hql, Object... values){
Query query = this.createQuery(hql, values);
return query.executeUpdate();
}
/**
* Hibernate 原生SQL,不支持有null参数的sql
* @param sql
* @param values
*/
public int executeSqlUpdate(String sql, Object...values){
SQLQuery query = getSession().createSQLQuery(sql);
if (values != null) {
for (int i = 0; i < values.length; i++) {
query.setParameter(i, values[i]);
}
}
return query.executeUpdate();
}
/**
* 直接执行原生SQL
* @param sql
*/
public int executeSqlUpdate(String sql){
SQLQuery query = getSession().createSQLQuery(sql);
return query.executeUpdate();
}
/**
* 向hql中设置orderBy条件(可以处理以有order by的hql和没有order by的hql)
* @param hql hql语句
* @param page 分页和排序参数
* @return
*/
protected String createHqlAddOrderBy(final String hql, final Page<T> page) {
String newHql = hql;
if(page.isOrderBySetted()) {
String[] orderByArray = StringUtils.split(page.getOrderBy(), ',');
String[] orderArray = StringUtils.split(page.getOrder(), ',');
Assert.isTrue(orderByArray.length == orderArray.length, "分页多重排序参数中,排序字段与排序方向的个数不相等");
String orderByStr = "";
if(StringUtils.contains(newHql, "order by")){
for (int i = 0; i < orderByArray.length; i++) {
if((i + 1) == orderByArray.length) {
orderByStr += getAlias(hql)+ "." + orderByArray[i].trim() + " " + orderArray[i].trim();
} else {
orderByStr += getAlias(hql)+ "." + orderByArray[i].trim() + " " + orderArray[i].trim() + ", ";
}
}
newHql = StringUtils.substringBefore(newHql, "order by") + "order by " + orderByStr;
}else{
orderByStr = " order by ";
for (int i = 0; i < orderByArray.length; i++) {
if((i + 1) == orderByArray.length) {
orderByStr += getAlias(hql)+ "." + orderByArray[i].trim() + " " + orderArray[i].trim();
} else {
orderByStr += getAlias(hql)+ "." + orderByArray[i].trim() + " " + orderArray[i].trim() + ", ";
}
}
newHql += orderByStr;
}
}
log.debug("newHql =" + newHql);
return newHql;
}
/*
* 解析 HQL from子句中的entity的别名
*/
public String getAlias(String hql){
String fromHql = StringUtils.substringAfter(hql, "from");
fromHql = StringUtils.substringBefore(fromHql, "where");
if(fromHql.indexOf(",")>=0){//TaskReport tr, WorkRepoet wr, ViewReport vr
String[] fromHql1 = fromHql.split(",");
return alias(fromHql1[0], fromHql);
}else{//TaskReport tr与TaskReport tr inner join tr.workReport wr left outer join wr.viewReport vr
if(fromHql.contains("join")){
String[] fromParts = fromHql.trim().split("join");
String hostTable = fromParts[0].trim();
String[] tableAlias = null;
if(hostTable.contains("inner")){
tableAlias = hostTable.split("inner");
return alias(tableAlias[0].trim(), fromHql);
}else if(hostTable.contains("left outer")){
tableAlias = hostTable.split("left outer");
return alias(tableAlias[0].trim(), fromHql);
}else if(hostTable.contains("right outer")){
tableAlias = hostTable.split("right outer");
return alias(tableAlias[0].trim(), fromHql);
}else{
return alias(hostTable, fromHql);
}
}else{
return alias(fromHql.trim(), fromHql);
}
}
}
private String alias(String str, String fromHql){
String[] strs = str.split(" ");
for(int i = strs.length-1; i >= 0; i--){
if(StringUtils.isNotBlank(strs[i])){
log.debug(" *** entity alias ["+strs[i]+"] hql : [" + fromHql + "]");
return strs[i].trim();
}
}
return "";
}
/**
* 执行count查询获得本次Hql查询所能获得的对象总数.
*
* 本函数只能自动处理简单的hql语句,复杂的hql查询请另行编写count语句查询.
*/
public int countHqlResult(final String hql, final Object... values) {
int count = 0;
String fromHql = hql;
//select子句与order by子句会影响count查询,进行简单的排除.
fromHql = "from " + StringUtils.substringAfter(fromHql, "from");
fromHql = StringUtils.substringBefore(fromHql, "order by");
//
// String countHql = "select count(*) " + fromHql;
String countHql = "select count(distinct "+getAlias(fromHql)+".id) " + fromHql;
try {
Object obj = findUnique(countHql, values);
count = Integer.parseInt(obj.toString());
} catch (Exception e) {
throw new RuntimeException("hql can't be auto count, hql is:" + countHql, e);
}
return count;
}
/**
* 设置分页参数到Query对象,辅助函数.
*/
protected Query setPageParameter(final Query q, final Page<T> page) {
//hibernate的firstResult的序号从0开始
q.setFirstResult(page.getFirst()-1);
q.setMaxResults(page.getPageSize());
return q;
}
public Page<T> searchPageByHql(final Page<T> page, final String hql, final Object... values) {
log.debug("old search Hql:[" + hql + "]");
Map<String, Object> result = SearchUtils.processSearchParameters(hql, true, values);
log.debug("new search Hql:[" + result.get(SearchUtils.SQL_OR_HQL).toString() + "]");
return findPage(page,
result.get(SearchUtils.SQL_OR_HQL).toString(),
(Object[])result.get(SearchUtils.PARAMETERS));
}
public Page<T> findPage(final Page<T> page, final String hql, final Object... values) {
Assert.notNull(page, "page不能为空");
String newHql = createHqlAddOrderBy(hql, page);
Query q = createQuery(newHql, values);
if (page.isAutoCount()) {
int pageNo=page.getPageNo();
int pageSize=page.getPageSize();
long totalCount = countHqlResult(newHql, values);
long z=totalCount/pageSize;
long y=totalCount%pageSize;
long c=pageNo-z;
page.setTotalCount(totalCount);
if(y==0 && c==1){//该页没有数据转到上一页
page.setPageNo(Integer.valueOf(pageNo-1));
}
}
setPageParameter(q, page);
List result = q.list();
page.setResult(result);
return page;
}
public <X> List<X> findBySql(String sql, Object... values){
SQLQuery sqlQuery = getSession().createSQLQuery(sql);
if(values != null){
for(int i = 0; i < values.length; i++){
sqlQuery.setParameter(i, values[i]);
}
}
return sqlQuery.list();
}
}