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; } }