前段时间在做模糊查询,并利用数据库分页,DAO用hibernate实现,刚开始的时候


根据业务层的数据,拼hql语句进行查询,且不说要进行一些if判断,单从结构上来说,


底层的数据访问层依赖于业务层或者表现层了.


  比如说,我想查询姓王的员工,年龄大于30岁的,在DAO显然要name like '%王' and age >30,如果业务发生变化,查询与王**姓名相同,年龄等于30的,那就改hql语句吧,


name ='王**' and age =30,数据访问层依赖于业务层,觉得不合理.


 Hibernate3提供一个新的东西,DetachedCriteria可以脱离session分离查询条件,也就是把查询条件通过业务层或表现层传入,数据访问层进行数据操作,解决了数据访问层依赖于业务层的问题.


实现细节:


结合泛型设计DAO


public interface DAO<PO,ID extends java.io.Serializable> {
/**
   * find rows by detachedCriteria
   */
  public List<Workparam> findRowsByCriteria( DetachedCriteria detachedCriteria, int first, int max);
  
  /**
   * find count by detachedCriteria
   */
  public int findCountByCriteria( DetachedCriteria detachedCriteria);}


DAO的实现:


public class DAOHibernate<PO,ID extends java.io.Serializable> extends HibernateDaoSupport implements DAO<PO,ID> {
 /**
   * find workparma objects by detachedCriteria
   */
  @SuppressWarnings("unchecked")
  public List<PO> findRowsByCriteria(DetachedCriteria detachedCriteria, int first, int max) {
   // TODO 自动生成方法存根
   return getHibernateTemplate().findByCriteria(detachedCriteria, first, max); 
 /**
   * find totalCount by detachedCriteria
   */
  public int findCountByCriteria(DetachedCriteria detachedCriteria) {
   // TODO 自动生成方法存根
   detachedCriteria.setProjection(Projections.rowCount());
   System.out.println(getHibernateTemplate().findByCriteria(detachedCriteria));
   return (Integer) getHibernateTemplate().findByCriteria(detachedCriteria).get(0);
  }  }
 
}


具体实现的DAO:


public interface WorkparamDAO extends DAO<Workparam,Integer>{
}
implements:
public class WorkparamDAOHibernate extends DAOHibernate<Workparam,Integer> implements WorkparamDAO {
}


 


在利用spring管理DAOHibernate的时候,最好设置其abstract="true",即为抽象的,


实际上DAOHibernate在没有由子类参数化PO,ID类型之前,也是不能使用的.它也不知道PO,ID是什么类型,编译时不会报错,但运行的时候就会出错.


 


接下来做一个分页工具类,封装分页信息:


public class PageSplitUtil<E> {
  
  //存放记录集合
  private List<E> items;
  
  //每页记录数
  private int pageSize = Constants.PAGE_SIZE;
  
  //总记录数
  //初始化其值,为了判断缓存
  private int totalCount=-1;
  
  //分页索引数组
  private int indexs[];
  
  //开始索引值
  private int firstIndex = Constants.FIRST_INDEX;
  
  //当前页索引
  private int currentIndex;
  
  //是否有上一个索引
  private boolean hasPreIndex;
  
  //是否有下一个索引
  private boolean hasNextIndex;
  
  //上一页索引
  private int preIndex;
  
  //上一页索引
  private int nextIndex;
  
  //最后一页
  private int lastIndex;
  
  //小分页数
  private int splitCount=Constants.SPLIT_COUNT;
  
  //存放url
  private String action; //constructor
  public PageSplitUtil(List<E> items,int current,int totalCount){
   this.items = items;
   this.totalCount = totalCount ;
   this.currentIndex = current;
   calculateTotalPage();
  }
  
  
  public PageSplitUtil(List<E> items,int current,int pageSize,int totalCount){
   this.items = items;
   this.pageSize = pageSize;
   this.totalCount = totalCount;
   this.currentIndex = current;
   calculateTotalPage();
  }
  /**
   * @return currentIndex
   */
  public int getCurrentIndex() {
   return currentIndex;
  } /**
   * @param currentIndex 要设置的 currentIndex
   */
  public void setCurrentIndex(int currentIndex) {
   this.currentIndex = currentIndex<1?1:currentIndex;
  } /**
   * @return hasNextIndex
   */
  public boolean isHasNextIndex() {
   return currentIndex>=lastIndex || lastIndex ==1 ?false:true;
  } /**
   * @return hasPreIndex
   */
  public boolean isHasPreIndex() {
   return currentIndex<=firstIndex ?false:true;
  } /**
   * @return indexs
   */
  public int[] getIndexs() {
   indexs = new int[lastIndex];
   for (int i = 0; i < lastIndex; i++) {
    indexs[i]=i+1;
   }
   return indexs;
  } /**
   * @return items
   */
  public List<E> getItems() {
   return items;
  } /**
   * @param items 要设置的 items
   */
  public void setItems(List<E> items) {
   this.items = items;
  } /**
   * @return pageSize
   */
  public int getPageSize() {
   return pageSize;
  }  /**
   * @return firstIndex
   */
  public int getFirstIndex() {
   return firstIndex;
  }  /**
   * @return totalCount
   */
  public int getTotalCount() {
   return totalCount;
  }  /**
   * @return lastIndex
   */
  public int getLastIndex() {  return lastIndex;
  } /**
   * @return splitCount
   */
  public int getSplitCount() {
   return splitCount;
  }
  /**
   * @return nextIndex
   */
  public int getNextIndex() {
   return currentIndex>=lastIndex ? lastIndex : currentIndex+1;
  } /**
   * @return preIndex
   */
  public int getPreIndex() {
   return currentIndex<=firstIndex ? firstIndex : currentIndex-1;
  } 
  
  
  public String getAction() {
   return action;
  } public void setAction(String action) {
   this.action = action;
  }  //计算总页数
  private void calculateTotalPage(){
   if(totalCount>0){
    lastIndex=(int) Math.ceil((double)totalCount/pageSize);  }else{
    lastIndex =0;
   }
  }}


 


把detachedCriteria查询条件在业务层实现


public PageSplitUtil findRowsByCriteria(Workparam param,int current,int pageSize) {
   // TODO 自动生成方法存根
   DetachedCriteria dc = DetachedCriteria.forClass(param.getClass());
   dc.add(Restrictions.like("workName", param.getWorkName(), MatchMode.ANYWHERE));
    dc.add(Restrictions.eq("workState", param.getWorkState())).addOrder(Order.desc("workId"));  int totalCount=workparamDAO.findCountByCriteria(dc);
   
   PageSplitUtil ps=new PageSplitUtil<Workparam>(list,current,pageSize,totalCount);
   return ps;
  }


由于detachedCriteria是根据Criteria的扩展实现,Critetia利用Express来封装了判断的条件以及sql函数(count(),avg()等).在hibernate3中,利用Restrictions封装逻辑判断条件,如like,eq,between等,用Projections封装了sql函数,如count(),avg()等.


MatchMode为匹配方式:START,前边匹配,END,后边匹配,ANYWHERE前后匹配,EXACT完全匹配四种方式.


detachedCriteria支持数据库查询时的排序,addOrder(Order.asc("按属性排序"));


detachedCriteria的多表关联查询, dc.createAlias("workType", "t").add(Restrictions.like("t.typeName", "早班类"));workType作为Workparam的关联属性,在映射文件中会根据其关系对相关联的表进行模糊查询.


 


为了方便在每个页面使用,用自定义标签显示分页信息:


public class PageSplitTag extends BodyTagSupport {
  private static final long serialVersionUID = -1411548776656848362L; private String action="";
 private PageSplitUtil pageUtil;
  
  public PageSplitTag() {
   // TODO 自动生成构造函数存根
  }
  
  public int doStartTag() throws JspException{
   try {
    String txt=getText().toString();
    pageContext.getOut().write(txt);
    return this.SKIP_BODY;
   } catch (IOException e) {
    // TODO 自动生成 catch 块
    throw new JspException("输出错误"+e.getMessage());
   }
  }
  
  /**
   * 输出文本
   * @return
   */
  private StringBuffer getText() {
   // TODO 自动生成方法存根
   if(pageUtil==null) return new StringBuffer("初始化分页失败");
   
   //判断action是否设置
   if(action==null||"".equals(action)){
    action=pageUtil.getAction();
   }
   
   StringBuffer txt=new StringBuffer("<form action="+action+" method=\"get\" name=\"splitfrm\">");
   txt.append("<td height=\"27\" align=\"center\">共有<font color=\"red\">"
      +pageUtil.getTotalCount()+"</font>条记录  ");
   txt.append("<font color=\"red\">"+pageUtil.getPageSize()+"</font>条/页  ");
   //判断是否有上一页
   if(pageUtil.isHasPreIndex()){
    txt.append("<a href="+action+"?page="+pageUtil.getFirstIndex()+">首页</a> ");
    txt.append("<a href="+action+"?page="+pageUtil.getPreIndex()+"><<<</a>  ");
   }
   else{
    txt.append("<font color=\"#999966\">首页</font> ");
    txt.append("<font color=\"#999966\"><<<</font> ");
   }
   //小的分页
   int indexs[]=pageUtil.getIndexs();
   int currentIndex=pageUtil.getCurrentIndex();
   int splitCount=pageUtil.getSplitCount();
   int count=0;
   //每次显示从当前页开始的后splitCount页
   if(pageUtil.getLastIndex()-(currentIndex+splitCount)>=0){
    count=currentIndex+splitCount;
   }else{
    count=indexs.length;
   }
    for (int i = currentIndex-1; i < count; i++) {
      if(currentIndex == indexs[i] ){
       txt.append("<font color=\"red\">"+currentIndex+"</font> ");
      }else{
       txt.append("<a href="+action+"?page="+indexs[i]+">"+indexs[i]+"</a> ");
     }
    }
   txt.append(" ");
   
   //判断是否还有下一页
   if(pageUtil.isHasNextIndex()){
    txt.append("<a href="+action+"?page="+pageUtil.getNextIndex()+">>>></a> ");
    txt.append("<a href="+action+"?page="+pageUtil.getLastIndex()+">尾页</a> ");
   }
   else{
    txt.append("<font color=\"#999966\">>>></font> ");
    txt.append("<font color=\"#999966\">尾页</font> ");
   }
   //页数选择
   txt.append("GO<select name=\"page\" οnchange=\"javascript:document.splitfrm.submit();\">");
   for (int i = 0; i < indexs.length; i++) {
    if(currentIndex == indexs[i]){
     txt.append("<option value="+indexs[i]+" selected=\"selected\">"+indexs[i]+"</option>");
    }else{
     txt.append("<option value="+indexs[i]+">"+indexs[i]+"</option>");
    }
   }
   txt.append("</select>页</form></td>");
   return txt;
  } 
setter..
}


然后在每个页面用自定义标签就可以了:


<%@ taglib uri="http://www.oamanager.com/mytag" prefix="tag"%>
<tag:splitPage action="${splitList.action}" pageUtil="${splitList}"></tag:splitPage>


 设置action请求的路径和分页信息就可以了.


 


缺点:


1:在DAO接口的设计中依赖于hibernate的实现.如果改用ibatis或ojb,需更改接口,不符合接口的设计原则.


2:分页的自定义Tag显示形式固定,如果利用DIV+CSS,或者XML+CSS的话,表现形式更加灵活.


      


  thanks

StringRedisTemplate 模糊查询所有keys criteria模糊查询_iBATIS