HibernateDAO工具类

package com.code.util;
import static java.util.Locale.ENGLISH;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.jdbc.Work;
import org.springframework.orm.hibernate4.support.HibernateDaoSupport;


/**
 * 
 * @author LGF 2014-11-17
 * BaseHibernateDAO 工具类
 * @param <T> 类型
 */ 
@SuppressWarnings("all")
public class HibernateDAO<T> extends HibernateDaoSupport {

	//统计条数语句
	private String countHql;
	//基本的 hql 语句
	private String baseHql;
	
	//统计条数,条件验证正则表达式
	private final static String WHERE_CHECK = ".+[\\s]+[w|W][h|H][e|E][r|R][e|E]+[\\s]+.*";
	//hql语句验证正则表达式
	private final static String HQL_QUERY = ".*\\s+.+";
	
	//类型
	private  Class<T> type;

	public HibernateDAO(){
		initial();
	}
	
	//初始化方法
	private void initial(){
		//获取类型
		type = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		if(type == null){
			new RuntimeException("ERROR: [ the <T> type is null ]");
		}else{
			countHql = "SELECT COUNT(1) FROM "+ type.getName();
			baseHql = "FROM " + type.getName();
		}
	}

	/**
	 * 获取session
	 * @return Session
	 */
	protected Session getSession(){
		return super.getSessionFactory().getCurrentSession();
	}

	//----------------------------------------------------------- 按 id 查询一个对象 -------------------------------------------
	/**
	 * 按 id 获取一个对象
	 * @param id
	 * @return T
	 */
	protected T get(Serializable id){
		return (T) getSession().get(type, id);
	}

	/**
	 * 按 id 加载一个对象
	 * @param id
	 * @return T
	 */
	protected T load(Serializable id){
		return (T) getSession().load(type, id);
	}

	//----------------------------------------------------------- 查询一个对象列表 -------------------------------------------

	/**
	 * 查询一个对象列表
	 * @param nameOrHQL 
	 * <p style="color:red">
	 * 查询名称或者HQL
	 * 如果传的是配置文件中的 SQL|HQL 名称(name) ,
	 * 中间空不能有空格,前后可以为空格,
	 * 否则验证错误,会当做HQL语句查询
	 * </p>
	 * @param params 参数集合
	 * @return List<T>
	 */
	protected List<T> query(String nameOrHQL,Object... params){
		return query(nameOrHQL,null,params);
	}

	/**
	 * 查询一个对象列表
	 * @param nameOrHQL 
	 * <p style="color:red">
	 * 查询名称或者HQL
	 * 如果传的是配置文件中的 SQL|HQL 名称(name) ,
	 * 中间空不能有空格,前后可以为空格,
	 * 否则验证错误,会当做HQL语句查询
	 * </p>
	 * @param page 分页工具
	 * @param params 参数集合
	 * @return List<T>
	 */
	protected List<T> query(String nameOrHQL,Page page,Object... params){
		return getQuery(nameOrHQL, page,params).list();
	}

	/**
	 * 查询一个对象列表
	 * @return List<T>
	 */
	protected List<T> query(){
		return query(null);
	}


	/**
	 * 按页数查询一个对象列表
	 * @param page 分页工具
	 * @return List<T>
	 */
	protected List<T> query(Page page){
		return getQuery(baseHql, page).list();
	}

	//------------------------------------------------ 动态条件查询  -------------------------------------------------

	/* and */

	/**
	 * 动态条件查询,如果对象字段有值将会用 and 连接条件查询
	 * @param obj 传入需要动态查询的类型对象
	 * @return List<T>
	 * @throws Exception
	 */
	protected List<T> queryByCriteriaAnd(T obj) throws Exception{
		return queryByCriteriaAnd(obj,null);
	}

	/**
	 * 动态条件查询,如果对象字段有值将会用 and 连接条件查询
	 * @param obj 传入需要动态查询的类型对象
	 * @param page 分页工具
	 * @return List<T>
	 * @throws Exception
	 */
	protected List<T> queryByCriteriaAnd(T obj,Page page) throws Exception{
		Criteria criteria = getSession().createCriteria(type);
		Map<String, Object> values = getFieldValues(obj);
		for (String key : values.keySet()) {
			criteria.add(Restrictions.eq(key, values.get(key)));
		}
		return setCriteriaPage(criteria,page).list();
	}

	/* or */

	/**
	 * 动态条件查询,如果对象字段有值将会用 or 连接条件查询
	 * @param obj 传入需要动态查询的类型对象
	 * @return List<T>
	 * @throws Exception
	 */
	protected List<T> queryByCriteriaOption(T obj) throws Exception{
		return queryByCriteriaOption(obj,null);
	}

	/**
	 * 动态条件查询,如果对象字段有值将会用 or 连接条件查询
	 * @param obj 传入需要动态查询的类型对象
	 * @param page 分页工具
	 * @return List<T>
	 * @throws Exception
	 */
	protected List<T> queryByCriteriaOption(T obj,Page page) throws Exception{
		Criteria criteria = getSession().createCriteria(type);
		Map<String, Object> values = getFieldValues(obj);
		Criterion[] conditions = new Criterion[values.size()];
		int index = 0;
		for (String key : values.keySet()) {
			conditions[index] = Restrictions.eq(key,values.get(key));
			index++;
		}
		criteria.add(Restrictions.disjunction(conditions));
		return setCriteriaPage(criteria,page).list();
	}

	/* like */

	/**
	 * 动态条件查询,如果对象字段有值将会用 like 连接条件查询
	 * @param obj 传入需要动态查询的类型对象
	 * @param page 分页工具
	 * @param ignore 是否忽略大小写
	 * @param mode 模式
	 * @return List<T>
	 * @throws Exception
	 */
	protected List<T> queryByCriteriaLike(T obj,Page page,boolean ignore,MatchMode mode) throws Exception{
		Criteria criteria = getSession().createCriteria(type);
		Map<String, Object> values = getFieldValues(obj);
		System.out.println(values);
		for (String key : values.keySet()) {
			if(key.getClass()!=String.class){continue;}
			if(ignore){
				criteria.add(Restrictions.ilike(key,values.get(key).toString(),mode));
			}else{
				criteria.add(Restrictions.like(key,values.get(key).toString(),mode));
			}
		}
		return setCriteriaPage(criteria,page).list();
	}

	/**
	 * 动态条件查询,如果对象字段有值将会用 like 连接条件查询
	 * @param obj 传入需要动态查询的类型对象
	 * @param page 分页工具
	 * @param ignore 是否忽略大小写
	 * @return List<T>
	 * @throws Exception
	 */
	protected List<T> queryByCriteriaLike(T obj,Page page,boolean ignore) throws Exception{
		return queryByCriteriaLike(obj,page,ignore,MatchMode.ANYWHERE);
	}

	/**
	 * 动态条件查询,如果对象字段有值将会用 like 连接条件查询
	 * @param obj 传入需要动态查询的类型对象
	 * @param page 分页工具
	 * @param mode 模式
	 * @return List<T>
	 * @throws Exception
	 */
	protected List<T> queryByCriteriaLike(T obj,Page page,MatchMode mode) throws Exception{
		return queryByCriteriaLike(obj,page,false,mode);
	}

	/**
	 * 动态条件查询,如果对象字段有值将会用 like 连接条件查询
	 * @param obj 传入需要动态查询的类型对象
	 * @return List<T>
	 * @throws Exception
	 */
	protected List<T> queryByCriteriaLike(T obj) throws Exception{
		return queryByCriteriaLike(obj,null,false,MatchMode.ANYWHERE);
	}

	/* criteria page */

	/**
	 * 设置分页参数
	 * @param criteria 
	 * @param page 分页对象
	 * @return Criteria
	 */
	protected Criteria setCriteriaPage(Criteria criteria,Page page){
		if(page!=null){
			page.setTotal((long)criteria.setProjection(Projections.rowCount()).uniqueResult());
			criteria.setFirstResult(page.getPageSize()*(page.getPageNumber()-1)).setMaxResults(page.getPageSize());
		}
		return criteria;
	}

	//------------------------------------------------ 查询一个对象 -----------------------------------------------------

	/**
	 * 查询一个对象
	 * @param nameOrHQL 
	 * <p style="color:red">
	 * 查询名称或者HQL
	 * 如果传的是配置文件中的 SQL|HQL 名称(name) ,
	 * 中间空不能有空格,前后可以为空格,
	 * 否则验证错误,会当做HQL语句查询
	 * </p>
	 * @param params 参数集合
	 * @return T
	 */
	protected T queryUniqueResult(String nameOrHQL,Object... params){
		return  (T) getQuery(nameOrHQL, params).uniqueResult();
	}

	//------------------------------------------------ 增删改 -----------------------------------------------------

	/**
	 * 更新一个对象
	 * @param o 对象
	 * @throws Exception 
	 */
	protected int update(T transientInstance) throws Exception{
		getSession().update(transientInstance);
		return 1;
	}

	/**
	 * 删除一个对象
	 * @param o 对象
	 * @throws Exception 
	 */
	protected int delete(T transientInstance) throws Exception{
		getSession().delete(transientInstance);
		return 1;
	}

	/**
	 * 批量删除操作
	 * @param transientInstances 删除的对象集合
	 * @return 更新的记录数
	 */
	protected int batchDelete(T... transientInstances){
		int count = 0;
		Session session  = getSession();
		for (T transientInstance : transientInstances) {
			session.delete(transientInstance);
			if(count%20 == 0){
				session.flush();
				session.clear();
			}
			count++;
		}
		return count;
	}

	/**
	 * 添加一个对象
	 * @param o 对象
	 * @throws Exception
	 */
	protected int save(T transientInstance) throws Exception{
		getSession().save(transientInstance);
		return 1;
	}

	/**
	 * 批量保存操作
	 * @param transientInstances 删除的对象集合
	 * @return 更新的记录数
	 */
	protected int batchSave(T... transientInstances) throws Exception{
		int count = 0;
		Session session  = getSession();
		for (T transientInstance : transientInstances) {
			session.save(transientInstance);
			if(count%20 == 0){
				session.flush();
				session.clear();
			}
			count++;
		}
		return count;
	}

	/**
	 * 更新一个对象
	 * @param nameOrHQL 
	 * <p style="color:red">
	 * 查询名称或者HQL
	 * 如果传的是配置文件中的 SQL|HQL 名称(name) ,
	 * 中间空不能有空格,前后可以为空格,
	 * 否则验证错误,会当做HQL语句查询
	 * </p>
	 * @param params 参数集合
	 * @return int结果
	 */
	protected int update(String nameOrHQL,Object... params) throws Exception{
		return getQuery(nameOrHQL,params).executeUpdate();
	}

	//------------------------------------------------ HQL查询参数设置 -----------------------------------------------------

	/**
	 * 设置查询参数
	 * @param nameOrHQL 
	 * <p style="color:red">
	 * 查询名称或者HQL
	 * 如果传的是配置文件中的 SQL|HQL 名称(name) ,
	 * 中间空不能有空格,前后可以为空格,
	 * 否则验证错误,会当做HQL语句查询
	 * </p>
	 * @param params 参数集合
	 * @return Query
	 */
	protected Query getQuery(String nameOrHQL,Object... params){
		return getQuery(nameOrHQL,null,params);
	}

	/**
	 * 设置 HQL 查询参数
	 * @param nameOrHQL 
	 * <p style="color:red">
	 * 查询名称或者HQL
	 * 如果传的是配置文件中的 SQL|HQL 名称(name) ,
	 * 中间空不能有空格,前后可以为空格,
	 * 否则验证错误,会当做HQL语句查询
	 * </p>
	 * @param page 分页工具
	 * @param params 参数集合
	 * @return Query
	 */
	protected Query getQuery(String nameOrHQL,Page page,Object... params){
		return getQuery(nameOrHQL,page,false,params);
	}

	/**
	 * 设置 HQL 查询参数
	 * @param nameOrHQL 
	 * <p style="color:red">
	 * 查询名称或者HQL
	 * 如果传的是配置文件中的 SQL|HQL 名称(name) ,
	 * 中间空不能有空格,前后可以为空格,
	 * 否则验证错误,会当做HQL语句查询
	 * </p>
	 * @param page 分页工具
	 * @param params 参数集合
	 * @return Query
	 */
	protected Query getQuery(String nameOrHQL,Page page,boolean isNamedParam,Object... params){
		Query query = null;
		String qs = null;
		if(nameOrHQL.trim().matches(HQL_QUERY)){
			query = getSession().createQuery(nameOrHQL);
		}else{
			query = getSession().getNamedQuery(nameOrHQL);
		}
		qs = query.getQueryString();
		int index = 0;
		for (Object object : params) {
			query.setParameter(index, object);
			index++;
		}
		if(page!=null){ 
			page.setTotal(getCount(qs,params));
			query.setFirstResult((page.getPageNumber()-1)*page.getPageSize()).setMaxResults(page.getPageSize());
		}
		print(qs,params);
		return query;
	}

	/**
	 * 设置配置文件HQL或者SQL查询
	 * @param queryString 查询字符串,获取配置文件中的名称
	 * @param page 分页工具
	 * @param params 参数集合
	 * @return Query
	 */
	protected Query getNamedQuery(String name,Page page,Object... params){
		Query query = getSession().getNamedQuery(name);
		int index = 0;
		for (Object object : params) {
			query.setParameter(index, object);
			index++;
		}
		if(page!=null){ 
			page.setTotal(getCount(query.getQueryString(),params));
			query.setFirstResult((page.getPageNumber()-1)*page.getPageSize()).setMaxResults(page.getPageSize());
		}
		print(query.getQueryString(),params);
		return query;
	}

	/**
	 * 设置配置文件HQL或者SQL查询
	 * @param queryString 查询字符串,获取配置文件中的名称
	 * @param params 参数集合
	 * @return Query
	 */
	protected Query getNamedQuery(String name,Object... params){
		return getNamedQuery(name,null,params);
	}

	/* 打印 查询语句 和参数  */
	private void print(String query,Object... params){
		System.out.println("query: [ " + query+" ] params: "+Arrays.asList(params));
	}
	//------------------------------------------------ SQL查询参数设置 -----------------------------------------------------

	/**
	 * 设置 SQL 查询参数
	 * @param sql 语句
	 * @param page 分页工具
	 * @param params 参数集合
	 * @return SQLQuery
	 */
	protected SQLQuery getSQLQuery(String sql,Page page,Class<?> entity,Object... params){
		return getSQLQuery(sql,page,entity,false,params);
	}

	/**
	 * 设置 SQL 查询参数
	 * @param sql 语句
	 * @param page 分页工具
	 * @param isNamedParam 是否是命名参数 ?
	 * @param params 参数集合
	 * @return SQLQuery
	 */
	protected SQLQuery getSQLQuery(String sql,Page page,Class<?> entity,boolean isNamedParam,Object... params){
		SQLQuery query =  getSession().createSQLQuery(sql);
		int index = 0;
		for (Object object : params) {
			query.setParameter(index, object);
			index++;
		}
		if(entity!=null){
			query.addEntity(entity);
		}
		return query;
	}
	//------------------------------------------------原生SQL操作 -----------------------------------------------------

	/**
	 * 原生SQL更新
	 * @param sql 语句
	 * @param params 参数集合
	 * @return 受影响行数
	 */
	protected int sqlUpdate(String sql,Object...params){
		return getSQLQuery(sql,null,null,params).executeUpdate();
	}

	/* 存储过程  */

	/**
	 * 调用存储过程,默认添加实体类类型:<T>
	 * @param sql 存储过程名称
	 * @param params 参数集合
	 * @return List<T>
	 */
	protected List<T> callEntity(String sql,Object...params){
		return getSQLQuery(sql, null, type, params).list();
	}

	/**
	 * <h3>调用存储过程,带返回值的</h3>
	 * <p style="color:red">注意:存储过程不能有输出参数.有输出参数会报错</p>
	 * <p style="color:red">输出参数用select把参数查询出来</p>
	 * <p style="color:red">输入的参数的值不能为空。</p>
	 * @param sql 存储过程
	 * @param params 参数集合
	 * @return List
	 */
	protected List call(String sql,Object...params){
		return getSQLQuery(sql, null, null, params).list();
	}

	/**
	 * 默认添加泛型<T>
	 * @param name 
	 * <p style="color:red">
	 * 查询名称或者HQL
	 * 如果传的是配置文件中的 SQL|HQL 名称(name) ,
	 * 中间空不能有空格,前后可以为空格,
	 * 否则验证错误,会当做HQL语句查询
	 * </p>
	 * @param params 参数集合
	 * @return List<T>
	 */
	protected <T> List<T> callNamedEntity(String name,Object...params){
		Query query = getQuery(name, params);
		if(query instanceof SQLQuery){
			((SQLQuery) query).addEntity(type);
		}
		return query.list();
	}

	/**
	 * <h3>调用存储过程,带返回值的</h3>
	 * <p style="color:red">注意:存储过程不能有输出参数.有输出参数会报错</p>
	 * <p style="color:red">输出参数用select把参数查询出来</p>
	 * <p style="color:red">输入的参数的值不能为空。</p>
	 * @param name 
	 * <p style="color:red">
	 * 查询名称或者HQL
	 * 如果传的是配置文件中的 SQL|名称(name) ,
	 * 中间空不能有空格,前后可以为空格,
	 * 否则验证错误,会当做HQL语句查询
	 * </p>
	 * @param name 参数集合
	 *  @return List
	 * 
	 */
	protected List callNamed(String name,Object...params){
		return getQuery(name, params).list();
	}

	/**
	 * JDBC 操作
	 * @param work
	 */
	protected void doWork(Work work){
		getSession().doWork(work);
	}

	//------------------------------------------------ 统计条数 -----------------------------------------------------

	/**
	 * 统计条数
	 * @param page 分页工具
	 * @return Long 对象
	 */
	protected Long getCount(String hql,Object... params){
		StringBuffer sb = new StringBuffer(); 
		sb.append(countHql)
			.append(" ")
			.append(getAlias(hql))
			.append(" ")
			.append(getCondition(hql));
		return (Long)getQuery(sb.toString(),params).uniqueResult();
	}

	/**
	 * 获取分页查询条件
	 * @param hql 语句
	 * @return 条件
	 */
	private String getCondition(String hql){
		int len = checkWhereExist(hql);
		if(len != -1){
			return hql.substring(len);
		}
		return "";
	}

	/**
	 * 获取别名
	 * @param hql 语句
	 * @return 别名
	 */
	private int checkWhereExist(String hql){
		if(hql.matches(WHERE_CHECK)){
			return hql.toUpperCase().indexOf("WHERE");
		}
		return -1;
	}

	/**
	 * 获取别名
	 * @param hql 语句
	 * @return 别名
	 */
	private String getAlias(String hql){
		String[] hs = hql.split("\\s+");
		for (int i = 0; i < hs.length; i++) {
			String temp = hs[i].toUpperCase();
			if(temp.equals("FROM")&&(i+2)<hs.length){
				return hs[i+2].toUpperCase().equals("WHERE")?"":hs[i+2];
			};
		}
		return "";
	}

	//------------------------------------------------ 其他 -----------------------------------------------------
	/**
	 * 获取字符串(type)类型
	 * @return
	 */
	public String getType() {
		return type.getName();
	}

	/**
	 * 将名称首字母转换成大写
	 * @param name 转换名称
	 * @return String
	 */
	private static String capitalize(String name){
		if (name == null || name.trim().length() == 0) {
			return name;
		}
		return name.substring(0, 1).toUpperCase(ENGLISH) + name.substring(1);
	}

	/**
	 * 获取类属性get方法
	 * 没有get方法返回空
	 * @param cls 类型
	 * @param field 字段名称
	 * @return 方法 Method
	 * @throws NoSuchMethodException 
	 * @throws SecurityException
	 */
	private static Method getReadMethod(Class<?> cls,Field field){
		StringBuffer sb = new StringBuffer();
		if(field.getType()==boolean.class){
			sb.append("is").append(capitalize(field.getName()));
		}else{
			sb.append("get").append(capitalize(field.getName()));
		}
		try {
			return cls.getMethod(sb.toString());
		} catch (NoSuchMethodException e) {
			return null;
		} catch (SecurityException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 获取类属性set方法
	 * @param cls 类型
	 * @param field 字段名称
	 * @return 方法 Method
	 * @throws NoSuchMethodException
	 * @throws SecurityException
	 */
	private static Method getWriterMethod(Class<?> cls,Field field) throws NoSuchMethodException, SecurityException{
		return cls.getMethod(new StringBuffer().append("set").append(capitalize(field.getName())).toString(),field.getType());
	}

	/**
	 * 获取一个字段的属性值
	 * 其字段必须有标准的get方法,如果没有返回空
	 * @param obj 对象
	 * @param field 字段
	 * @return 字段属性值
	 * @throws Exception
	 */
	private static Object getFieldValue(Object obj,Field field){
		try {
			Method method = getReadMethod(obj.getClass(), field);
			if(method!=null){
				return method.invoke(obj);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 传入一个对象,动态取值属性值方法
	 * 如果该对象的属性值不为空,并且有 标准的 get 方法
	 * 可以使用 HIBERNATE Criteria实 现动态查询
	 * @param obj 对象
	 * @return Map键值对的方式,键:字段名称,值:字段值
	 * @throws Exception
	 */
	private static Map<String,Object> getFieldValues(Object obj) throws Exception{
		Field[] fs = obj.getClass().getDeclaredFields();
		if(fs == null){
			return null;
		}
		Map<String,Object> fields = new HashMap<>();
		for (Field field : fs) {
			Object value = getFieldValue(obj,field); 
			if(value == null)continue;
			if(value.getClass()==Integer.class){
				int val = Integer.parseInt(value.toString());
				if(val<=0)continue;
			}else if(value.getClass()==String.class){
				if(value.toString().trim().length()<=0)continue;
			}else if(value instanceof Collection)continue;
			fields.put(field.getName(), value);
		}
		return fields;
	}
}

猜你喜欢

转载自liguanfeng.iteye.com/blog/2199284