zoukankan      html  css  js  c++  java
  • 利用DetachedCriteria实现模糊查询和分页

     

     
      分类: Java-Developing
     前段时间在做模糊查询,并利用数据库分页,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> {


     public List<Workparam> findRowsByCriteria( DetachedCriteria detachedCriteria, int first, int max);
     
     
     public int findCountByCriteria( DetachedCriteria detachedCriteria);

    }

    DAO的实现:

    public class DAOHibernate<PO,ID extends java.io.Serializable> extends HibernateDaoSupport implements DAO<PO,ID> {

     
     @SuppressWarnings("unchecked")
     public List<PO> findRowsByCriteria(DetachedCriteria detachedCriteria, int first, int max) {
      // TODO 自动生成方法存根
      return getHibernateTemplate().findByCriteria(detachedCriteria, first, max);

     
     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();
     }
     
     public int getCurrentIndex() {
      return currentIndex;
     }

     
     public void setCurrentIndex(int currentIndex) {
      this.currentIndex = currentIndex<1?1:currentIndex;
     }

     
     public boolean isHasNextIndex() {
      return currentIndex>=lastIndex || lastIndex ==1 ?false:true;
     }

     
     public boolean isHasPreIndex() {
      return currentIndex<=firstIndex ?false:true;
     }

     
     public int[] getIndexs() {
      indexs = new int[lastIndex];
      for (int i = 0; i < lastIndex; i++) {
       indexs[i]=i+1;
      }
      return indexs;
     }

     
     public List<E> getItems() {
      return items;
     }

     
     public void setItems(List<E> items) {
      this.items = items;
     }

     
     public int getPageSize() {
      return pageSize;
     }


     
     public int getFirstIndex() {
      return firstIndex;
     }


     
     public int getTotalCount() {
      return totalCount;
     }


     
     public int getLastIndex() {

      return lastIndex;
     }

     
     public int getSplitCount() {
      return splitCount;
     }
     
     public int getNextIndex() {
      return currentIndex>=lastIndex ? lastIndex : currentIndex+1;
     }

     
     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());
      }
     }
     
     
     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>条记录&nbsp;&nbsp;");
      txt.append("<font color="red">"+pageUtil.getPageSize()+"</font>条/页&nbsp;&nbsp;");
      //判断是否有上一页
      if(pageUtil.isHasPreIndex()){
       txt.append("<a href="+action+"?page="+pageUtil.getFirstIndex()+">首页</a>&nbsp;");
       txt.append("<a href="+action+"?page="+pageUtil.getPreIndex()+">&lt;&lt;&lt;</a>&nbsp;&nbsp;");
      }
      else{
       txt.append("<font color="#999966">首页</font>&nbsp;");
       txt.append("<font color="#999966">&lt;&lt;&lt;</font>&nbsp;");
      }
      //小的分页
      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>&nbsp;");
         }else{
          txt.append("<a href="+action+"?page="+indexs[i]+">"+indexs[i]+"</a>&nbsp;");
        }
       }
      txt.append("&nbsp");
      
      //判断是否还有下一页
      if(pageUtil.isHasNextIndex()){
       txt.append("<a href="+action+"?page="+pageUtil.getNextIndex()+">&gt;&gt;&gt;</a>&nbsp;");
       txt.append("<a href="+action+"?page="+pageUtil.getLastIndex()+">尾页</a>&nbsp;");
      }
      else{
       txt.append("<font color="#999966">&gt;&gt;&gt;</font>&nbsp;");
       txt.append("<font color="#999966">尾页</font>&nbsp;");
      }
      //页数选择
      txt.append("GO<select name="page" onchange="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利用DetachedCriteria实现模糊查询和分页
  • 相关阅读:
    Maven 环境的配置
    zTree的简单例子
    plsql免安装客户端的配置
    HDU 1232 畅通工程
    HDU 5698 瞬间移动
    Codeforces 1015E1 Stars Drawing (Easy Edition)
    Codeforces 784B Santa Claus and Keyboard Check
    Codeforces 500C New Year Book Reading
    NSarray 赋值 拷贝 等问题记录
    UINavigationController 操作记录
  • 原文地址:https://www.cnblogs.com/doudou618/p/4326610.html
Copyright © 2011-2022 走看看