上篇文章我们已经把前台和工具类PageBean抽象出来了,下面我们继续抽象:
比如我们要查询板块的信息时,我们要将板块的信息,以及是否要排序和按照什么排序都要在hql语句中声明,但是我换了一个主题信息查询呢,上面那些东西我们还要继续赋值,传值,再次做了一些重复性的事情。
还有一个问题,我们在拼接hql语句时,以及order by的时候,总是会出现语句错误,如果字段再多的话,相信大家就已经疯了,那好,我们继续来抽象,看下面代码:
QueryHelper工具类:
<span style="font-size:18px;">package cn.itcast.oa.util; import java.util.ArrayList; import java.util.List; import cn.itcast.oa.base.DaoSupport; import cn.itcast.oa.domain.PageBean; import com.opensymphony.xwork2.ActionContext; /** * 用于辅助拼接HQL语句 * * @author 志鹏 * */ public class QueryHelper { private String fromClause; // FROM子句 private String whereClause = ""; // Where子句 private String orderByClause = ""; // OrderBy子句 private List<Object> parameters = new ArrayList<Object>(); // 参数列表 /** * 生成From子句 * * @param clazz * @param alias * 别名 */ public QueryHelper(Class clazz, String alias) { fromClause = "FROM " + clazz.getSimpleName() + " " + alias; } /** * 拼接Where子句 * * @param condition * @param params */ public QueryHelper addCondition(String condition, Object... params) { // 拼接 if (whereClause.length() == 0) { whereClause = " WHERE " + condition; } else { whereClause += " AND " + condition; } // 参数 if (params != null) { for (Object p : params) { parameters.add(p); } } return this; } /** * 如果第一个参数为true,则拼接Where子句 * * @param append * @param condition * @param params */ public QueryHelper addCondition(boolean append, String condition, Object... params) { if (append) { addCondition(condition, params); } return this; } /** * 拼接OrderBy子句 * * @param propertyName * 参与排序的属性名 * @param asc * true表示升序,false表示降序 */ public QueryHelper addOrderProperty(String propertyName, boolean asc) { if (orderByClause.length() == 0) { orderByClause = " ORDER BY " + propertyName + (asc ? " ASC" : " DESC"); } else { orderByClause += ", " + propertyName + (asc ? " ASC" : " DESC"); } return this; } /** * 如果第一个参数为true,则拼接OrderBy子句 * * @param append * @param propertyName * @param asc */ public QueryHelper addOrderProperty(boolean append, String propertyName, boolean asc) { if (append) { addOrderProperty(propertyName, asc); } return this; } /** * 获取生成的用于查询数据列表的HQL语句 * * @return */ public String getListQueryHql() { return fromClause + whereClause + orderByClause; } /** * 获取生成的用于查询总记录数的HQL语句 * * @return */ public String getCountQueryHql() { return "SELECT COUNT(*) " + fromClause + whereClause; } /** * 获取HQL中的参数值列表 * * @return */ public List<Object> getParameters() { return parameters; } /** * 查询分页信息,并放到值栈栈顶 * * @param service * @param pageNum * @param pageSize */ public void preparePageBean(DaoSupport<?> service, int pageNum, int pageSize) { PageBean pageBean = service.getPageBean(pageNum, pageSize, this); ActionContext.getContext().getValueStack().push(pageBean); } } </span>
简单介绍,如果我们的参数过多,我们可以根据循环来进行赋值,这样都避免了赋值繁杂,和一些空格的错误了。
OA系统的抽象不仅仅这些,比如一些公共的GetById(),FindAll()等等这样公共的底层方法,我们都抽象到了一个叫做DaoSupportImpl这样的实现类中,那么我们的分页功能也有这样的公共方法我们依旧抽象出来放在DaoSupportImpl实现类中,看下面代码:
PageBean方法:
<span style="font-size:18px;">// 公共的查询分页信息的方法(最终版) public PageBean getPageBean(int pageNum, int pageSize, QueryHelper queryHelper) { // 参数列表 List<Object> parameters = queryHelper.getParameters(); // 查询本页的数据列表 Query listQuery = getSession().createQuery(queryHelper.getListQueryHql()); // 创建查询对象 if (parameters != null) { // 设置参数 for (int i = 0; i < parameters.size(); i++) { listQuery.setParameter(i, parameters.get(i)); } } listQuery.setFirstResult((pageNum - 1) * pageSize); listQuery.setMaxResults(pageSize); List list = listQuery.list(); // 执行查询 // 查询总记录数量 Query countQuery = getSession().createQuery(queryHelper.getCountQueryHql()); if (parameters != null) { // 设置参数 for (int i = 0; i < parameters.size(); i++) { countQuery.setParameter(i, parameters.get(i)); } } Long count = (Long) countQuery.uniqueResult(); // 执行查询 return new PageBean(pageNum, pageSize, count.intValue(), list); } </span>
大家也许会奇怪,那怎么进行具体的查询呢,比如我是板块查询,没有看到真正的hql语句和表的查询呀,当然我们一些特殊的我们会进行重写呀,比如下面这段代码,就是重写的过程:
<span style="font-size:18px;">public PageBean getPageBeanByForum(int pageNum, int pageSize, Forum forum) { // 查询本页的数据列表 List list = getSession().createQuery(// "FROM Topic t WHERE t.forum=? ORDER BY (CASE t.type WHEN 2 THEN 2 ELSE 0 END) DESC, t.lastUpdateTime DESC")// .setParameter(0, forum)// .setFirstResult((pageNum - 1) * pageSize)// .setMaxResults(pageSize)// .list(); // 查询总记录数量 Long count = (Long) getSession().createQuery(// "SELECT COUNT(*) FROM Topic t WHERE t.forum=?")// .setParameter(0, forum)// .uniqueResult(); return new PageBean(pageNum, pageSize, count.intValue(), list); }</span>
关于这段内容都这些了,让我很疑惑的是,在action中的hql语句,是不是会让我们的架构设计不够明确呢,hql语句应该放在底层,而不是Action呀,看下面代码:
Action代码:
<span style="font-size:18px;">// 准备分页信息 ,最终版 new QueryHelper(Topic.class, "t")// // 过滤条件 .addCondition("t.forum=?", forum)// .addCondition((viewType == 1), "t.type=?", Topic.TYPE_BEST) // 1 表示只看精华帖 // 排序条件 .addOrderProperty((orderBy == 1), "t.lastUpdateTime", asc) // 1 表示只按最后更新时间排序 .addOrderProperty((orderBy == 2), "t.postTime", asc) // 2 表示只按主题发表时间排序 .addOrderProperty((orderBy == 3), "t.replyCount", asc) // 3 表示只按回复数量排序 .addOrderProperty((orderBy == 0), "(CASE t.type WHEN 2 THEN 2 ELSE 0 END)", false)// .addOrderProperty((orderBy == 0), "t.lastUpdateTime", false) // 0 表示默认排序(所有置顶帖在前面,并按最后更新时间降序排列) .preparePageBean(topicService, pageNum, pageSize); </span>