import java.io.Serializable; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.annotation.Resource; import org.hibernate.Criteria; import org.hibernate.Query; import org.hibernate.SQLQuery; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.criterion.Projections; import org.hibernate.criterion.Restrictions; import com.assess.lang.Paging; import com.assess.lang.util.Misc; @Resource public class DaoHelper { @Resource private SessionFactory sessionFactory; private StatementBuilder statementBuilder; /** * 统计总数 * * @param c * @return */ public int count(Criteria c) { return ((Number) c.uniqueResult()).intValue(); } /** * 统计总数 * * @param q * @return */ public int count(Query q) { return ((Number) q.uniqueResult()).intValue(); } /** * 获取当前Session * * @return */ public final Session session() { return sessionFactory.getCurrentSession(); } /** * 根据主键获取持久化的实体对象 * * @param clazz 持久化实体的类型 * @param id 数据的主键 * @return */ @SuppressWarnings("unchecked") public <T> T get(Class<T> clazz, Serializable id) { return (T) session().get(clazz, id); } /** * 保存数据对象 * * @param obj */ public void save(Object obj) { Session ses = session(); if (obj instanceof Collection<?>) { Collection<?> cs = (Collection<?>) obj; if (cs != null && cs.size() > 0) { for (Object o : cs) { ses.saveOrUpdate(o); } } } else { ses.saveOrUpdate(obj); } } /** * 删除对象 * * @param obj */ public void delete(Object obj) { session().delete(obj); } /** * 使用主键删除持久化对象 * * @param clazz 持久化对象类 * @param id 主键 */ public <T> void delete(Class<T> clazz, Serializable id) { Session s = session(); Object o = s.get(clazz, id); if (o != null) { s.delete(o); } } /** * 更新数据 * * @param obj */ public void update(Object obj) { session().update(obj); } /** * 保存或更新数据。主键为null时保存,否则更新 * * @param obj */ public void saveOrUpdate(Object obj) { session().saveOrUpdate(obj); } /** * 使用HQL创建Query对象 * * @param hql HQL语句 * @return */ public Query query(String hql) { return session().createQuery(hql); } @SuppressWarnings("unchecked") public <T> List<T> query(String hql, String countHql, Paging paging, Map<String, Object> params) { List<T> results = Collections.EMPTY_LIST; if (paging.isCountable()) { Query countQuery = session().createQuery(countHql); setParameter(countQuery, params); // 统计数据总数 int total = ((Number) countQuery.uniqueResult()).intValue(); paging.setTotal(total); // 总数比偏移量小,不需要执行查询 if (total > paging.getOffset()) { Query query = session().createQuery(hql); setParameter(query, params); results = query.setFirstResult(paging.getOffset()).setMaxResults(paging.getPageSize()).list(); } } else { Query countQuery = session().createQuery(hql); setParameter(countQuery, params); results = countQuery.setFirstResult(paging.getOffset()).setMaxResults(paging.getPageSize()) .list(); } return results; } @SuppressWarnings("unchecked") public <T> List<T> nativeQuery(String sql, String countSql, Paging paging, Map<String, Object> params) { List<T> results = Collections.EMPTY_LIST; if (paging.isCountable()) { Query countQuery = session().createSQLQuery(countSql); setParameter(countQuery, params); // 统计数据总数 int total = ((Number) countQuery.uniqueResult()).intValue(); paging.setTotal(total); // 总数比偏移量小,不需要执行查询 if (total > paging.getOffset()) { Query query = session().createSQLQuery(sql); setParameter(query, params); results = query.setFirstResult(paging.getOffset()).setMaxResults(paging.getPageSize()).list(); } } else { results = session().createSQLQuery(sql).setFirstResult(paging.getOffset()) .setMaxResults(paging.getPageSize()).list(); } return results; } /** * 使用SQL创建SQLQuery对象 * * @param sql SQL语句 * @return */ public SQLQuery sqlQuery(String sql) { return session().createSQLQuery(sql); } /** * 获取命名查询 * * @param name * @return */ public Query namedQuery(String name) { return session().getNamedQuery(name); } /** * 获得动态命名HQL查询对象 * * @param namedQuery 命名HQL的名称 * @param params 查询参数 * @return */ public Query dynamicQuery(String namedQuery, Map<String, Object> params) { return session().createQuery(statementBuilder.namedHQLQuery(namedQuery, params)).setProperties(params); } /** * 获得动态命名SQL查询对象 * * @param namedQuery 命名SQL的名称 * @param params 查询参数 * @return */ public SQLQuery nativeDynamicQuery(String namedQuery, Map<String, Object> params) { SQLQuery query = session().createSQLQuery(statementBuilder.namedSQLQuery(namedQuery, params)); query.setProperties(params); return query; } /** * 创建指定持久化类的Criteria对象 * * @param clazz 数据实体类 * @return */ public Criteria criteria(Class<?> clazz) { return session().createCriteria(clazz); } /** * 查询所有持久化数据 * * @param clazz 数据实体类 * @return 数据列表 */ public <T> List<T> select(Class<T> clazz) { return selector(clazz, 0).list(); } /** * 查询指定数量的持久化数据 * * @param clazz 数据实体类 * @param size 查询数量,返回列表中对象数量不超过size * @return 数据列表 */ public <T> List<T> select(Class<T> clazz, int size) { return selector(clazz, size).list(); } /** * 创建查询器 * * @param clazz 要查询的数据实体类 * @return */ public <T> Selector<T> selector(Class<T> clazz) { return new Selector<T>(criteria(clazz), 0, 0); } /** * 创建查询器 * * @param clazz 要查询的数据实体类 * @param size 要查询的最大数据条数 * @return */ public <T> Selector<T> selector(Class<T> clazz, int size) { return new Selector<T>(criteria(clazz), 0, size); } /** * 创建分页查询器 * * @param clazz 要查询的数据实体类 * @param paging 分页对象 * @return */ public <T> Selector<T> selector(Class<T> clazz, Paging paging) { Criteria finder = criteria(clazz); if ((paging.getPageSize() != 0) && paging.isCountable()) { return new PagingSelector<T>(criteria(clazz).setProjection(Projections.rowCount()), finder, paging); } return new Selector<T>(finder, paging.getOffset(), paging.getPageSize()); } /** * 获取动态SQL的分页查询对象 * * @param counterName 统计数量的SQL名称,为null时不统计数量 * @param finderName 查询数据的SQL名称 * @param paging 分页对象 * @param params 查询参数 * @return */ public NativeDynamicSelector nativeDynamicSelector(String counterName, String finderName, Paging paging, Map<String, Object> params) { SQLQuery counter = null; if (counterName != null) { counter = nativeDynamicQuery(counterName, params); } SQLQuery finder = nativeDynamicQuery(finderName, params); return new NativeDynamicSelector(counter, finder, paging); } /** * 获取动态HQL的分页查询对象 * * @param counterName 统计数量的HQL名称,为null时不统计数量 * @param finderName 查询数据的HQL名称 * @param paging 分页对象 * @param params 查询参数 * @return */ public DynamicSelector dynamicSelector(String counterName, String finderName, Paging paging, Map<String, Object> params) { Query counter = null; if (counterName != null) { counter = dynamicQuery(counterName, params); } Query finder = dynamicQuery(finderName, params); return new DynamicSelector(counter, finder, paging); } /** * 执行单一In查询,多用于查询多个主键对应的数据 * * @param clazz * @param property * @param values * @return */ @SuppressWarnings("unchecked") public <T> List<T> in(Class<T> clazz, String property, Set<? extends Serializable> values) { if (Misc.isEmpty(values)) { return Collections.EMPTY_LIST; } return criteria(clazz).add(Restrictions.in(property, values)).list(); } /** * 执行单一In查询和条件查询 * * @param clazz * @param property * @param values * @return */ @SuppressWarnings("unchecked") public <T> List<T> in(Class<T> clazz, String property, Set<? extends Serializable> values, String otherProperty, Object propertyValue) { if (Misc.isEmpty(values)) { return Collections.EMPTY_LIST; } return criteria(clazz).add(Restrictions.in(property, values)) .add(Restrictions.eq(otherProperty, propertyValue)).list(); } public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } @SuppressWarnings("rawtypes") private void setParameter(Query query, Map<String, Object> params) { if (params != null) { Iterator<String> it = params.keySet().iterator(); while (it.hasNext()) { String key = it.next(); if (params.get(key) instanceof Collection) { query.setParameterList(key, (Collection) params.get(key)); } else { query.setParameter(key, params.get(key)); } } } } /** * 同步数据 * * @param flush */ public void flush() { session().flush(); } public void setStatementBuilder(StatementBuilder statementBuilder) { this.statementBuilder = statementBuilder; } }
import httl.Engine; import httl.Template; import java.io.IOException; import java.io.InputStream; import java.io.Writer; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.dom4j.Element; import org.hibernate.internal.util.xml.MappingReader; import org.hibernate.internal.util.xml.OriginImpl; import org.hibernate.internal.util.xml.XmlDocument; import org.springframework.core.io.Resource; import org.xml.sax.InputSource; import com.assess.lang.AppException; import com.assess.lang.util.TextUtil; public class StatementBuilder { private Resource[] locations; private Engine engine; private ConcurrentHashMap<String, Template> hqlCache = new ConcurrentHashMap<>(32); private ConcurrentHashMap<String, Template> sqlCache = new ConcurrentHashMap<>(32); public void setLocations(Resource...locations) { this.locations = locations; } public void init() throws Exception { engine = Engine.getEngine("httl-hibernate.properties"); if (locations != null) { for (Resource r : locations) { parse(r); } } } public String namedSQLQuery(String name, Map<String, Object> params) { Template tpl = sqlCache.get(name); if (tpl == null) { throw new IllegalArgumentException("Not found named query: " + name); } return render(tpl, params); } public String namedHQLQuery(String name, Map<String, Object> params) { Template tpl = hqlCache.get(name); if (tpl == null) { throw new IllegalArgumentException("Not found named query: " + name); } return render(tpl, params); } private String render(Template tpl, Map<String, Object> params) { try { Writer out = new StringBuilderWriter(128); tpl.render(params, out); return out.toString(); } catch (Exception e) { throw new AppException(e); } } @SuppressWarnings("unchecked") private void parse(Resource resource) throws Exception { try (InputStream is = resource.getInputStream()) { InputSource source = new InputSource(is); OriginImpl o = new OriginImpl("file", resource.getFilename()); XmlDocument xml = MappingReader.INSTANCE.readMappingDocument(source, o); Element statement = xml.getDocumentTree().getRootElement(); for (Element e : (List<Element>) statement.elements()) { final String name = e.getName(); if ("sql-query".equals(name)) { cacheStatement(resource, e, sqlCache); } else if ("query".equals(name)) { cacheStatement(resource, e, hqlCache); } } } } private void cacheStatement(Resource res, final Element element, Map<String, Template> cache) throws Exception { String name = element.attribute("name").getText(); if (TextUtil.isBlank(name)) { throw new Exception("query name is lacked in " + res.getURI()); } String text = element.getText(); if (TextUtil.isBlank(text)) { throw new Exception("query text is lacked in " + res.getURI()); } if (cache.containsKey(name)) { throw new Exception("query name " + name + " is duplicated in " + res.getURI()); } Template tpl = engine.parseTemplate(text); if (tpl == null) { throw new Exception("Cann't parse namedQuery: " + name); } cache.put(name, tpl); } private static class StringBuilderWriter extends Writer { private final StringBuilder buf; public StringBuilderWriter(int capacity) { buf = new StringBuilder(capacity); } @Override public void write(String value) { if (value != null) { buf.append(value); } } @Override public void write(char[] value, int offset, int length) throws IOException { if (value != null) { buf.append(value, offset, length); } } @Override public void flush() throws IOException { } @Override public void close() throws IOException { } @Override public Writer append(char value) { buf.append(value); return this; } @Override public Writer append(CharSequence value) { buf.append(value); return this; } @Override public Writer append(CharSequence value, int start, int end) { buf.append(value, start, end); return this; } @Override public String toString() { return buf.toString(); } } }
compiler=httl.spi.compilers.JavassistCompiler loader=httl.spi.loaders.ClasspathLoader logger=httl.spi.loggers.Slf4jLogger logger.level=INFO codecs= before.listener= after.listener= formatter=httl.spi.formatters.DateFormatter formatter.switcher= template.filter= expression.filter=httl.spi.filters.UnescapeXmlFilter value.filter=httl.spi.filters.MultiValueFilter text.filter=httl.spi.filters.MultiTextFilter script.value.filter= script.text.filter= style.value.filter= style.text.filter=
具体的使用: <sql-query name="Survey.findCodeByActor"> <![CDATA[ SELECT DISTINCT(s.code) as code FROM t_survey s, t_actor a, t_user u WHERE s.category=2 AND a.user_id=:userId AND s.locale=:locale AND a.state=1 AND a.assessed_actor_id=u.person_id AND s.code=a.survey_code AND (s.state=3 OR s.state=4) #if(relationship != -1) AND a.relationship=:relationship #end #if(assessedActor != null) AND a.assessed_actor_id=:assessedActor #end #if(name != null) AND s.name LIKE :name #end #if(state == 2) GROUP BY s.code HAVING min(a.answer_status)=2 AND max(a.answer_status)=2 ORDER BY s.end_time ASC #else(state != -1) GROUP BY s.code HAVING min(a.answer_status)=:state ORDER BY s.end_time ASC #else GROUP BY s.code ORDER BY min(a.answer_status) ASC, s.end_time ASC #end ]]> </sql-query> <query name="Survey.reject"> <![CDATA[ SELECT a FROM Actor a, Survey s WHERE a.surveyCode=:surveyCode AND a.userId=:userId AND s.locale=:locale AND a.assessedActorId=:peer AND a.surveyCode=s.code AND a.relationship=4 AND s.category=2 AND s.state=3 AND a.state=1 AND a.answerStatus=1 ]]> </query>
public void reject(Map<String, Object> params) { Actor actor = (Actor) daoHelper.namedQuery("Survey.reject").setProperties(params).uniqueResult(); if (actor == null) { throw new AppException("survey.reject.notFound"); } // 拒绝答题 actor.setAnswerStatus(Constants.ANSWER_STATUS_REFUSED); } public List<Object[]> findByActor(Paging paging, Map<String, Object> params) { List<Long> codes = daoHelper.nativeDynamicQuery("Survey.findCodeByActor", params) .addScalar("code", StandardBasicTypes.LONG).list(); paging.setTotal(codes.size()); int offset = paging.getOffset(); if (codes.size() <= offset) { return Collections.EMPTY_LIST; } int end = Math.min(codes.size(), offset + paging.getPageSize()); params.put("codes", codes.subList(offset, end)); return daoHelper.namedQuery("Actor.findForSurvey").setProperties(params).list(); }
<bean id="statementBuilder" class="com.assess.lang.hibernate.StatementBuilder" init-method="init"> <property name="locations" value="classpath:hibernate/dynamic-queries-*.xml" /> </bean> <bean id="daoHelper" class="com.assess.lang.hibernate.DaoHelper"> <property name="sessionFactory" ref="sessionFactory" /> <property name="statementBuilder" ref="statementBuilder" /> </bean>